diff --git a/.gn b/.gn
index 34646676..a98d422 100644
--- a/.gn
+++ b/.gn
@@ -525,7 +525,6 @@
   "//third_party/protobuf/*",
   "//third_party/pycoverage/*",
   "//third_party/pyelftools/*",
-  "//third_party/pyftpdlib/*",
   "//third_party/pyjson5/*",
   "//third_party/pylint/*",
   "//third_party/pymock/*",
diff --git a/DEPS b/DEPS
index 736f243..ff231591 100644
--- a/DEPS
+++ b/DEPS
@@ -133,7 +133,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '1f09898e9a8a31f0ea977253ab39b908d0ae0dce',
+  'skia_revision': '9b2633e294de873d7c00201f26b033e0296747e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -145,15 +145,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'a253cff3c8ac98adce68c75ae03cb65616352d58',
+  'angle_revision': 'eaf2d928e6fadd165b943c06a9ee028bc027646e',
   # 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': '10186cb85fd68463067f8b0cbc59695739dbabbd',
+  'swiftshader_revision': '558df923fcce1048a2a1b1b6cb36be615df17f11',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'a664b953817c9d439a71486f2c1d9cda67edb8ef',
+  'pdfium_revision': 'a2d9e64b410f55bad194fddc35558b9a3a3afa32',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -196,7 +196,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': '71e1bec28dde3882f523a2bff1f82842ad710e9d',
+  'catapult_revision': '0aa89afdae25efe44528f3b8677503559a3f981a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -802,7 +802,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '023ca2db25adb55eeb69a42c2fa2021f946ea859',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ddbdb74d5561fe1ece1792c158a3d265e34afea7',
       'condition': 'checkout_linux',
   },
 
@@ -827,7 +827,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2d3b9260f3085f0ce161dbec51f131979b828474',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a16f28fc23a44ea79bd6a8d6b6b940d88f84adb6',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1177,7 +1177,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'a47facdd75f95c30d421beebe7421591e7935bca',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '93a00f9295450d486191f59eaae4cff26e6e778e',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1212,9 +1212,6 @@
       'condition': 'checkout_linux',
   },
 
-  'src/third_party/pyftpdlib/src':
-    Var('chromium_git') + '/external/pyftpdlib.git' + '@' + '2be6d65e31c7ee6320d059f581f05ae8d89d7e45',
-
   'src/third_party/quic_trace/src':
     Var('chromium_git') + '/external/github.com/google/quic-trace.git' + '@' + '8415c22f0ca2485bd8a16eff64075f4361f3878e',
 
@@ -1348,7 +1345,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'e62a08a87a6f21672b2ae8ba25632007f417a3f1',
+    Var('webrtc_git') + '/src.git' + '@' + '7581ff73754e34d7b0f5c42e075a2a12087f5bfb',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1389,7 +1386,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ed36a5728bd95c97fce0821c471e118f285b0475',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@13e71f2526bec30e8b870828e887ab8a32327650',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index b02b0b4..d173ac04 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -288,17 +288,18 @@
 int AwMainDelegate::RunProcess(
     const std::string& process_type,
     const content::MainFunctionParams& main_function_params) {
-  if (process_type.empty()) {
-    browser_runner_ = content::BrowserMainRunner::Create();
-    int exit_code = browser_runner_->Initialize(main_function_params);
-    DCHECK_LT(exit_code, 0);
+  // Defer to the default main method outside the browser process.
+  if (!process_type.empty())
+    return -1;
 
-    // Return 0 so that we do NOT trigger the default behavior. On Android, the
-    // UI message loop is managed by the Java application.
-    return 0;
-  }
-
-  return -1;
+  browser_runner_ = content::BrowserMainRunner::Create();
+  int exit_code = browser_runner_->Initialize(main_function_params);
+  // We do not expect Initialize() to ever fail in AndroidWebView. On success
+  // it returns a negative value but we do not want to use that on Android.
+  DCHECK_LT(exit_code, 0);
+  // Return 0 so that we do NOT trigger the default behavior. On Android, the
+  // UI message loop is managed by the Java application.
+  return 0;
 }
 
 void AwMainDelegate::ProcessExiting(const std::string& process_type) {
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7fa6dc99..e34bfec 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -214,8 +214,6 @@
     "detachable_base/detachable_base_pairing_status.h",
     "disconnected_app_handler.cc",
     "disconnected_app_handler.h",
-    "display/ash_display_controller.cc",
-    "display/ash_display_controller.h",
     "display/cros_display_config.cc",
     "display/cros_display_config.h",
     "display/cursor_window_controller.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index e6b1bc9..a7273995 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -1014,9 +1014,6 @@
 
 void AppListControllerImpl::ViewClosing() {
   if (presenter_.GetView()->search_box_view()->is_search_box_active()) {
-    // Close the search box if it is open when the app list is closing.
-    presenter_.HandleCloseOpenSearchBox();
-
     // Close the virtual keyboard before the app list view is dismissed.
     // Otherwise if the browser is behind the app list view, after the latter is
     // closed, IME is updated because of the changed focus. Consequently,
diff --git a/ash/app_list/views/assistant/privacy_info_view.cc b/ash/app_list/views/assistant/privacy_info_view.cc
index 4facca41..c579b81 100644
--- a/ash/app_list/views/assistant/privacy_info_view.cc
+++ b/ash/app_list/views/assistant/privacy_info_view.cc
@@ -173,9 +173,8 @@
   close_button_->SetImage(views::ImageButton::STATE_NORMAL,
                           gfx::CreateVectorIcon(views::kCloseIcon, kIconSizeDip,
                                                 gfx::kGoogleGrey700));
-  close_button_->SetImageAlignment(
-      views::ImageButton::HorizontalAlignment::ALIGN_CENTER,
-      views::ImageButton::VerticalAlignment::ALIGN_MIDDLE);
+  close_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  close_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   base::string16 close_button_label(
       l10n_util::GetStringUTF16(IDS_APP_LIST_ASSISTANT_PRIVACY_INFO_CLOSE));
   close_button_->SetAccessibleName(close_button_label);
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 4926610..27f2bf5 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -227,8 +227,8 @@
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   back->SetImage(views::ImageButton::STATE_NORMAL,
                  rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
-  back->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                          views::ImageButton::ALIGN_MIDDLE);
+  back->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  back->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   back->SetVisible(false);
   base::string16 back_button_label(
       l10n_util::GetStringUTF16(IDS_APP_LIST_BACK));
diff --git a/ash/app_list/views/search_result_actions_view.cc b/ash/app_list/views/search_result_actions_view.cc
index e07b1f0b..f8a697e 100644
--- a/ash/app_list/views/search_result_actions_view.cc
+++ b/ash/app_list/views/search_result_actions_view.cc
@@ -96,8 +96,8 @@
   SetInkDropMode(InkDropMode::ON);
 
   SetPreferredSize({kImageButtonSizeDip, kImageButtonSizeDip});
-  SetImageAlignment(HorizontalAlignment::ALIGN_CENTER,
-                    VerticalAlignment::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
 
   SetButtonImage(action.image,
                  AppListConfig::instance().search_list_icon_dimension());
diff --git a/ash/assistant/ui/base/assistant_button.cc b/ash/assistant/ui/base/assistant_button.cc
index 38532f0..57eb7d9 100644
--- a/ash/assistant/ui/base/assistant_button.cc
+++ b/ash/assistant/ui/base/assistant_button.cc
@@ -33,8 +33,8 @@
   SetFocusForPlatform();
 
   // Image.
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
 
   // Ink drop.
   SetInkDropMode(InkDropMode::ON);
diff --git a/ash/assistant/ui/main_stage/suggestion_container_view.cc b/ash/assistant/ui/main_stage/suggestion_container_view.cc
index ec90e7f9..fc3e270 100644
--- a/ash/assistant/ui/main_stage/suggestion_container_view.cc
+++ b/ash/assistant/ui/main_stage/suggestion_container_view.cc
@@ -192,8 +192,10 @@
     AssistantVisibility old_visibility,
     base::Optional<AssistantEntryPoint> entry_point,
     base::Optional<AssistantExitPoint> exit_point) {
-  if (assistant::util::IsStartingSession(new_visibility, old_visibility)) {
-    // Show conversation starters at the start of a new Assistant session.
+  if (assistant::util::IsStartingSession(new_visibility, old_visibility) &&
+      entry_point.value() != AssistantEntryPoint::kLauncherSearchResult) {
+    // Show conversation starters at the start of a new Assistant session except
+    // when the user already started a query in Launcher quick search box (QSB).
     OnConversationStartersChanged(
         delegate_->GetCacheModel()->GetConversationStarters());
     return;
diff --git a/ash/components/shortcut_viewer/views/ksv_search_box_view.cc b/ash/components/shortcut_viewer/views/ksv_search_box_view.cc
index 7a67814e..90029175 100644
--- a/ash/components/shortcut_viewer/views/ksv_search_box_view.cc
+++ b/ash/components/shortcut_viewer/views/ksv_search_box_view.cc
@@ -112,8 +112,8 @@
       views::ImageButton::STATE_NORMAL,
       gfx::CreateVectorIcon(kKsvSearchCloseIcon, gfx::kGoogleGrey700));
   close->SetSize(gfx::Size(kIconSize, kIconSize));
-  close->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                           views::ImageButton::ALIGN_MIDDLE);
+  close->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  close->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   const base::string16 close_button_label(
       l10n_util::GetStringUTF16(IDS_KSV_CLEAR_SEARCHBOX_ACCESSIBILITY_NAME));
   close->SetAccessibleName(close_button_label);
@@ -127,8 +127,8 @@
       views::ImageButton::STATE_NORMAL,
       gfx::CreateVectorIcon(kKsvSearchBackIcon, gfx::kGoogleBlue500));
   back->SetSize(gfx::Size(kIconSize, kIconSize));
-  back->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                          views::ImageButton::ALIGN_MIDDLE);
+  back->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  back->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   const base::string16 back_button_label(
       l10n_util::GetStringUTF16(IDS_KSV_BACK_ACCESSIBILITY_NAME));
   back->SetAccessibleName(back_button_label);
diff --git a/ash/dbus/display_service_provider.cc b/ash/dbus/display_service_provider.cc
index 52a0955b..f845b70c 100644
--- a/ash/dbus/display_service_provider.cc
+++ b/ash/dbus/display_service_provider.cc
@@ -6,8 +6,6 @@
 
 #include <utility>
 
-#include "ash/public/interfaces/ash_display_controller.mojom.h"
-#include "ash/public/interfaces/constants.mojom.h"
 #include "ash/shell.h"
 #include "ash/wm/screen_dimmer.h"
 #include "base/bind.h"
@@ -42,24 +40,11 @@
   void ReleaseDisplayOwnership(base::OnceCallback<void(bool)> callback);
 
  private:
-  // Tests may not have a service_manager::Connector. Connect() is called
-  // whenever ash_display_controller_ is used to lazily connect as needed.
-  bool Connect();
-
-  mojom::AshDisplayControllerPtr ash_display_controller_;
   std::unique_ptr<ScreenDimmer> screen_dimmer_;
 
   DISALLOW_COPY_AND_ASSIGN(Impl);
 };
 
-bool DisplayServiceProvider::Impl::Connect() {
-  if (ash_display_controller_)
-    return true;
-  Shell::Get()->connector()->BindInterface(mojom::kServiceName,
-                                           &ash_display_controller_);
-  return !!ash_display_controller_;
-}
-
 void DisplayServiceProvider::Impl::SetDimming(bool dimmed) {
   if (!screen_dimmer_) {
     screen_dimmer_ =
@@ -70,22 +55,22 @@
 
 void DisplayServiceProvider::Impl::TakeDisplayOwnership(
     base::OnceCallback<void(bool)> callback) {
-  if (!Connect()) {
+  if (!Shell::Get()->display_configurator()) {
     LOG(ERROR) << "Display Controller not connected";
     std::move(callback).Run(false);
     return;
   }
-  ash_display_controller_->TakeDisplayControl(std::move(callback));
+  Shell::Get()->display_configurator()->TakeControl(std::move(callback));
 }
 
 void DisplayServiceProvider::Impl::ReleaseDisplayOwnership(
     base::OnceCallback<void(bool)> callback) {
-  if (!Connect()) {
+  if (!Shell::Get()->display_configurator()) {
     LOG(ERROR) << "Display Controller not connected";
     std::move(callback).Run(false);
     return;
   }
-  ash_display_controller_->RelinquishDisplayControl(std::move(callback));
+  Shell::Get()->display_configurator()->RelinquishControl(std::move(callback));
 }
 
 DisplayServiceProvider::DisplayServiceProvider()
diff --git a/ash/display/ash_display_controller.cc b/ash/display/ash_display_controller.cc
deleted file mode 100644
index a311114..0000000
--- a/ash/display/ash_display_controller.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/display/ash_display_controller.h"
-
-#include "ash/shell.h"
-#include "ui/display/manager/display_configurator.h"
-
-namespace ash {
-
-AshDisplayController::AshDisplayController() = default;
-
-AshDisplayController::~AshDisplayController() = default;
-
-void AshDisplayController::BindRequest(
-    mojom::AshDisplayControllerRequest request) {
-  bindings_.AddBinding(this, std::move(request));
-}
-
-void AshDisplayController::TakeDisplayControl(
-    TakeDisplayControlCallback callback) {
-  Shell::Get()->display_configurator()->TakeControl(std::move(callback));
-}
-
-void AshDisplayController::RelinquishDisplayControl(
-    RelinquishDisplayControlCallback callback) {
-  Shell::Get()->display_configurator()->RelinquishControl(std::move(callback));
-}
-
-}  // namespace ash
diff --git a/ash/display/ash_display_controller.h b/ash/display/ash_display_controller.h
deleted file mode 100644
index f2bd867..0000000
--- a/ash/display/ash_display_controller.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_DISPLAY_ASH_DISPLAY_CONTROLLER_H_
-#define ASH_DISPLAY_ASH_DISPLAY_CONTROLLER_H_
-
-#include "ash/public/interfaces/ash_display_controller.mojom.h"
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace ash {
-
-class AshDisplayController : public mojom::AshDisplayController {
- public:
-  AshDisplayController();
-  ~AshDisplayController() override;
-
-  void BindRequest(mojom::AshDisplayControllerRequest request);
-
-  // mojom::AshDisplayController:
-  void TakeDisplayControl(TakeDisplayControlCallback callback) override;
-  void RelinquishDisplayControl(
-      RelinquishDisplayControlCallback callback) override;
-
- private:
-  mojo::BindingSet<mojom::AshDisplayController> bindings_;
-
-  DISALLOW_COPY_AND_ASSIGN(AshDisplayController);
-};
-
-}  // namespace ash
-
-#endif  // ASH_DISPLAY_ASH_DISPLAY_CONTROLLER_H_
diff --git a/ash/display/screen_ash.cc b/ash/display/screen_ash.cc
index 9578af9..8baad56 100644
--- a/ash/display/screen_ash.cc
+++ b/ash/display/screen_ash.cc
@@ -15,10 +15,8 @@
 #include "base/logging.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/display/display.h"
 #include "ui/display/display_finder.h"
 #include "ui/display/manager/display_manager.h"
@@ -124,21 +122,6 @@
   if (!window)
     return GetPrimaryDisplay();
 
-  if (::features::IsSingleProcessMash()) {
-    // In IsSingleProcessMash() ScreenAsh is also called from non-ash code.
-    // Non-ash code creates aura Windows that are not parented to Ash's root
-    // Windows. Check for this first.
-    aura::WindowTreeHostMus* window_tree_host_mus =
-        aura::WindowTreeHostMus::ForWindow(window);
-    if (window_tree_host_mus) {
-      // WindowTreeHostMus::GetDisplay() can return an invalid display (i.e.
-      // with ID == |kInvalidDisplayID|) if that display is being removed. Use
-      // the primary display instead.
-      const auto display = window_tree_host_mus->GetDisplay();
-      return display.is_valid() ? display : GetPrimaryDisplay();
-    }
-  }
-
   const aura::Window* root_window = window->GetRootWindow();
   if (!root_window)
     return GetPrimaryDisplay();
diff --git a/ash/frame/header_view.cc b/ash/frame/header_view.cc
index 3a81c97..008ab7b 100644
--- a/ash/frame/header_view.cc
+++ b/ash/frame/header_view.cc
@@ -16,7 +16,6 @@
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/aura/window.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/views/controls/image_view.h"
diff --git a/ash/login/ui/login_button.cc b/ash/login/ui/login_button.cc
index 2524596..e42d227 100644
--- a/ash/login/ui/login_button.cc
+++ b/ash/login/ui/login_button.cc
@@ -25,8 +25,8 @@
 
 LoginButton::LoginButton(views::ButtonListener* listener)
     : views::ImageButton(listener) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   SetFocusPainter(views::Painter::CreateSolidFocusPainter(
       kFocusBorderColor, kFocusBorderThickness, gfx::InsetsF()));
   SetInkDropMode(InkDropMode::ON);
diff --git a/ash/login/ui/parent_access_view.cc b/ash/login/ui/parent_access_view.cc
index 60529463..d507c5e 100644
--- a/ash/login/ui/parent_access_view.cc
+++ b/ash/login/ui/parent_access_view.cc
@@ -433,8 +433,8 @@
   back_button_->SetImage(views::Button::STATE_NORMAL,
                          gfx::CreateVectorIcon(kLockScreenArrowBackIcon,
                                                kArrowSizeDp, SK_ColorWHITE));
-  back_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                                  views::ImageButton::ALIGN_MIDDLE);
+  back_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  back_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   back_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ASH_LOGIN_BACK_BUTTON_ACCESSIBLE_NAME));
   back_button_->SetFocusBehavior(FocusBehavior::ALWAYS);
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc
index 62607cc..5fb3eb1 100644
--- a/ash/mojo_interface_factory.cc
+++ b/ash/mojo_interface_factory.cc
@@ -15,7 +15,6 @@
 #include "ash/assistant/assistant_screen_context_controller.h"
 #include "ash/assistant/assistant_setup_controller.h"
 #include "ash/autotest/shelf_integration_test_api.h"
-#include "ash/display/ash_display_controller.h"
 #include "ash/display/cros_display_config.h"
 #include "ash/display/display_output_protection.h"
 #include "ash/events/event_rewriter_controller.h"
@@ -81,11 +80,6 @@
     Shell::Get()->app_list_controller()->BindRequest(std::move(request));
 }
 
-void BindAshDisplayControllerRequestOnMainThread(
-    mojom::AshDisplayControllerRequest request) {
-  Shell::Get()->ash_display_controller()->BindRequest(std::move(request));
-}
-
 void BindAssistantAlarmTimerControllerRequestOnMainThread(
     mojom::AssistantAlarmTimerControllerRequest request) {
   Shell::Get()->assistant_controller()->alarm_timer_controller()->BindRequest(
@@ -290,9 +284,6 @@
         main_thread_task_runner);
   }
   registry->AddInterface(
-      base::BindRepeating(&BindAshDisplayControllerRequestOnMainThread),
-      main_thread_task_runner);
-  registry->AddInterface(
       base::BindRepeating(&BindCrosDisplayConfigControllerRequestOnMainThread),
       main_thread_task_runner);
   registry->AddInterface(
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.cc b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.cc
index b343010..afa193e 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.cc
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.cc
@@ -6,43 +6,10 @@
 
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
-#include "base/run_loop.h"
 #include "ui/aura/env.h"
-#include "ui/aura/event_injector.h"
 #include "ui/aura/window.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/views/widget/widget.h"
-
-namespace {
-
-// Update mouse location for |window|. For local window, update its aura::Env
-// directly. For remote window, update aura::Env by injecting a mouse move
-// event. EventInjector is used so that the Window Service side code under mash
-// sees the updated mouse location as well.
-void UpdateMouseLocation(aura::Window* window,
-                         const gfx::Point& screen_location,
-                         bool wait) {
-  if (window->env()->mode() == aura::Env::Mode::LOCAL) {
-    window->env()->SetLastMouseLocation(screen_location);
-    return;
-  }
-
-  ui::MouseEvent event(ui::ET_MOUSE_MOVED, screen_location, screen_location,
-                       ui::EventTimeForNow(), ui::EF_NONE, 0);
-  if (!wait) {
-    aura::EventInjector().Inject(window->GetHost(), &event);
-    return;
-  }
-
-  // Ensure the mouse event goes through when |wait| is set.
-  aura::EventInjector event_injector;
-  base::RunLoop run_loop;
-  event_injector.Inject(window->GetHost(), &event, run_loop.QuitClosure());
-  run_loop.Run();
-}
-
-}  // namespace
 
 namespace ash {
 
@@ -53,8 +20,7 @@
 ImmersiveFullscreenControllerTestApi::~ImmersiveFullscreenControllerTestApi() =
     default;
 
-void ImmersiveFullscreenControllerTestApi::SetupForTest(
-    bool wait_for_mouse_event) {
+void ImmersiveFullscreenControllerTestApi::SetupForTest() {
   immersive_fullscreen_controller_->animations_disabled_for_test_ = true;
 
   // Move the mouse off of the top-of-window views so that it does not keep the
@@ -68,9 +34,7 @@
       bottommost_in_screen = bounds_in_screen[i].bottom();
   }
   gfx::Point cursor_pos(0, bottommost_in_screen + 10);
-  UpdateMouseLocation(
-      immersive_fullscreen_controller_->widget()->GetNativeView(), cursor_pos,
-      wait_for_mouse_event);
+  aura::Env::GetInstance()->SetLastMouseLocation(cursor_pos);
   immersive_fullscreen_controller_->UpdateLocatedEventRevealedLock();
 }
 
diff --git a/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h
index 6d510fa..d8fb97e 100644
--- a/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h
@@ -30,11 +30,8 @@
   };
 
   // Disables animations and moves the mouse so that it is not over the
-  // top-of-window views for the sake of testing. |wait_for_mouse_move| should
-  // normally be true to wait for the generated mouse events to go through under
-  // mash. It is provided for tests that call SetupForTest under the scope of
-  // TestMockTimeTaskRunner::ScopedContext that does not allow RunLoop::Run().
-  void SetupForTest(bool wait_for_mouse_event = true);
+  // top-of-window views for the sake of testing.
+  void SetupForTest();
 
   bool IsTopEdgeHoverTimerRunning() const;
 
diff --git a/ash/public/cpp/manifest.cc b/ash/public/cpp/manifest.cc
index 478ba1c..c972e5ef 100644
--- a/ash/public/cpp/manifest.cc
+++ b/ash/public/cpp/manifest.cc
@@ -7,7 +7,6 @@
 #include "ash/public/interfaces/accessibility_controller.mojom.h"
 #include "ash/public/interfaces/accessibility_focus_ring_controller.mojom.h"
 #include "ash/public/interfaces/app_list.mojom.h"
-#include "ash/public/interfaces/ash_display_controller.mojom.h"
 #include "ash/public/interfaces/ash_message_center_controller.mojom.h"
 #include "ash/public/interfaces/assistant_controller.mojom.h"
 #include "ash/public/interfaces/assistant_volume_control.mojom.h"
@@ -95,9 +94,6 @@
                   mojom::TabletModeController, mojom::TrayAction,
                   mojom::VoiceInteractionController, mojom::VpnList,
                   mojom::WallpaperController>())
-          .ExposeCapability("display", service_manager::Manifest::InterfaceList<
-                                           mojom::AshDisplayController,
-                                           mojom::DisplayOutputProtection>())
           .ExposeCapability("test", service_manager::Manifest::InterfaceList<
                                         mojom::ShelfIntegrationTestApi>())
           .RequireCapability("*", "accessibility")
diff --git a/ash/public/cpp/window_properties.cc b/ash/public/cpp/window_properties.cc
index 1aafd21..5e3a4a7 100644
--- a/ash/public/cpp/window_properties.cc
+++ b/ash/public/cpp/window_properties.cc
@@ -10,16 +10,7 @@
 #include "ash/public/cpp/window_state_type.h"
 #include "ash/public/interfaces/window_pin_type.mojom.h"
 #include "ash/public/interfaces/window_properties.mojom.h"
-#include "base/bind.h"
-#include "base/unguessable_token.h"
-#include "services/ws/public/mojom/window_manager.mojom.h"
-#include "ui/accessibility/platform/aura_window_properties.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/mus/property_converter.h"
 #include "ui/aura/window.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image_skia.h"
 #include "ui/wm/core/window_properties.h"
 
 DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_PUBLIC_EXPORT,
@@ -29,123 +20,6 @@
                                        ash::BackdropWindowMode)
 
 namespace ash {
-namespace {
-
-bool IsValidWindowVisibilityAnimationTransition(int64_t value) {
-  return value == wm::ANIMATE_SHOW || value == wm::ANIMATE_HIDE ||
-         value == wm::ANIMATE_BOTH || value == wm::ANIMATE_NONE;
-}
-
-bool IsValidWindowPinType(int64_t value) {
-  return value == static_cast<int64_t>(mojom::WindowPinType::NONE) ||
-         value == static_cast<int64_t>(mojom::WindowPinType::PINNED) ||
-         value == static_cast<int64_t>(mojom::WindowPinType::TRUSTED_PINNED);
-}
-
-}  // namespace
-
-void RegisterWindowProperties(aura::PropertyConverter* property_converter) {
-  property_converter->RegisterStringProperty(
-      kArcPackageNameKey, ws::mojom::WindowManager::kArcPackageName_Property);
-  property_converter->RegisterPrimitiveProperty(
-      aura::client::kAppType, mojom::kAppType_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kBlockedForAssistantSnapshotKey,
-      mojom::kBlockedForAssistantSnapshot_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kCanAttachToAnotherWindowKey, mojom::kCanAttachToAnotherWindow_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kCanConsumeSystemKeysKey, mojom::kCanConsumeSystemKeys_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterStringProperty(
-      ui::kChildAXTreeID, ws::mojom::WindowManager::kChildAXTreeID_Property);
-  property_converter->RegisterPrimitiveProperty(
-      kFrameActiveColorKey,
-      ws::mojom::WindowManager::kFrameActiveColor_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kFrameInactiveColorKey,
-      ws::mojom::WindowManager::kFrameInactiveColor_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kHideInOverviewKey, mojom::kHideInOverview_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kHideShelfWhenFullscreenKey, mojom::kHideShelfWhenFullscreen_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kImmersiveImpliedByFullscreen,
-      mojom::kImmersiveImpliedByFullscreen_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kImmersiveIsActive, mojom::kImmersiveIsActive_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterRectProperty(
-      kImmersiveTopContainerBoundsInScreen,
-      mojom::kImmersiveTopContainerBoundsInScreen_Property);
-  property_converter->RegisterPrimitiveProperty(
-      kIsDeferredTabDraggingTargetWindowKey,
-      mojom::kIsDeferredTabDraggingTargetWindow_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kIsDraggingTabsKey, mojom::kIsDraggingTabs_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kIsShowingInOverviewKey, mojom::kIsShowingInOverview_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kRenderTitleAreaProperty,
-      ws::mojom::WindowManager::kRenderParentTitleArea_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kShelfItemTypeKey, ws::mojom::WindowManager::kShelfItemType_Property,
-      base::BindRepeating(&IsValidShelfItemType));
-  property_converter->RegisterPrimitiveProperty(
-      aura::client::kTopViewInset, mojom::kTopViewInset_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      kWindowPinTypeKey, mojom::kWindowPinType_Property,
-      base::BindRepeating(&IsValidWindowPinType));
-  property_converter->RegisterPrimitiveProperty(
-      kWindowPositionManagedTypeKey, mojom::kWindowPositionManaged_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterStringProperty(
-      kShelfIDKey, ws::mojom::WindowManager::kShelfID_Property);
-  property_converter->RegisterRectProperty(
-      kRestoreBoundsOverrideKey, mojom::kRestoreBoundsOverride_Property);
-  property_converter->RegisterPrimitiveProperty(
-      kRestoreWindowStateTypeOverrideKey,
-      mojom::kRestoreWindowStateTypeOverride_Property,
-      base::BindRepeating(&IsValidWindowStateType));
-  property_converter->RegisterPrimitiveProperty(
-      aura::client::kTitleShownKey,
-      ws::mojom::WindowManager::kWindowTitleShown_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterWindowPtrProperty(
-      kTabDraggingSourceWindowKey, mojom::kTabDraggingSourceWindow_Property);
-  property_converter->RegisterPrimitiveProperty(
-      kWindowPipTypeKey, mojom::kIsWindowPip_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterTimeDeltaProperty(
-      wm::kWindowVisibilityAnimationDurationKey,
-      ws::mojom::WindowManager::kWindowVisibilityAnimationDuration_Property);
-  property_converter->RegisterPrimitiveProperty(
-      wm::kWindowVisibilityAnimationTransitionKey,
-      ws::mojom::WindowManager::kWindowVisibilityAnimationTransition_Property,
-      base::BindRepeating(&IsValidWindowVisibilityAnimationTransition));
-  property_converter->RegisterPrimitiveProperty(
-      wm::kWindowVisibilityAnimationTypeKey,
-      ws::mojom::WindowManager::kWindowVisibilityAnimationType_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-  property_converter->RegisterPrimitiveProperty(
-      wm::kWindowVisibilityAnimationVerticalPositionKey,
-      ws::mojom::WindowManager::
-          kWindowVisibilityAnimationVerticalPosition_Property,
-      aura::PropertyConverter::CreateAcceptAnyValueCallback());
-}
 
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kArcPackageNameKey, nullptr)
 DEFINE_UI_CLASS_PROPERTY_KEY(BackdropWindowMode,
diff --git a/ash/public/cpp/window_properties.h b/ash/public/cpp/window_properties.h
index 56e8f7e..b4e895b6 100644
--- a/ash/public/cpp/window_properties.h
+++ b/ash/public/cpp/window_properties.h
@@ -13,7 +13,6 @@
 #include "ui/base/class_property.h"
 
 namespace aura {
-class PropertyConverter;
 class Window;
 template <typename T>
 using WindowProperty = ui::ClassProperty<T>;
@@ -37,11 +36,6 @@
   kAuto,  // The window manager decides if the window should have a backdrop.
 };
 
-// Registers Ash's properties with the given PropertyConverter. This allows Ash
-// and other services (eg. Chrome) to exchange Ash window property values.
-ASH_PUBLIC_EXPORT void RegisterWindowProperties(
-    aura::PropertyConverter* property_converter);
-
 // Shell-specific window property keys for use by ash and its clients.
 
 // Alphabetical sort.
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn
index 0ec2d2d..07edf9b 100644
--- a/ash/public/interfaces/BUILD.gn
+++ b/ash/public/interfaces/BUILD.gn
@@ -21,7 +21,6 @@
     "accessibility_focus_ring_controller.mojom",
     "app_list.mojom",
     "app_list_view.mojom",
-    "ash_display_controller.mojom",
     "ash_message_center_controller.mojom",
     "assistant_controller.mojom",
     "assistant_image_downloader.mojom",
diff --git a/ash/public/interfaces/ash_display_controller.mojom b/ash/public/interfaces/ash_display_controller.mojom
deleted file mode 100644
index b94f13e..0000000
--- a/ash/public/interfaces/ash_display_controller.mojom
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ash.mojom;
-
-// Allows configuring various display related state.
-interface AshDisplayController {
-  // ============================ Virtual Terminal ============================
-
-  // Take control of all display output. This is called when switching from the
-  // virtual terminal back to Chrome in response to a dbus message.
-  TakeDisplayControl() => (bool status);
-
-  // Relinquish control of all display output. This is called when switching
-  // from Chrome to the virtual terminal in response to a dbus message.
-  RelinquishDisplayControl() => (bool status);
-};
diff --git a/ash/shelf/window_preview.cc b/ash/shelf/window_preview.cc
index f8aa7719..e3f235b 100644
--- a/ash/shelf/window_preview.cc
+++ b/ash/shelf/window_preview.cc
@@ -158,8 +158,8 @@
   close_button_->SetImage(
       views::Button::STATE_NORMAL,
       gfx::CreateVectorIcon(kOverviewWindowCloseIcon, kCloseButtonColor));
-  close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                                   views::ImageButton::ALIGN_MIDDLE);
+  close_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  close_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   close_button_->SetMinimumImageSize(
       gfx::Size(kCloseButtonImageSize, kCloseButtonImageSize));
 }
diff --git a/ash/shell.cc b/ash/shell.cc
index ed7be4d0..18ee207 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -26,7 +26,6 @@
 #include "ash/dbus/ash_dbus_services.h"
 #include "ash/detachable_base/detachable_base_handler.h"
 #include "ash/detachable_base/detachable_base_notification_controller.h"
-#include "ash/display/ash_display_controller.h"
 #include "ash/display/cros_display_config.h"
 #include "ash/display/cursor_window_controller.h"
 #include "ash/display/display_color_manager.h"
@@ -561,7 +560,6 @@
                           : nullptr),
       aura_env_(owned_aura_env_.get() ? owned_aura_env_.get()
                                       : aura::Env::GetInstance()),
-      ash_display_controller_(std::make_unique<AshDisplayController>()),
       brightness_control_delegate_(
           std::make_unique<system::BrightnessControllerChromeos>()),
       connector_(connector),
diff --git a/ash/shell.h b/ash/shell.h
index e926b5f1..0ad4d12c 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -94,7 +94,6 @@
 class AccessibilityFocusRingController;
 class AshDBusHelper;
 class AshDBusServices;
-class AshDisplayController;
 class AshFocusRules;
 class AppListControllerImpl;
 class NativeCursorManagerAsh;
@@ -319,9 +318,6 @@
   AppListControllerImpl* app_list_controller() {
     return app_list_controller_.get();
   }
-  AshDisplayController* ash_display_controller() {
-    return ash_display_controller_.get();
-  }
   AssistantController* assistant_controller() {
     DCHECK(chromeos::switches::IsAssistantEnabled());
     return assistant_controller_.get();
@@ -688,7 +684,6 @@
   std::unique_ptr<AppListControllerImpl> app_list_controller_;
   std::unique_ptr<AshDBusHelper> ash_dbus_helper_;
   std::unique_ptr<AshDBusServices> ash_dbus_services_;
-  std::unique_ptr<AshDisplayController> ash_display_controller_;
   std::unique_ptr<AssistantController> assistant_controller_;
   std::unique_ptr<BacklightsForcedOffSetter> backlights_forced_off_setter_;
   std::unique_ptr<BrightnessControlDelegate> brightness_control_delegate_;
diff --git a/ash/system/message_center/notification_swipe_control_view.cc b/ash/system/message_center/notification_swipe_control_view.cc
index 575ee9a..4a89160 100644
--- a/ash/system/message_center/notification_swipe_control_view.cc
+++ b/ash/system/message_center/notification_swipe_control_view.cc
@@ -121,8 +121,10 @@
             message_center::kNotificationSettingsButtonIcon,
             message_center_style::kSwipeControlButtonImageSize,
             gfx::kChromeIconGrey));
-    settings_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                                        views::ImageButton::ALIGN_MIDDLE);
+    settings_button_->SetImageHorizontalAlignment(
+        views::ImageButton::ALIGN_CENTER);
+    settings_button_->SetImageVerticalAlignment(
+        views::ImageButton::ALIGN_MIDDLE);
     settings_button_->SetPreferredSize(
         gfx::Size(message_center_style::kSwipeControlButtonSize,
                   message_center_style::kSwipeControlButtonSize));
@@ -152,8 +154,9 @@
             message_center::kNotificationSnoozeButtonIcon,
             message_center_style::kSwipeControlButtonImageSize,
             gfx::kChromeIconGrey));
-    snooze_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                                      views::ImageButton::ALIGN_MIDDLE);
+    snooze_button_->SetImageHorizontalAlignment(
+        views::ImageButton::ALIGN_CENTER);
+    snooze_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
     snooze_button_->SetPreferredSize(
         gfx::Size(message_center_style::kSwipeControlButtonSize,
                   message_center_style::kSwipeControlButtonSize));
diff --git a/ash/system/tray/detailed_view_delegate.cc b/ash/system/tray/detailed_view_delegate.cc
index 2a4b0b9..f2bc883e 100644
--- a/ash/system/tray/detailed_view_delegate.cc
+++ b/ash/system/tray/detailed_view_delegate.cc
@@ -64,8 +64,8 @@
     gfx::ImageSkia image =
         gfx::CreateVectorIcon(kUnifiedMenuArrowBackIcon, kUnifiedMenuIconColor);
     SetImage(views::Button::STATE_NORMAL, image);
-    SetImageAlignment(HorizontalAlignment::ALIGN_RIGHT,
-                      VerticalAlignment::ALIGN_MIDDLE);
+    SetImageHorizontalAlignment(ALIGN_RIGHT);
+    SetImageVerticalAlignment(ALIGN_MIDDLE);
     SetTooltipText(
         l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_PREVIOUS_MENU));
     SetBorder(views::CreateEmptyBorder(
diff --git a/ash/system/tray/system_menu_button.cc b/ash/system/tray/system_menu_button.cc
index 12d0a88d..eb86c61c 100644
--- a/ash/system/tray/system_menu_button.cc
+++ b/ash/system/tray/system_menu_button.cc
@@ -32,7 +32,8 @@
   SetImage(STATE_NORMAL, normal_icon);
   SetImage(STATE_DISABLED, disabled_icon);
 
-  SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(ALIGN_CENTER);
+  SetImageVerticalAlignment(ALIGN_MIDDLE);
   SetPreferredSize(gfx::Size(kMenuButtonSize, kMenuButtonSize));
 
   SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id));
diff --git a/ash/system/unified/feature_pod_button.cc b/ash/system/unified/feature_pod_button.cc
index 845cc483..1921a97 100644
--- a/ash/system/unified/feature_pod_button.cc
+++ b/ash/system/unified/feature_pod_button.cc
@@ -39,7 +39,8 @@
     : views::ImageButton(listener) {
   SetPreferredSize(kUnifiedFeaturePodIconSize);
   SetBorder(views::CreateEmptyBorder(kUnifiedFeaturePodIconPadding));
-  SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(ALIGN_CENTER);
+  SetImageVerticalAlignment(ALIGN_MIDDLE);
   TrayPopupUtils::ConfigureTrayPopupButton(this);
 
   auto path = std::make_unique<SkPath>();
diff --git a/ash/system/unified/top_shortcut_button.cc b/ash/system/unified/top_shortcut_button.cc
index 6531425..8874405 100644
--- a/ash/system/unified/top_shortcut_button.cc
+++ b/ash/system/unified/top_shortcut_button.cc
@@ -40,7 +40,8 @@
 TopShortcutButton::TopShortcutButton(views::ButtonListener* listener,
                                      int accessible_name_id)
     : views::ImageButton(listener) {
-  SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(ALIGN_CENTER);
+  SetImageVerticalAlignment(ALIGN_MIDDLE);
   if (accessible_name_id)
     SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id));
 
diff --git a/ash/wm/collision_detection/collision_detection_utils.cc b/ash/wm/collision_detection/collision_detection_utils.cc
index 0543e19..d7314e60 100644
--- a/ash/wm/collision_detection/collision_detection_utils.cc
+++ b/ash/wm/collision_detection/collision_detection_utils.cc
@@ -9,7 +9,6 @@
 #include "ash/shell.h"
 #include "ash/wm/work_area_insets.h"
 #include "base/macros.h"
-#include "ui/aura/mus/property_converter.h"
 #include "ui/base/class_property.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
diff --git a/ash/wm/desks/close_desk_button.cc b/ash/wm/desks/close_desk_button.cc
index 6f701c2..1226767 100644
--- a/ash/wm/desks/close_desk_button.cc
+++ b/ash/wm/desks/close_desk_button.cc
@@ -35,8 +35,8 @@
 
   SetImage(views::Button::STATE_NORMAL,
            gfx::CreateVectorIcon(kDesksCloseDeskButtonIcon, SK_ColorWHITE));
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   SetBackgroundImageAlignment(views::ImageButton::ALIGN_CENTER,
                               views::ImageButton::ALIGN_MIDDLE);
   SetBackground(
diff --git a/ash/wm/desks/desk.cc b/ash/wm/desks/desk.cc
index acb32f4b..dfda390 100644
--- a/ash/wm/desks/desk.cc
+++ b/ash/wm/desks/desk.cc
@@ -6,12 +6,12 @@
 
 #include <utility>
 
+#include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_transient_descendant_iterator.h"
 #include "ash/wm/window_util.h"
-#include "base/auto_reset.h"
 
 namespace ash {
 
@@ -62,6 +62,11 @@
 
 Desk::~Desk() {
   DCHECK(windows_.empty()) << "DesksController should remove my windows first.";
+
+  for (auto& observer : observers_) {
+    observers_.RemoveObserver(&observer);
+    observer.OnDeskDestroyed(this);
+  }
 }
 
 void Desk::AddObserver(Observer* observer) {
@@ -102,7 +107,13 @@
       transient_window->AddObserver(this);
   }
 
-  NotifyDeskWindowsChanged();
+  NotifyContentChanged();
+}
+
+std::unique_ptr<base::AutoReset<bool>>
+Desk::GetScopedNotifyContentChangedDisabler() {
+  return std::make_unique<base::AutoReset<bool>>(
+      &should_notify_content_changed_, false);
 }
 
 void Desk::Activate(bool update_window_activation) {
@@ -159,10 +170,10 @@
   {
     // Throttle notifying the observers, while we move those windows and notify
     // them only once when done.
-    base::AutoReset<bool> this_desk_throttled(&should_notify_windows_changed_,
+    base::AutoReset<bool> this_desk_throttled(&should_notify_content_changed_,
                                               false);
     base::AutoReset<bool> target_desk_throttled(
-        &(target_desk->should_notify_windows_changed_), false);
+        &(target_desk->should_notify_content_changed_), false);
 
     for (auto* window : windows_) {
       window->RemoveObserver(this);
@@ -191,8 +202,8 @@
     windows_.clear();
   }
 
-  NotifyDeskWindowsChanged();
-  target_desk->NotifyDeskWindowsChanged();
+  NotifyContentChanged();
+  target_desk->NotifyContentChanged();
 }
 
 aura::Window* Desk::GetDeskContainerForRoot(aura::Window* root) const {
@@ -201,18 +212,25 @@
   return root->GetChildById(container_id_);
 }
 
-void Desk::OnWindowDestroying(aura::Window* window) {
+void Desk::OnWindowDestroyed(aura::Window* window) {
+  // We listen to `OnWindowDestroyed()` as opposed to `OnWindowDestroying()`
+  // since we want to refresh the mini_views only after the window has been
+  // removed from the window tree hierarchy.
   const size_t count = windows_.erase(window);
   DCHECK(count);
-  NotifyDeskWindowsChanged();
+
+  // No need to refresh the mini_views if the destroyed window doesn't show up
+  // there in the first place.
+  if (!window->GetProperty(kHideInDeskMiniViewKey))
+    NotifyContentChanged();
 }
 
-void Desk::NotifyDeskWindowsChanged() {
-  if (!should_notify_windows_changed_)
+void Desk::NotifyContentChanged() {
+  if (!should_notify_content_changed_)
     return;
 
   for (auto& observer : observers_)
-    observer.OnDeskWindowsChanged();
+    observer.OnContentChanged();
 }
 
 }  // namespace ash
diff --git a/ash/wm/desks/desk.h b/ash/wm/desks/desk.h
index bf77791..35d8f780 100644
--- a/ash/wm/desks/desk.h
+++ b/ash/wm/desks/desk.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "base/auto_reset.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
@@ -31,8 +32,15 @@
  public:
   class Observer : public base::CheckedObserver {
    public:
-    // Called after windows are added or removed from this desk.
-    virtual void OnDeskWindowsChanged() = 0;
+    // Called when the desk's content change as a result of windows addition or
+    // removal. Note that some windows are added or removed, but are not
+    // considered a content change, such as the windows created by overview
+    // mode.
+    virtual void OnContentChanged() = 0;
+
+    // Called when Desk is at the end of its destructor. Desk automatically
+    // removes its Observers before calling this.
+    virtual void OnDeskDestroyed(const Desk* desk) = 0;
   };
 
   explicit Desk(int associated_container_id);
@@ -44,6 +52,10 @@
 
   bool is_active() const { return is_active_; }
 
+  bool should_notify_content_changed() const {
+    return should_notify_content_changed_;
+  }
+
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
@@ -52,6 +64,9 @@
 
   void AddWindowToDesk(aura::Window* window);
 
+  std::unique_ptr<base::AutoReset<bool>>
+  GetScopedNotifyContentChangedDisabler();
+
   // Activates this desk. All windows on this desk (if any) will become visible
   // (by means of showing this desk's associated containers on all root
   // windows). If |update_window_activation| is true, the most recently
@@ -70,11 +85,11 @@
   aura::Window* GetDeskContainerForRoot(aura::Window* root) const;
 
   // aura::WindowObserver:
-  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowDestroyed(aura::Window* window) override;
+
+  void NotifyContentChanged();
 
  private:
-  void NotifyDeskWindowsChanged();
-
   // The associated container ID with this desk.
   const int container_id_;
 
@@ -92,10 +107,10 @@
   // TODO(afakhry): Consider removing this.
   bool is_active_ = false;
 
-  // If false, observers won't be notified of desk's windows changes. This is
+  // If false, observers won't be notified of desk's contents changes. This is
   // used to throttle those notifications when we add or remove many windows,
   // and we want to notify observers only once.
-  bool should_notify_windows_changed_ = true;
+  bool should_notify_content_changed_ = true;
 
   DISALLOW_COPY_AND_ASSIGN(Desk);
 };
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc
index 6cecac8..773d4016 100644
--- a/ash/wm/desks/desk_mini_view.cc
+++ b/ash/wm/desks/desk_mini_view.cc
@@ -87,15 +87,12 @@
 }
 
 DeskMiniView::~DeskMiniView() {
+  // In tests, where animations are disabled, the mini_view maybe destroyed
+  // before the desk.
   if (desk_)
     desk_->RemoveObserver(this);
 }
 
-void DeskMiniView::OnDeskRemoved() {
-  desk_->RemoveObserver(this);
-  desk_ = nullptr;
-}
-
 void DeskMiniView::SetTitle(const base::string16& title) {
   label_->SetText(title);
 }
@@ -175,8 +172,28 @@
   controller->RemoveDesk(desk_);
 }
 
-void DeskMiniView::OnDeskWindowsChanged() {
+void DeskMiniView::OnContentChanged() {
   desk_preview_->RecreateDeskContentsMirrorLayers();
 }
 
+void DeskMiniView::OnDeskDestroyed(const Desk* desk) {
+  // Note that the mini_view outlives the desk (which will be removed after all
+  // DeskController's observers have been notified of its removal) because of
+  // the animation.
+  // Note that we can't make it the other way around (i.e. make the desk outlive
+  // the mini_view). The desk's existence (or lack thereof) is more important
+  // than the existence of the mini_view, since it determines whether we can
+  // create new desks or remove existing ones. This determines whether the close
+  // button will show on hover, and whether the new_desk_button is enabled. We
+  // shouldn't allow that state to be wrong while the mini_views perform the
+  // desk removal animation.
+  // TODO(afakhry): Consider detaching the layer and destroying the mini_view
+  // directly.
+
+  DCHECK_EQ(desk_, desk);
+  desk_ = nullptr;
+
+  // No need to remove `this` as an observer; it's done automatically.
+}
+
 }  // namespace ash
diff --git a/ash/wm/desks/desk_mini_view.h b/ash/wm/desks/desk_mini_view.h
index 616d9f0a..6bb57f81 100644
--- a/ash/wm/desks/desk_mini_view.h
+++ b/ash/wm/desks/desk_mini_view.h
@@ -40,20 +40,6 @@
     return close_desk_button_;
   }
 
-  // Called by DesksBarView to inform us that the desk was actually deleted, and
-  // the animation to remove the mini_view is about to begin.
-  // Note that the mini_view outlives the desk (which will be removed after all
-  // observers have been removed) because of the animation. We need to stop
-  // observing it now.
-  // Note that we can't make it the other way around (i.e. make the desk outlive
-  // the mini_view). The desk's existence (or lack thereof) is more important
-  // than the existence of the mini_view, since it determines whether we can
-  // create new desks or remove existing ones. This determines whether the close
-  // button will show on hover, and whether the new_desk_button is enabled. We
-  // shouldn't allow that state to be wrong while the mini_views perform the
-  // desk removal animation.
-  void OnDeskRemoved();
-
   void SetTitle(const base::string16& title);
 
   // Returns the associated desk's container window on the display this
@@ -77,7 +63,8 @@
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
   // Desk::Observer:
-  void OnDeskWindowsChanged() override;
+  void OnContentChanged() override;
+  void OnDeskDestroyed(const Desk* desk) override;
 
  private:
   // The root window on which this mini_view is created.
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc
index 434c351..e3e32c0b 100644
--- a/ash/wm/desks/desk_preview_view.cc
+++ b/ash/wm/desks/desk_preview_view.cc
@@ -121,6 +121,7 @@
 
   wallpaper_preview_->SetPaintToLayer();
   auto* wallpaper_preview_layer = wallpaper_preview_->layer();
+  wallpaper_preview_layer->SetFillsBoundsOpaquely(false);
   wallpaper_preview_layer->SetRoundedCornerRadius(kCornerRadii);
   wallpaper_preview_layer->SetIsFastRoundedCorner(true);
   AddChildView(wallpaper_preview_);
@@ -128,7 +129,7 @@
   desk_mirrored_contents_view_->SetPaintToLayer(ui::LAYER_NOT_DRAWN);
   ui::Layer* contents_view_layer = desk_mirrored_contents_view_->layer();
   contents_view_layer->SetMasksToBounds(true);
-  contents_view_layer->set_name("Desk mirrored contents");
+  contents_view_layer->set_name("Desk mirrored contents view");
   AddChildView(desk_mirrored_contents_view_);
 
   RecreateDeskContentsMirrorLayers();
@@ -146,10 +147,9 @@
   DCHECK(desk_container->layer());
 
   // Mirror the layer tree of the desk container.
-  std::unique_ptr<ui::Layer> mirrored_content_root_layer =
-      desk_container->layer()->Mirror();
-  mirrored_content_root_layer->SetVisible(true);
-  mirrored_content_root_layer->SetOpacity(1);
+  auto mirrored_content_root_layer =
+      std::make_unique<ui::Layer>(ui::LAYER_NOT_DRAWN);
+  mirrored_content_root_layer->set_name("mirrored contents root layer");
   base::flat_map<ui::Layer*, LayerData> layers_data;
   GetLayersData(desk_container, &layers_data);
   MirrorLayerTree(desk_container->layer(), mirrored_content_root_layer.get(),
@@ -179,11 +179,10 @@
   wallpaper_preview_->SetBoundsRect(bounds);
   desk_mirrored_contents_view_->SetBoundsRect(bounds);
 
-  // The desk's contents mirrored layer needs to be scaled and translated so
-  // that it fits exactly in the center of the view.
+  // The desk's contents mirrored layer needs to be scaled down so that it fits
+  // exactly in the center of the view.
   const auto root_size = mini_view_->root_window()->layer()->size();
   gfx::Transform transform;
-  transform.Translate(kBorderSize, kBorderSize);
   transform.Scale(static_cast<float>(bounds.width()) / root_size.width(),
                   static_cast<float>(bounds.height()) / root_size.height());
   ui::Layer* desk_mirrored_contents_layer =
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index a808cd91..cd750b5 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -243,8 +243,6 @@
   std::transform(partition_iter, mini_views_.end(),
                  std::back_inserter(mini_views_after), transform_lambda);
 
-  removed_mini_view->OnDeskRemoved();
-
   PerformRemoveDeskMiniViewAnimation(std::move(removed_mini_view),
                                      mini_views_before, mini_views_after,
                                      begin_x - GetFirstMiniViewXOffset());
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 32465398..3a116921 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -130,10 +130,18 @@
   const base::flat_set<aura::Window*> removed_desk_windows =
       removed_desk->windows();
 
+  // No need to spend time refreshing the mini_views of the removed desk.
+  auto removed_desk_mini_views_pauser =
+      removed_desk->GetScopedNotifyContentChangedDisabler();
+
   // - Move windows in removed desk (if any) to the currently active desk.
   // - If the active desk is the one being removed, activate the desk to its
   //   left, if no desk to the left, activate one on the right.
   if (removed_desk.get() != active_desk_) {
+    // We will refresh the mini_views of the active desk only once at the end.
+    auto active_desk_mini_view_pauser =
+        active_desk_->GetScopedNotifyContentChangedDisabler();
+
     removed_desk->MoveWindowsToDesk(active_desk_);
 
     // If overview mode is active, we add the windows of the removed desk to the
@@ -154,6 +162,11 @@
 
     DCHECK(target_desk);
 
+    // The target desk, which is about to become active, will have its
+    // mini_views refreshed at the end.
+    auto target_desk_mini_view_pauser =
+        target_desk->GetScopedNotifyContentChangedDisabler();
+
     // The removed desk is the active desk, so temporarily remove its windows
     // from the overview grid which will result in removing the
     // "OverviewModeLabel" widgets created by overview mode for these windows.
@@ -175,6 +188,12 @@
       AppendWindowsToOverview(target_desk->windows(), /*should_animate=*/false);
   }
 
+  // It's OK now to refresh the mini_views of *only* the active desk, and only
+  // if windows from the removed desk moved to it.
+  DCHECK(active_desk_->should_notify_content_changed());
+  if (!removed_desk_windows.empty())
+    active_desk_->NotifyContentChanged();
+
   for (auto& observer : observers_)
     observer.OnDeskRemoved(removed_desk.get());
 
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index 525f2f7..b18dc75 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -122,7 +122,8 @@
   int notify_counts() const { return notify_counts_; }
 
   // Desk::Observer:
-  void OnDeskWindowsChanged() override { ++notify_counts_; }
+  void OnContentChanged() override { ++notify_counts_; }
+  void OnDeskDestroyed(const Desk* desk) override {}
 
  private:
   int notify_counts_ = 0;
@@ -671,7 +672,7 @@
 
   // Active desk_4 and enter overview mode. Expect that the grid is currently
   // empty.
-  const Desk* desk_4 = controller->desks()[3].get();
+  Desk* desk_4 = controller->desks()[3].get();
   ActivateDesk(desk_4);
   auto* overview_controller = Shell::Get()->overview_controller();
   overview_controller->ToggleOverview();
@@ -686,11 +687,23 @@
   const auto* desks_bar_view = overview_grid->GetDesksBarViewForTesting();
   ASSERT_TRUE(desks_bar_view);
   ASSERT_EQ(4u, desks_bar_view->mini_views().size());
-  const Desk* desk_1 = controller->desks()[0].get();
+  Desk* desk_1 = controller->desks()[0].get();
   const auto* mini_view = desks_bar_view->mini_views().front().get();
   EXPECT_EQ(desk_1, mini_view->desk());
+
+  // Setup observers of both the active and inactive desks to make sure
+  // refreshing the mini_view is requested only *once* for the active desk, and
+  // never for the to-be-removed inactive desk.
+  TestDeskObserver desk_4_observer;
+  desk_4->AddObserver(&desk_4_observer);
+  TestDeskObserver desk_1_observer;
+  desk_1->AddObserver(&desk_1_observer);
+
   CloseDeskFromMiniView(mini_view, GetEventGenerator());
 
+  EXPECT_EQ(0, desk_1_observer.notify_counts());
+  EXPECT_EQ(1, desk_4_observer.notify_counts());
+
   ASSERT_EQ(3u, desks_bar_view->mini_views().size());
   EXPECT_TRUE(overview_controller->InOverviewSession());
   ASSERT_EQ(2u, overview_grid->window_list().size());
@@ -704,6 +717,20 @@
   // Make sure overview mode remains active.
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(overview_controller->InOverviewSession());
+
+  // Removing a desk with no windows should not result in any new mini_views
+  // updates.
+  mini_view = desks_bar_view->mini_views().front().get();
+  EXPECT_TRUE(mini_view->desk()->windows().empty());
+  CloseDeskFromMiniView(mini_view, GetEventGenerator());
+  EXPECT_EQ(1, desk_4_observer.notify_counts());
+
+  // Exiting overview mode should not cause any mini_views refreshes, since the
+  // destroyed overview-specific windows do not show up in the mini_view.
+  overview_controller->ToggleOverview();
+  EXPECT_FALSE(overview_controller->InOverviewSession());
+  EXPECT_EQ(1, desk_4_observer.notify_counts());
+  desk_4->RemoveObserver(&desk_4_observer);
 }
 
 TEST_F(DesksTest, RemoveActiveDeskFromOverview) {
@@ -714,13 +741,14 @@
   ASSERT_EQ(2u, controller->desks().size());
 
   // Create two windows on desk_1.
+  Desk* desk_1 = controller->desks()[0].get();
   auto win0 = CreateTestWindow(gfx::Rect(0, 0, 250, 100));
   auto win1 = CreateTestWindow(gfx::Rect(50, 50, 200, 200));
   wm::ActivateWindow(win0.get());
   EXPECT_EQ(win0.get(), wm::GetActiveWindow());
 
   // Activate desk_2 and create one more window.
-  const Desk* desk_2 = controller->desks()[1].get();
+  Desk* desk_2 = controller->desks()[1].get();
   ActivateDesk(desk_2);
   auto win2 = CreateTestWindow(gfx::Rect(50, 50, 200, 200));
   wm::ActivateWindow(win2.get());
@@ -738,13 +766,24 @@
   ASSERT_EQ(2u, desks_bar_view->mini_views().size());
   const auto* mini_view = desks_bar_view->mini_views().back().get();
   EXPECT_EQ(desk_2, mini_view->desk());
+
+  // Setup observers of both the active and inactive desks to make sure
+  // refreshing the mini_view is requested only *once* for the soon-to-be active
+  // desk_1, and never for the to-be-removed currently active desk_2.
+  TestDeskObserver desk_1_observer;
+  desk_1->AddObserver(&desk_1_observer);
+  TestDeskObserver desk_2_observer;
+  desk_2->AddObserver(&desk_2_observer);
+
   CloseDeskFromMiniView(mini_view, GetEventGenerator());
 
+  EXPECT_EQ(1, desk_1_observer.notify_counts());
+  EXPECT_EQ(0, desk_2_observer.notify_counts());
+
   // desk_1 will become active, and windows from desk_2 and desk_1 will merge
   // and added in the overview grid in the order of MRU.
   ASSERT_EQ(1u, controller->desks().size());
   ASSERT_EQ(1u, desks_bar_view->mini_views().size());
-  const Desk* desk_1 = controller->desks()[0].get();
   EXPECT_TRUE(desk_1->is_active());
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_EQ(3u, overview_grid->window_list().size());
@@ -763,6 +802,13 @@
   // Make sure overview mode remains active.
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(overview_controller->InOverviewSession());
+
+  // Exiting overview mode should not cause any mini_views refreshes, since the
+  // destroyed overview-specific windows do not show up in the mini_view.
+  overview_controller->ToggleOverview();
+  EXPECT_FALSE(overview_controller->InOverviewSession());
+  EXPECT_EQ(1, desk_1_observer.notify_counts());
+  desk_1->RemoveObserver(&desk_1_observer);
 }
 
 TEST_F(DesksTest, ActivateActiveDeskFromOverview) {
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 1c010b1..645a93b2 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -188,8 +188,8 @@
     SetImage(
         views::Button::STATE_NORMAL,
         gfx::CreateVectorIcon(kOverviewWindowCloseIcon, kCloseButtonColor));
-    SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                      views::ImageButton::ALIGN_MIDDLE);
+    SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+    SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
     SetMinimumImageSize(gfx::Size(kHeaderHeightDp, kHeaderHeightDp));
     SetAccessibleName(l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
     SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc
index 24467bdb7..09322247 100644
--- a/ash/wm/workspace/backdrop_controller.cc
+++ b/ash/wm/workspace/backdrop_controller.cc
@@ -17,6 +17,7 @@
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller.h"
 #include "ash/wm/always_on_top_controller.h"
+#include "ash/wm/desks/desks_util.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_animations.h"
@@ -86,7 +87,7 @@
   Shell::Get()->RemoveShellObserver(this);
   // TODO(oshima): animations won't work right with mus:
   // http://crbug.com/548396.
-  Hide();
+  Hide(/*destroy=*/true);
 }
 
 void BackdropController::OnWindowAddedToLayout() {
@@ -129,8 +130,8 @@
 
   aura::Window* window = GetTopmostWindowWithBackdrop();
   if (!window) {
-    // Hide backdrop since no suitable window was found.
-    Hide();
+    // Destroy the backdrop since no suitable window was found.
+    Hide(/*destroy=*/true);
     return;
   }
   // We are changing the order of windows which will cause recursion.
@@ -171,7 +172,10 @@
 }
 
 void BackdropController::OnOverviewModeStarting() {
-  Hide(/*animate=*/false);
+  // Don't destroy backdrops, just hide them so they don't show in the overview
+  // grid, but keep the widget so that it can be mirrored into the mini_desk
+  // views.
+  Hide(/*destroy=*/false, /*animate=*/false);
 }
 
 void BackdropController::OnOverviewModeEnding(
@@ -212,7 +216,7 @@
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.bounds = container_->GetBoundsInScreen();
   params.layer_type = ui::LAYER_SOLID_COLOR;
-  params.name = "WorkspaceBackdropDelegate";
+  params.name = "Backdrop";
   // To disallow the MRU list from picking this window up it should not be
   // activateable.
   params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
@@ -220,7 +224,7 @@
   params.parent = container_;
   backdrop_->Init(params);
   backdrop_window_ = backdrop_->GetNativeWindow();
-  backdrop_window_->SetName("Backdrop");
+  backdrop_window_->SetProperty(kHideInOverviewKey, true);
   // The backdrop window in always on top container can be reparented without
   // this when the window is set to fullscreen.
   AlwaysOnTopController::SetDisallowReparent(backdrop_window_);
@@ -252,11 +256,31 @@
   for (auto window_iter = windows.rbegin(); window_iter != windows.rend();
        ++window_iter) {
     aura::Window* window = *window_iter;
-    if (window != backdrop_window_ && window->layer()->GetTargetVisibility() &&
-        window->type() == aura::client::WINDOW_TYPE_NORMAL &&
-        ::wm::CanActivateWindow(window) && WindowShouldHaveBackdrop(window)) {
-      return window;
+    if (window == backdrop_window_)
+      continue;
+
+    if (window->type() != aura::client::WINDOW_TYPE_NORMAL)
+      continue;
+
+    auto* window_state = wm::GetWindowState(window);
+    if (window_state->IsMinimized())
+      continue;
+
+    // No need to check the visibility or the activateability of the window if
+    // this is an inactive desk's container.
+    if (!desks_util::IsDeskContainer(container_) ||
+        desks_util::IsActiveDeskContainer(container_)) {
+      if (!window->layer()->GetTargetVisibility())
+        continue;
+
+      if (!::wm::CanActivateWindow(window))
+        continue;
     }
+
+    if (!WindowShouldHaveBackdrop(window))
+      continue;
+
+    return window;
   }
   return nullptr;
 }
@@ -287,7 +311,7 @@
   backdrop_->Show();
 }
 
-void BackdropController::Hide(bool animate) {
+void BackdropController::Hide(bool destroy, bool animate) {
   if (!backdrop_)
     return;
 
@@ -307,11 +331,15 @@
     backdrop_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
   }
 
-  backdrop_->Close();
-  backdrop_ = nullptr;
-  backdrop_window_ = nullptr;
-  original_event_handler_ = nullptr;
-  backdrop_event_handler_.reset();
+  if (destroy) {
+    backdrop_->Close();
+    backdrop_ = nullptr;
+    backdrop_window_ = nullptr;
+    original_event_handler_ = nullptr;
+    backdrop_event_handler_.reset();
+  } else {
+    backdrop_->Hide();
+  }
 }
 
 bool BackdropController::BackdropShouldFullscreen() {
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h
index 421a0af..276691e5 100644
--- a/ash/wm/workspace/backdrop_controller.h
+++ b/ash/wm/workspace/backdrop_controller.h
@@ -99,8 +99,9 @@
   // Show the backdrop window.
   void Show();
 
-  // Hide the backdrop window.
-  void Hide(bool animate = true);
+  // Hide the backdrop window. If |destroy| is true, the backdrop widget will be
+  // destroyed, otherwise it'll be just hidden.
+  void Hide(bool destroy, bool animate = true);
 
   // Returns true if the backdrop window should be fullscreen. It should not be
   // fullscreen only if 1) split view is active and 2) there is only one snapped
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 6406454..f1a5a32b3 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1392,12 +1392,15 @@
   // Toggle overview.
   Shell::Get()->overview_controller()->ToggleOverview();
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
+  backdrop = test_helper.GetBackdropWindow();
+  ASSERT_TRUE(backdrop);
+  EXPECT_FALSE(backdrop->IsVisible());
 
   Shell::Get()->overview_controller()->ToggleOverview();
   base::RunLoop().RunUntilIdle();
   backdrop = test_helper.GetBackdropWindow();
-  EXPECT_TRUE(backdrop);
+  ASSERT_TRUE(backdrop);
+  EXPECT_TRUE(backdrop->IsVisible());
   {
     aura::Window::Windows children = window1->parent()->children();
     EXPECT_EQ(4U, children.size());
@@ -1422,10 +1425,14 @@
   // Toggle overview with the delegate.
   Shell::Get()->overview_controller()->ToggleOverview();
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(test_helper.GetBackdropWindow());
+  backdrop = test_helper.GetBackdropWindow();
+  ASSERT_TRUE(backdrop);
+  EXPECT_FALSE(backdrop->IsVisible());
   Shell::Get()->overview_controller()->ToggleOverview();
   base::RunLoop().RunUntilIdle();
   backdrop = test_helper.GetBackdropWindow();
+  ASSERT_TRUE(backdrop);
+  EXPECT_TRUE(backdrop->IsVisible());
   {
     aura::Window::Windows children = window1->parent()->children();
     EXPECT_EQ(4U, children.size());
diff --git a/base/BUILD.gn b/base/BUILD.gn
index d294d8a..93ebb0f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -864,6 +864,8 @@
     "task_runner_util.h",
     "template_util.h",
     "test/malloc_wrapper.h",
+    "third_party/cityhash/city.cc",
+    "third_party/cityhash/city.h",
     "third_party/dmg_fp/dmg_fp.h",
     "third_party/dmg_fp/dtoa_wrapper.cc",
     "third_party/dmg_fp/g_fmt.cc",
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index bb0c1a2..2a9ef4f93 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -255,15 +255,19 @@
     return;
   }
 
-  auto task =
+  Closure task = AdaptCallbackForRepeating(
       BindOnce(&WriteScopedStringToFileAtomically, path_, std::move(data),
                std::move(before_next_write_callback_),
-               std::move(after_next_write_callback_), histogram_suffix_);
+               std::move(after_next_write_callback_), histogram_suffix_));
 
-  // If PostTask() returns false, it means that |task_runner_| isn't
-  // BLOCK_SHUTDOWN and thus isn't appropriate to write an important file.
-  CHECK(task_runner_->PostTask(FROM_HERE, std::move(task)));
+  if (!task_runner_->PostTask(FROM_HERE, MakeCriticalClosure(task))) {
+    // Posting the task to background message loop is not expected
+    // to fail, but if it does, avoid losing data and just hit the disk
+    // on the current thread.
+    NOTREACHED();
 
+    task.Run();
+  }
   ClearPendingWrite();
 }
 
diff --git a/base/hash/hash.cc b/base/hash/hash.cc
index 988daea5a..778aa6f2 100644
--- a/base/hash/hash.cc
+++ b/base/hash/hash.cc
@@ -4,6 +4,9 @@
 
 #include "base/hash/hash.h"
 
+#include "base/third_party/cityhash/city.h"
+#include "build/build_config.h"
+
 // Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
 // code did not come with its own header file, so declaring the function here.)
 // Note: This algorithm is also in Blink under Source/wtf/StringHasher.h.
@@ -11,6 +14,26 @@
 
 namespace base {
 
+size_t FastHash(base::span<const uint8_t> data) {
+  // We use the updated CityHash within our namespace (not the deprecated
+  // version from third_party/smhasher).
+#if defined(ARCH_CPU_64_BITS)
+  return base::internal::cityhash_v111::CityHash64(
+      reinterpret_cast<const char*>(data.data()), data.size());
+#else
+  return base::internal::cityhash_v111::CityHash32(
+      reinterpret_cast<const char*>(data.data()), data.size());
+#endif
+}
+
+size_t FastHash(const std::string& str) {
+#if defined(ARCH_CPU_64_BITS)
+  return base::internal::cityhash_v111::CityHash64(str.data(), str.size());
+#else
+  return base::internal::cityhash_v111::CityHash32(str.data(), str.size());
+#endif
+}
+
 uint32_t Hash(const void* data, size_t length) {
   // Currently our in-memory hash is the same as the persistent hash. The
   // split between in-memory and persistent hash functions is maintained to
diff --git a/base/hash/hash.h b/base/hash/hash.h
index 4bf6829..0f98e4f5 100644
--- a/base/hash/hash.h
+++ b/base/hash/hash.h
@@ -13,20 +13,32 @@
 #include <utility>
 
 #include "base/base_export.h"
+#include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/strings/string16.h"
 
 namespace base {
 
-// Computes a hash of a memory buffer. This hash function is subject to change
-// in the future, so use only for temporary in-memory structures. If you need
-// to persist a change on disk or between computers, use PersistentHash().
-//
-// WARNING: This hash function should not be used for any cryptographic purpose.
+// WARNING: This hash functions should not be used for any cryptographic
+// purpose.
+
+// Deprecated: Computes a hash of a memory buffer, use FastHash() instead.
+// If you need to persist a change on disk or between computers, use
+// PersistentHash().
+// TODO(cavalcantii): Migrate client code to new hash function.
 BASE_EXPORT uint32_t Hash(const void* data, size_t length);
 BASE_EXPORT uint32_t Hash(const std::string& str);
 BASE_EXPORT uint32_t Hash(const string16& str);
 
+// Really *fast* and high quality hash.
+// Recommended hash function for general use, we pick the best performant
+// hash for each build target.
+// It is prone to be updated whenever a newer/faster hash function is
+// publicly available.
+// May changed without warning, do not expect stability of outputs.
+BASE_EXPORT size_t FastHash(base::span<const uint8_t> data);
+BASE_EXPORT size_t FastHash(const std::string& str);
+
 // Computes a hash of a memory buffer. This hash function must not change so
 // that code can use the hashed values for persistent storage purposes or
 // sending across the network. If a new persistent hash function is desired, a
diff --git a/base/task/promise/abstract_promise_unittest.cc b/base/task/promise/abstract_promise_unittest.cc
index df85078..fab3f5b 100644
--- a/base/task/promise/abstract_promise_unittest.cc
+++ b/base/task/promise/abstract_promise_unittest.cc
@@ -16,10 +16,10 @@
 // Even trivial DCHECK_DEATH_TESTs like
 // AbstractPromiseTest.CantRejectIfpromiseDeclaredAsNonRejecting can flakily
 // timeout on the chromeos bots.
-#if DCHECK_IS_ON() && !defined(OS_CHROMEOS)
-#define DCHECK_DEATH_TEST_ENABLED 1
+#if defined(OS_CHROMEOS)
+#define ABSTRACT_PROMISE_DEATH_TEST(test_name) DISABLED_##test_name
 #else
-#define DCHECK_DEATH_TEST_ENABLED 0
+#define ABSTRACT_PROMISE_DEATH_TEST(test_name) test_name
 #endif
 
 using testing::ElementsAre;
@@ -1023,8 +1023,8 @@
   EXPECT_TRUE(any_promise->IsCanceled());
 }
 
-TEST_F(AbstractPromiseTest, DetectResolveDoubleMoveHazard) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(DetectResolveDoubleMoveHazard)) {
   scoped_refptr<AbstractPromise> p0 = ThenPromise(FROM_HERE, nullptr);
 
   scoped_refptr<AbstractPromise> p1 =
@@ -1034,11 +1034,11 @@
     scoped_refptr<AbstractPromise> p2 =
         ThenPromise(FROM_HERE, p0).WithResolve(ArgumentPassingType::kMove);
   });
-#endif
 }
 
-TEST_F(AbstractPromiseTest, DetectMixedResolveCallbackMoveAndNonMoveHazard) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(
+           DetectMixedResolveCallbackMoveAndNonMoveHazard)) {
   scoped_refptr<AbstractPromise> p0 = ThenPromise(FROM_HERE, nullptr);
 
   scoped_refptr<AbstractPromise> p1 =
@@ -1046,7 +1046,6 @@
 
   EXPECT_DCHECK_DEATH(
       { scoped_refptr<AbstractPromise> p2 = ThenPromise(FROM_HERE, p0); });
-#endif
 }
 
 TEST_F(AbstractPromiseTest, MultipleNonMoveCatchCallbacksAreOK) {
@@ -1073,8 +1072,8 @@
   scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p2);
 }
 
-TEST_F(AbstractPromiseTest, DetectCatchCallbackDoubleMoveHazard) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(DetectCatchCallbackDoubleMoveHazard)) {
   /*
    * Key:  T = Then, C = Catch
    *
@@ -1098,11 +1097,11 @@
     scoped_refptr<AbstractPromise> p2 =
         CatchPromise(FROM_HERE, p0).WithReject(ArgumentPassingType::kMove);
   });
-#endif
 }
 
-TEST_F(AbstractPromiseTest, DetectCatchCallbackDoubleMoveHazardInChain) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(DetectCatchCallbackDoubleMoveHazardInChain)) {
   /*
    * Key:  T = Then, C = Catch
    *
@@ -1133,12 +1132,12 @@
     scoped_refptr<AbstractPromise> p4 =
         CatchPromise(FROM_HERE, p2).WithReject(ArgumentPassingType::kMove);
   });
-#endif
 }
 
-TEST_F(AbstractPromiseTest,
-       DetectCatchCallbackDoubleMoveHazardInChainIntermediateThensCanReject) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(
+        DetectCatchCallbackDoubleMoveHazardInChainIntermediateThensCanReject)) {
   /*
    * Key:  T = Then, C = Catch
    *
@@ -1172,11 +1171,11 @@
     scoped_refptr<AbstractPromise> p4 =
         CatchPromise(FROM_HERE, p2).WithReject(ArgumentPassingType::kMove);
   });
-#endif
 }
 
-TEST_F(AbstractPromiseTest, DetectMixedCatchCallbackMoveAndNonMoveHazard) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(DetectMixedCatchCallbackMoveAndNonMoveHazard)) {
   /*
    * Key:  T = Then, C = Catch
    *
@@ -1206,11 +1205,10 @@
 
   EXPECT_DCHECK_DEATH(
       { scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p2); });
-#endif
 }
 
-TEST_F(AbstractPromiseTest, DetectThenCallbackDoubleMoveHazardInChain) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(DetectThenCallbackDoubleMoveHazardInChain)) {
   /*
    * Key:  T = Then, C = Catch
    *
@@ -1239,7 +1237,6 @@
     scoped_refptr<AbstractPromise> p4 =
         ThenPromise(FROM_HERE, p2).WithResolve(ArgumentPassingType::kMove);
   });
-#endif
 }
 
 TEST_F(AbstractPromiseTest, SimpleMissingCatch) {
@@ -1265,8 +1262,7 @@
   scoped_refptr<AbstractPromise> p2 = CatchPromise(FROM_HERE, p1);
 }
 
-TEST_F(AbstractPromiseTest, MissingCatch) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest, ABSTRACT_PROMISE_DEATH_TEST(MissingCatch)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1291,7 +1287,6 @@
   // Under the hood EXPECT_DCHECK_DEATH uses fork() so |p2| isn't actually
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p2);
-#endif
 }
 
 TEST_F(AbstractPromiseTest, MissingCatchNotRequired) {
@@ -1315,8 +1310,8 @@
   RunLoop().RunUntilIdle();
 }
 
-TEST_F(AbstractPromiseTest, MissingCatchFromCurriedPromise) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(MissingCatchFromCurriedPromise)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1350,11 +1345,11 @@
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p3 = CatchPromise(FROM_HERE, p2);
   RunLoop().RunUntilIdle();
-#endif
 }
 
-TEST_F(AbstractPromiseTest, MissingCatchFromCurriedPromiseWithDependent) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(MissingCatchFromCurriedPromiseWithDependent)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1390,12 +1385,11 @@
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p3);
   RunLoop().RunUntilIdle();
-#endif
 }
 
 TEST_F(AbstractPromiseTest,
-       MissingCatchFromCurriedPromiseWithDependentAddedAfterExecution) {
-#if DCHECK_DEATH_TEST_ENABLED
+       ABSTRACT_PROMISE_DEATH_TEST(
+           MissingCatchFromCurriedPromiseWithDependentAddedAfterExecution)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1432,11 +1426,10 @@
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p4 = CatchPromise(FROM_HERE, p3);
   RunLoop().RunUntilIdle();
-#endif
 }
 
-TEST_F(AbstractPromiseTest, MissingCatchLongChain) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(MissingCatchLongChain)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1462,12 +1455,11 @@
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, p4);
   RunLoop().RunUntilIdle();
-#endif
 }
 
 TEST_F(AbstractPromiseTest,
-       ThenAddedToSettledPromiseWithMissingCatchAndSeveralDependents) {
-#if DCHECK_DEATH_TEST_ENABLED
+       ABSTRACT_PROMISE_DEATH_TEST(
+           ThenAddedToSettledPromiseWithMissingCatchAndSeveralDependents)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1498,11 +1490,11 @@
   scoped_refptr<AbstractPromise> p7 = CatchPromise(FROM_HERE, p4);
   scoped_refptr<AbstractPromise> p8 = CatchPromise(FROM_HERE, p5);
   RunLoop().RunUntilIdle();
-#endif
 }
 
-TEST_F(AbstractPromiseTest, ThenAddedAfterChainExecutionWithMissingCatch) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(ThenAddedAfterChainExecutionWithMissingCatch)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1532,7 +1524,6 @@
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, p4);
   RunLoop().RunUntilIdle();
-#endif
 }
 
 TEST_F(AbstractPromiseTest, CatchAddedAfterChainExecution) {
@@ -1560,8 +1551,8 @@
   RunLoop().RunUntilIdle();
 }
 
-TEST_F(AbstractPromiseTest, MultipleThensAddedAfterChainExecution) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(MultipleThensAddedAfterChainExecution)) {
   scoped_refptr<AbstractPromise> p0 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1600,7 +1591,6 @@
   scoped_refptr<AbstractPromise> p9 = CatchPromise(FROM_HERE, p6);
   scoped_refptr<AbstractPromise> p10 = CatchPromise(FROM_HERE, p7);
   RunLoop().RunUntilIdle();
-#endif
 }
 
 TEST_F(AbstractPromiseTest, MultipleDependentsAddedAfterChainExecution) {
@@ -1652,8 +1642,9 @@
   RunLoop().RunUntilIdle();
 }
 
-TEST_F(AbstractPromiseTest, MissingCatchOneSideOfBranchedExecutionChain) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(MissingCatchOneSideOfBranchedExecutionChain)) {
   /*
    * Key:  T = Then, C = Catch
    *
@@ -1690,27 +1681,25 @@
   // cleared so we need to tidy up.
   scoped_refptr<AbstractPromise> p5 = CatchPromise(FROM_HERE, p4);
   RunLoop().RunUntilIdle();
-#endif
 }
 
-TEST_F(AbstractPromiseTest, CantResolveIfpromiseDeclaredAsNonResolving) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(
+    AbstractPromiseTest,
+    ABSTRACT_PROMISE_DEATH_TEST(CantResolveIfpromiseDeclaredAsNonResolving)) {
   scoped_refptr<AbstractPromise> p = DoNothingPromiseBuilder(FROM_HERE);
 
   EXPECT_DCHECK_DEATH({ p->OnResolved(); });
-#endif
 }
 
-TEST_F(AbstractPromiseTest, CantRejectIfpromiseDeclaredAsNonRejecting) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(CantRejectIfpromiseDeclaredAsNonRejecting)) {
   scoped_refptr<AbstractPromise> p = DoNothingPromiseBuilder(FROM_HERE);
 
   EXPECT_DCHECK_DEATH({ p->OnRejected(); });
-#endif
 }
 
-TEST_F(AbstractPromiseTest, DoubleMoveDoNothingPromise) {
-#if DCHECK_DEATH_TEST_ENABLED
+TEST_F(AbstractPromiseTest,
+       ABSTRACT_PROMISE_DEATH_TEST(DoubleMoveDoNothingPromise)) {
   scoped_refptr<AbstractPromise> p1 =
       DoNothingPromiseBuilder(FROM_HERE).SetCanResolve(true);
 
@@ -1731,7 +1720,6 @@
               p->OnResolved();
             }));
   });
-#endif
 }
 
 TEST_F(AbstractPromiseTest, CatchBothSidesOfBranchedExecutionChain) {
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
index f624423..a457c288 100644
--- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc
+++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -149,8 +149,8 @@
   FixtureWithMockTaskRunner()
       : test_task_runner_(MakeRefCounted<TestMockTimeTaskRunner>(
             TestMockTimeTaskRunner::Type::kBoundToThread)),
-        call_counting_clock_(
-            Bind(&TestMockTimeTaskRunner::NowTicks, test_task_runner_)),
+        call_counting_clock_(BindRepeating(&TestMockTimeTaskRunner::NowTicks,
+                                           test_task_runner_)),
         sequence_manager_(SequenceManagerForTest::Create(
             nullptr,
             ThreadTaskRunnerHandle::Get(),
@@ -4142,9 +4142,9 @@
 }
 
 namespace {
-// Inject a test point for recording the destructor calls for Closure objects
-// send to PostTask(). It is awkward usage since we are trying to hook the
-// actual destruction, which is not a common operation.
+// Inject a test point for recording the destructor calls for OnceClosure
+// objects sent to PostTask(). It is awkward usage since we are trying to hook
+// the actual destruction, which is not a common operation.
 class DestructionObserverProbe : public RefCounted<DestructionObserverProbe> {
  public:
   DestructionObserverProbe(bool* task_destroyed,
diff --git a/base/task/thread_pool/service_thread.cc b/base/task/thread_pool/service_thread.cc
index 5aad89e9..2d2d73f 100644
--- a/base/task/thread_pool/service_thread.cc
+++ b/base/task/thread_pool/service_thread.cc
@@ -89,8 +89,8 @@
 
   // Post through the static API to time the full stack. Use a new Now() for
   // every set of traits in case PostTaskWithTraits() itself is slow.
-  // Bonus: this appraoch also includes the overhead of Bind() in the reported
-  // latency).
+  // Bonus: this approach also includes the overhead of BindOnce() in the
+  // reported latency.
   // TODO(jessemckenna): pass |profiled_traits| directly to
   // RecordHeartbeatLatencyAndTasksRunWhileQueuingHistograms() once compiler
   // error on NaCl is fixed
diff --git a/base/task/thread_pool/task_tracker_posix_unittest.cc b/base/task/thread_pool/task_tracker_posix_unittest.cc
index 058afd2..d074c794 100644
--- a/base/task/thread_pool/task_tracker_posix_unittest.cc
+++ b/base/task/thread_pool/task_tracker_posix_unittest.cc
@@ -53,9 +53,10 @@
 // Verify that TaskTrackerPosix runs a Task it receives.
 TEST_F(ThreadPoolTaskTrackerPosixTest, RunTask) {
   bool did_run = false;
-  Task task(FROM_HERE,
-            Bind([](bool* did_run) { *did_run = true; }, Unretained(&did_run)),
-            TimeDelta());
+  Task task(
+      FROM_HERE,
+      BindOnce([](bool* did_run) { *did_run = true; }, Unretained(&did_run)),
+      TimeDelta());
   constexpr TaskTraits default_traits = {};
 
   EXPECT_TRUE(tracker_.WillPostTask(&task, default_traits.shutdown_behavior()));
@@ -75,8 +76,8 @@
   int fds[2];
   ASSERT_EQ(0, pipe(fds));
   Task task(FROM_HERE,
-            Bind(IgnoreResult(&FileDescriptorWatcher::WatchReadable), fds[0],
-                 DoNothing()),
+            BindOnce(IgnoreResult(&FileDescriptorWatcher::WatchReadable),
+                     fds[0], DoNothing()),
             TimeDelta());
   constexpr TaskTraits default_traits = {};
 
diff --git a/base/task/thread_pool/task_tracker_unittest.cc b/base/task/thread_pool/task_tracker_unittest.cc
index 5e12523d..c7da542 100644
--- a/base/task/thread_pool/task_tracker_unittest.cc
+++ b/base/task/thread_pool/task_tracker_unittest.cc
@@ -51,19 +51,19 @@
 // Invokes a closure asynchronously.
 class CallbackThread : public SimpleThread {
  public:
-  explicit CallbackThread(const Closure& closure)
-      : SimpleThread("CallbackThread"), closure_(closure) {}
+  explicit CallbackThread(OnceClosure closure)
+      : SimpleThread("CallbackThread"), closure_(std::move(closure)) {}
 
   // Returns true once the callback returns.
   bool has_returned() { return has_returned_.IsSet(); }
 
  private:
   void Run() override {
-    closure_.Run();
+    std::move(closure_).Run();
     has_returned_.Set();
   }
 
-  const Closure closure_;
+  OnceClosure closure_;
   AtomicFlag has_returned_;
 
   DISALLOW_COPY_AND_ASSIGN(CallbackThread);
@@ -150,7 +150,7 @@
   Task CreateTask() {
     return Task(
         FROM_HERE,
-        Bind(&ThreadPoolTaskTrackerTest::RunTaskCallback, Unretained(this)),
+        BindOnce(&ThreadPoolTaskTrackerTest::RunTaskCallback, Unretained(this)),
         TimeDelta());
   }
 
@@ -170,7 +170,7 @@
     ASSERT_FALSE(thread_calling_shutdown_);
     ASSERT_TRUE(tracker_.HasShutdownStarted());
     thread_calling_shutdown_ = std::make_unique<CallbackThread>(
-        Bind(&TaskTracker::CompleteShutdown, Unretained(&tracker_)));
+        BindOnce(&TaskTracker::CompleteShutdown, Unretained(&tracker_)));
     thread_calling_shutdown_->Start();
     PlatformThread::Sleep(TestTimeouts::tiny_timeout());
     VerifyAsyncShutdownInProgress();
@@ -194,7 +194,7 @@
   void CallFlushFromAnotherThread() {
     ASSERT_FALSE(thread_calling_flush_);
     thread_calling_flush_.reset(new CallbackThread(
-        Bind(&TaskTracker::FlushForTesting, Unretained(&tracker_))));
+        BindOnce(&TaskTracker::FlushForTesting, Unretained(&tracker_))));
     thread_calling_flush_->Start();
   }
 
@@ -285,7 +285,7 @@
                              WaitableEvent::InitialState::NOT_SIGNALED);
   Task blocked_task(
       FROM_HERE,
-      Bind(
+      BindOnce(
           [](WaitableEvent* task_running, WaitableEvent* task_barrier) {
             task_running->Signal();
             test::WaitWithoutBlockingObserver(task_barrier);
@@ -494,7 +494,7 @@
   // Unset the IO allowed bit. Expect TaskTracker to set it before running a
   // task with the MayBlock() trait.
   ThreadRestrictions::SetIOAllowed(false);
-  Task task_with_may_block(FROM_HERE, Bind([]() {
+  Task task_with_may_block(FROM_HERE, BindOnce([]() {
                              // Shouldn't fail.
                              ScopedBlockingCall scope_blocking_call(
                                  FROM_HERE, BlockingType::WILL_BLOCK);
@@ -509,7 +509,7 @@
   // Set the IO allowed bit. Expect TaskTracker to unset it before running a
   // task without the MayBlock() trait.
   ThreadRestrictions::SetIOAllowed(true);
-  Task task_without_may_block(FROM_HERE, Bind([]() {
+  Task task_without_may_block(FROM_HERE, BindOnce([]() {
                                 EXPECT_DCHECK_DEATH({
                                   ScopedBlockingCall scope_blocking_call(
                                       FROM_HERE, BlockingType::WILL_BLOCK);
@@ -932,7 +932,8 @@
       TaskTraits(), nullptr, TaskSourceExecutionMode::kParallel);
 
   const SequenceToken sequence_token = sequence->token();
-  Task task(FROM_HERE, Bind(&ExpectSequenceToken, sequence_token), TimeDelta());
+  Task task(FROM_HERE, BindOnce(&ExpectSequenceToken, sequence_token),
+            TimeDelta());
   tracker_.WillPostTask(&task, sequence->shutdown_behavior());
 
   {
@@ -1149,7 +1150,7 @@
     // running a task without the WithBaseSyncPrimitives() trait.
     internal::AssertBaseSyncPrimitivesAllowed();
     Task task_without_sync_primitives(
-        FROM_HERE, Bind([]() {
+        FROM_HERE, BindOnce([]() {
           EXPECT_DCHECK_DEATH({ internal::AssertBaseSyncPrimitivesAllowed(); });
         }),
         TimeDelta());
@@ -1165,7 +1166,7 @@
     // with the WithBaseSyncPrimitives() trait.
     ThreadRestrictions::DisallowWaiting();
     Task task_with_sync_primitives(
-        FROM_HERE, Bind([]() {
+        FROM_HERE, BindOnce([]() {
           // Shouldn't fail.
           internal::AssertBaseSyncPrimitivesAllowed();
         }),
diff --git a/base/task/thread_pool/thread_group_impl_unittest.cc b/base/task/thread_pool/thread_group_impl_unittest.cc
index 0aec0cc..d87f681 100644
--- a/base/task/thread_pool/thread_group_impl_unittest.cc
+++ b/base/task/thread_pool/thread_group_impl_unittest.cc
@@ -191,7 +191,7 @@
 
     for (size_t i = 0; i < kNumTasksPostedPerThread; ++i) {
       thread_group_->WaitForAllWorkersIdleForTesting();
-      EXPECT_TRUE(factory_.PostTask(PostNestedTask::NO, Closure()));
+      EXPECT_TRUE(factory_.PostTask(PostNestedTask::NO, OnceClosure()));
     }
   }
 
@@ -253,7 +253,7 @@
                                         &mock_pooled_task_runner_delegate_),
       GetParam());
   for (size_t i = 0; i < kNumTasksPostedPerThread; ++i)
-    EXPECT_TRUE(short_task_factory.PostTask(PostNestedTask::NO, Closure()));
+    EXPECT_TRUE(short_task_factory.PostTask(PostNestedTask::NO, OnceClosure()));
   short_task_factory.WaitForAllTasksToRun();
 
   // Release tasks waiting on |event|.
@@ -452,8 +452,8 @@
         TaskSourceExecutionMode::kParallel));
     ASSERT_TRUE(factories.back()->PostTask(
         PostNestedTask::NO,
-        Bind(&ThreadGroupImplCheckTlsReuse::SetTlsValueAndWait,
-             Unretained(this))));
+        BindOnce(&ThreadGroupImplCheckTlsReuse::SetTlsValueAndWait,
+                 Unretained(this))));
     factories.back()->WaitForAllTasksToRun();
   }
 
@@ -474,8 +474,8 @@
     count_waiters.push_back(std::make_unique<WaitableEvent>());
     ASSERT_TRUE(factory->PostTask(
         PostNestedTask::NO,
-        Bind(&ThreadGroupImplCheckTlsReuse::CountZeroTlsValuesAndWait,
-             Unretained(this), count_waiters.back().get())));
+        BindOnce(&ThreadGroupImplCheckTlsReuse::CountZeroTlsValuesAndWait,
+                 Unretained(this), count_waiters.back().get())));
     factory->WaitForAllTasksToRun();
   }
 
@@ -1160,7 +1160,7 @@
     task_runner_->PostTask(
         FROM_HERE,
         BindOnce(
-            [](Closure* extra_threads_running_barrier,
+            [](RepeatingClosure* extra_threads_running_barrier,
                WaitableEvent* extra_threads_continue) {
               extra_threads_running_barrier->Run();
               test::WaitWithoutBlockingObserver(extra_threads_continue);
@@ -1376,7 +1376,8 @@
 
   WaitableEvent blocked_call_continue;
   RepeatingClosure closure = BindRepeating(
-      [](Closure* threads_running_barrier, WaitableEvent* threads_continue,
+      [](RepeatingClosure* threads_running_barrier,
+         WaitableEvent* threads_continue,
          WaitableEvent* blocked_call_continue) {
         threads_running_barrier->Run();
         {
@@ -1405,7 +1406,7 @@
     task_runner_->PostTask(
         FROM_HERE,
         BindOnce(
-            [](Closure* extra_threads_running_barrier,
+            [](RepeatingClosure* extra_threads_running_barrier,
                WaitableEvent* extra_threads_continue) {
               extra_threads_running_barrier->Run();
               test::WaitWithoutBlockingObserver(extra_threads_continue);
@@ -1460,23 +1461,23 @@
 
   // Post ScopedBlockingCall tasks to hit the worker cap.
   for (size_t i = 0; i < kMaxNumberOfWorkers; ++i) {
-    task_runner_->PostTask(FROM_HERE,
-                           BindOnce(
-                               [](Closure* early_threads_barrier_closure,
-                                  WaitableEvent* early_release_threads_continue,
-                                  Closure* early_threads_finished) {
-                                 {
-                                   ScopedBlockingCall scoped_blocking_call(
-                                       FROM_HERE, BlockingType::WILL_BLOCK);
-                                   early_threads_barrier_closure->Run();
-                                   test::WaitWithoutBlockingObserver(
-                                       early_release_threads_continue);
-                                 }
-                                 early_threads_finished->Run();
-                               },
-                               Unretained(&early_threads_barrier_closure),
-                               Unretained(&early_release_threads_continue),
-                               Unretained(&early_threads_finished_barrier)));
+    task_runner_->PostTask(
+        FROM_HERE, BindOnce(
+                       [](RepeatingClosure* early_threads_barrier_closure,
+                          WaitableEvent* early_release_threads_continue,
+                          RepeatingClosure* early_threads_finished) {
+                         {
+                           ScopedBlockingCall scoped_blocking_call(
+                               FROM_HERE, BlockingType::WILL_BLOCK);
+                           early_threads_barrier_closure->Run();
+                           test::WaitWithoutBlockingObserver(
+                               early_release_threads_continue);
+                         }
+                         early_threads_finished->Run();
+                       },
+                       Unretained(&early_threads_barrier_closure),
+                       Unretained(&early_release_threads_continue),
+                       Unretained(&early_threads_finished_barrier)));
   }
 
   early_blocking_threads_running.Wait();
@@ -1497,7 +1498,7 @@
     task_runner_->PostTask(
         FROM_HERE,
         BindOnce(
-            [](Closure* late_threads_barrier_closure,
+            [](RepeatingClosure* late_threads_barrier_closure,
                WaitableEvent* late_release_thread_contine) {
               ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                       BlockingType::WILL_BLOCK);
@@ -1527,7 +1528,7 @@
     task_runner_->PostTask(
         FROM_HERE,
         BindOnce(
-            [](Closure* closure, WaitableEvent* final_tasks_continue) {
+            [](RepeatingClosure* closure, WaitableEvent* final_tasks_continue) {
               closure->Run();
               test::WaitWithoutBlockingObserver(final_tasks_continue);
             },
diff --git a/base/task/thread_pool/thread_group_unittest.cc b/base/task/thread_pool/thread_group_unittest.cc
index 0de9db9a..42cc66f 100644
--- a/base/task/thread_pool/thread_group_unittest.cc
+++ b/base/task/thread_pool/thread_group_unittest.cc
@@ -90,7 +90,7 @@
     EXPECT_FALSE(factory_.task_runner()->RunsTasksInCurrentSequence());
 
     for (size_t i = 0; i < kNumTasksPostedPerThread; ++i)
-      EXPECT_TRUE(factory_.PostTask(post_nested_task_, Closure()));
+      EXPECT_TRUE(factory_.PostTask(post_nested_task_, OnceClosure()));
   }
 
   const scoped_refptr<TaskRunner> task_runner_;
diff --git a/base/test/sequenced_task_runner_test_template.cc b/base/test/sequenced_task_runner_test_template.cc
index de68492..bccc301 100644
--- a/base/test/sequenced_task_runner_test_template.cc
+++ b/base/test/sequenced_task_runner_test_template.cc
@@ -24,35 +24,36 @@
 
 void SequencedTaskTracker::PostWrappedNonNestableTask(
     SequencedTaskRunner* task_runner,
-    const Closure& task) {
+    OnceClosure task) {
   AutoLock event_lock(lock_);
   const int post_i = next_post_i_++;
-  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
-                              task, post_i);
-  task_runner->PostNonNestableTask(FROM_HERE, wrapped_task);
+  auto wrapped_task =
+      BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
+  task_runner->PostNonNestableTask(FROM_HERE, std::move(wrapped_task));
   TaskPosted(post_i);
 }
 
 void SequencedTaskTracker::PostWrappedNestableTask(
     SequencedTaskRunner* task_runner,
-    const Closure& task) {
+    OnceClosure task) {
   AutoLock event_lock(lock_);
   const int post_i = next_post_i_++;
-  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
-                              task, post_i);
-  task_runner->PostTask(FROM_HERE, wrapped_task);
+  auto wrapped_task =
+      BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
+  task_runner->PostTask(FROM_HERE, std::move(wrapped_task));
   TaskPosted(post_i);
 }
 
 void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
     SequencedTaskRunner* task_runner,
-    const Closure& task,
+    OnceClosure task,
     TimeDelta delay) {
   AutoLock event_lock(lock_);
   const int post_i = next_post_i_++;
-  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
-                              task, post_i);
-  task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay);
+  auto wrapped_task =
+      BindOnce(&SequencedTaskTracker::RunTask, this, std::move(task), post_i);
+  task_runner->PostNonNestableDelayedTask(FROM_HERE, std::move(wrapped_task),
+                                          delay);
   TaskPosted(post_i);
 }
 
@@ -60,14 +61,14 @@
     SequencedTaskRunner* task_runner,
     int task_count) {
   for (int i = 0; i < task_count; ++i) {
-    PostWrappedNonNestableTask(task_runner, Closure());
+    PostWrappedNonNestableTask(task_runner, OnceClosure());
   }
 }
 
-void SequencedTaskTracker::RunTask(const Closure& task, int task_i) {
+void SequencedTaskTracker::RunTask(OnceClosure task, int task_i) {
   TaskStarted(task_i);
   if (!task.is_null())
-    task.Run();
+    std::move(task).Run();
   TaskEnded(task_i);
 }
 
diff --git a/base/test/sequenced_task_runner_test_template.h b/base/test/sequenced_task_runner_test_template.h
index 96c7bf8..541ccae 100644
--- a/base/test/sequenced_task_runner_test_template.h
+++ b/base/test/sequenced_task_runner_test_template.h
@@ -42,15 +42,15 @@
 
   // Posts the non-nestable task |task|, and records its post event.
   void PostWrappedNonNestableTask(SequencedTaskRunner* task_runner,
-                                  const Closure& task);
+                                  OnceClosure task);
 
   // Posts the nestable task |task|, and records its post event.
   void PostWrappedNestableTask(SequencedTaskRunner* task_runner,
-                               const Closure& task);
+                               OnceClosure task);
 
   // Posts the delayed non-nestable task |task|, and records its post event.
   void PostWrappedDelayedNonNestableTask(SequencedTaskRunner* task_runner,
-                                         const Closure& task,
+                                         OnceClosure task,
                                          TimeDelta delay);
 
   // Posts |task_count| non-nestable tasks.
@@ -67,7 +67,7 @@
   ~SequencedTaskTracker();
 
   // A task which runs |task|, recording the start and end events.
-  void RunTask(const Closure& task, int task_i);
+  void RunTask(OnceClosure task, int task_i);
 
   // Records a post event for task |i|. The owner is expected to be holding
   // |lock_| (unlike |TaskStarted| and |TaskEnded|).
@@ -137,10 +137,10 @@
 
   this->task_tracker_->PostWrappedNonNestableTask(
       task_runner.get(),
-      Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+      BindOnce(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
   for (int i = 1; i < kTaskCount; ++i) {
     this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(),
-                                                    Closure());
+                                                    OnceClosure());
   }
 
   this->delegate_.StopTaskRunner();
@@ -161,9 +161,10 @@
 
   this->task_tracker_->PostWrappedNestableTask(
       task_runner.get(),
-      Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+      BindOnce(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
   for (int i = 1; i < kTaskCount; ++i) {
-    this->task_tracker_->PostWrappedNestableTask(task_runner.get(), Closure());
+    this->task_tracker_->PostWrappedNestableTask(task_runner.get(),
+                                                 OnceClosure());
   }
 
   this->delegate_.StopTaskRunner();
@@ -185,7 +186,7 @@
 
   for (int i = 0; i < kTaskCount; ++i) {
     this->task_tracker_->PostWrappedDelayedNonNestableTask(
-        task_runner.get(), Closure(),
+        task_runner.get(), OnceClosure(),
         TimeDelta::FromMilliseconds(kDelayIncrementMs * i));
   }
 
@@ -208,12 +209,11 @@
       this->delegate_.GetTaskRunner();
 
   for (int i = 0; i < kParentCount; ++i) {
-    Closure task = Bind(
-        &internal::SequencedTaskTracker::PostNonNestableTasks,
-        this->task_tracker_,
-        RetainedRef(task_runner),
-        kChildrenPerParent);
-    this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(), task);
+    auto task = BindOnce(&internal::SequencedTaskTracker::PostNonNestableTasks,
+                         this->task_tracker_, RetainedRef(task_runner),
+                         kChildrenPerParent);
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(),
+                                                    std::move(task));
   }
 
   this->delegate_.StopTaskRunner();
@@ -239,9 +239,9 @@
       this->delegate_.GetTaskRunner();
 
   this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
-                                                         Closure(), kDelay);
+                                                         OnceClosure(), kDelay);
   this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
-                                                         Closure(), kDelay);
+                                                         OnceClosure(), kDelay);
   this->task_tracker_->WaitForCompletedTasks(kTaskCount);
   this->delegate_.StopTaskRunner();
 
@@ -261,9 +261,9 @@
 
   this->task_tracker_->PostWrappedNonNestableTask(
       task_runner.get(),
-      base::Bind(&PlatformThread::Sleep, TimeDelta::FromMilliseconds(50)));
+      base::BindOnce(&PlatformThread::Sleep, TimeDelta::FromMilliseconds(50)));
   this->task_tracker_->PostWrappedDelayedNonNestableTask(
-      task_runner.get(), Closure(), TimeDelta::FromMilliseconds(10));
+      task_runner.get(), OnceClosure(), TimeDelta::FromMilliseconds(10));
   this->task_tracker_->WaitForCompletedTasks(kTaskCount);
   this->delegate_.StopTaskRunner();
 
@@ -282,11 +282,11 @@
 
   for (int i = 0; i < kTaskCount - 1; i++) {
     this->task_tracker_->PostWrappedNonNestableTask(
-        task_runner.get(),
-        base::Bind(&PlatformThread::Sleep, TimeDelta::FromMilliseconds(50)));
+        task_runner.get(), base::BindOnce(&PlatformThread::Sleep,
+                                          TimeDelta::FromMilliseconds(50)));
   }
   this->task_tracker_->PostWrappedDelayedNonNestableTask(
-      task_runner.get(), Closure(), TimeDelta::FromMilliseconds(10));
+      task_runner.get(), OnceClosure(), TimeDelta::FromMilliseconds(10));
   this->task_tracker_->WaitForCompletedTasks(kTaskCount);
   this->delegate_.StopTaskRunner();
 
@@ -330,7 +330,7 @@
 
   Time time_before_run = Time::Now();
   this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
-                                                         Closure(), kDelay);
+                                                         OnceClosure(), kDelay);
   this->task_tracker_->WaitForCompletedTasks(kTaskCount);
   this->delegate_.StopTaskRunner();
   Time time_after_run = Time::Now();
diff --git a/base/test/task_runner_test_template.cc b/base/test/task_runner_test_template.cc
index fe702472..2a22194 100644
--- a/base/test/task_runner_test_template.cc
+++ b/base/test/task_runner_test_template.cc
@@ -12,11 +12,11 @@
 
 TaskTracker::~TaskTracker() = default;
 
-Closure TaskTracker::WrapTask(const Closure& task, int i) {
-  return Bind(&TaskTracker::RunTask, this, task, i);
+RepeatingClosure TaskTracker::WrapTask(RepeatingClosure task, int i) {
+  return BindRepeating(&TaskTracker::RunTask, this, std::move(task), i);
 }
 
-void TaskTracker::RunTask(const Closure& task, int i) {
+void TaskTracker::RunTask(RepeatingClosure task, int i) {
   AutoLock lock(lock_);
   if (!task.is_null()) {
     task.Run();
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
index 09d707b..37acde1 100644
--- a/base/test/task_runner_test_template.h
+++ b/base/test/task_runner_test_template.h
@@ -43,12 +43,6 @@
 //       MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
 //
 // Easy!
-//
-// The optional test harnesses TaskRunnerAffinityTest can be
-// instanciated in the same way, using the same delegate:
-//
-//   INSTANTIATE_TYPED_TEST_SUITE_P(
-//       MyTaskRunner, TaskRunnerAffinityTest, MyTaskRunnerTestDelegate);
 
 #ifndef BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
 #define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
@@ -81,7 +75,7 @@
   // Returns a closure that runs the given task and increments the run
   // count of |i| by one.  |task| may be null.  It is guaranteed that
   // only one task wrapped by a given tracker will be run at a time.
-  Closure WrapTask(const Closure& task, int i);
+  RepeatingClosure WrapTask(RepeatingClosure task, int i);
 
   std::map<int, int> GetTaskRunCounts() const;
 
@@ -93,7 +87,7 @@
 
   ~TaskTracker();
 
-  void RunTask(const Closure& task, int i);
+  void RunTask(RepeatingClosure task, int i);
 
   mutable Lock lock_;
   std::map<int, int> task_run_counts_;
@@ -108,7 +102,7 @@
 template <typename TaskRunnerTestDelegate>
 class TaskRunnerTest : public testing::Test {
  protected:
-  TaskRunnerTest() : task_tracker_(new test::TaskTracker()) {}
+  TaskRunnerTest() : task_tracker_(base::MakeRefCounted<test::TaskTracker>()) {}
 
   const scoped_refptr<test::TaskTracker> task_tracker_;
   TaskRunnerTestDelegate delegate_;
@@ -128,7 +122,8 @@
   scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
   // Post each ith task i+1 times.
   for (int i = 0; i < 20; ++i) {
-    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    RepeatingClosure ith_task =
+        this->task_tracker_->WrapTask(RepeatingClosure(), i);
     for (int j = 0; j < i + 1; ++j) {
       task_runner->PostTask(FROM_HERE, ith_task);
       ++expected_task_run_counts[i];
@@ -150,7 +145,8 @@
   scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
   // Post each ith task i+1 times with delays from 0-i.
   for (int i = 0; i < 20; ++i) {
-    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    RepeatingClosure ith_task =
+        this->task_tracker_->WrapTask(RepeatingClosure(), i);
     for (int j = 0; j < i + 1; ++j) {
       task_runner->PostDelayedTask(
           FROM_HERE, ith_task, base::TimeDelta::FromMilliseconds(j));
@@ -169,61 +165,6 @@
 // task runner in order to be conformant.
 REGISTER_TYPED_TEST_SUITE_P(TaskRunnerTest, Basic, Delayed);
 
-namespace test {
-
-// Calls RunsTasksInCurrentSequence() on |task_runner| and expects it to
-// equal |expected_value|.
-void ExpectRunsTasksInCurrentSequence(bool expected_value,
-                                      TaskRunner* task_runner);
-
-}  // namespace test
-
-template <typename TaskRunnerTestDelegate>
-class TaskRunnerAffinityTest : public TaskRunnerTest<TaskRunnerTestDelegate> {};
-
-TYPED_TEST_SUITE_P(TaskRunnerAffinityTest);
-
-// Post a bunch of tasks to the task runner as well as to a separate
-// thread, each checking the value of RunsTasksInCurrentSequence(),
-// which should return true for the tasks posted on the task runner
-// and false for the tasks posted on the separate thread.
-TYPED_TEST_P(TaskRunnerAffinityTest, RunsTasksInCurrentSequence) {
-  std::map<int, int> expected_task_run_counts;
-
-  Thread thread("Non-task-runner thread");
-  ASSERT_TRUE(thread.Start());
-  this->delegate_.StartTaskRunner();
-
-  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
-  // Post each ith task i+1 times on the task runner and i+1 times on
-  // the non-task-runner thread.
-  for (int i = 0; i < 20; ++i) {
-    const Closure& ith_task_runner_task = this->task_tracker_->WrapTask(
-        Bind(&test::ExpectRunsTasksInCurrentSequence, true,
-             base::RetainedRef(task_runner)),
-        i);
-    const Closure& ith_non_task_runner_task = this->task_tracker_->WrapTask(
-        Bind(&test::ExpectRunsTasksInCurrentSequence, false,
-             base::RetainedRef(task_runner)),
-        i);
-    for (int j = 0; j < i + 1; ++j) {
-      task_runner->PostTask(FROM_HERE, ith_task_runner_task);
-      thread.task_runner()->PostTask(FROM_HERE, ith_non_task_runner_task);
-      expected_task_run_counts[i] += 2;
-    }
-  }
-
-  this->delegate_.StopTaskRunner();
-  thread.Stop();
-
-  EXPECT_EQ(expected_task_run_counts,
-            this->task_tracker_->GetTaskRunCounts());
-}
-
-// TaskRunnerAffinityTest tests that the TaskRunner implementation
-// can determine if tasks will never be run on a specific thread.
-REGISTER_TYPED_TEST_SUITE_P(TaskRunnerAffinityTest, RunsTasksInCurrentSequence);
-
 }  // namespace base
 
 #endif  // BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/third_party/cityhash/COPYING b/base/third_party/cityhash/COPYING
new file mode 100644
index 0000000..bf15194
--- /dev/null
+++ b/base/third_party/cityhash/COPYING
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
diff --git a/base/third_party/cityhash/README b/base/third_party/cityhash/README
new file mode 100644
index 0000000..0ec19171
--- /dev/null
+++ b/base/third_party/cityhash/README
@@ -0,0 +1,196 @@
+CityHash, a family of hash functions for strings.
+
+
+Introduction
+============
+
+CityHash provides hash functions for strings.  The functions mix the
+input bits thoroughly but are not suitable for cryptography.  See
+"Hash Quality," below, for details on how CityHash was tested and so on.
+
+We provide reference implementations in C++, with a friendly MIT license.
+
+CityHash32() returns a 32-bit hash.
+
+CityHash64() and similar return a 64-bit hash.
+
+CityHash128() and similar return a 128-bit hash and are tuned for
+strings of at least a few hundred bytes.  Depending on your compiler
+and hardware, it's likely faster than CityHash64() on sufficiently long
+strings.  It's slower than necessary on shorter strings, but we expect
+that case to be relatively unimportant.
+
+CityHashCrc128() and similar are variants of CityHash128() that depend
+on _mm_crc32_u64(), an intrinsic that compiles to a CRC32 instruction
+on some CPUs.  However, none of the functions we provide are CRCs.
+
+CityHashCrc256() is a variant of CityHashCrc128() that also depends
+on _mm_crc32_u64().  It returns a 256-bit hash.
+
+All members of the CityHash family were designed with heavy reliance
+on previous work by Austin Appleby, Bob Jenkins, and others.
+For example, CityHash32 has many similarities with Murmur3a.
+
+Performance on long strings: 64-bit CPUs
+========================================
+ 
+We are most excited by the performance of CityHash64() and its variants on
+short strings, but long strings are interesting as well.
+
+CityHash is intended to be fast, under the constraint that it hash very
+well.  For CPUs with the CRC32 instruction, CRC is speedy, but CRC wasn't
+designed as a hash function and shouldn't be used as one.  CityHashCrc128()
+is not a CRC, but it uses the CRC32 machinery.
+
+On a single core of a 2.67GHz Intel Xeon X5550, CityHashCrc256 peaks at about
+5 to 5.5 bytes/cycle.  The other CityHashCrc functions are wrappers around
+CityHashCrc256 and should have similar performance on long strings.
+(CityHashCrc256 in v1.0.3 was even faster, but we decided it wasn't as thorough
+as it should be.)  CityHash128 peaks at about 4.3 bytes/cycle.  The fastest
+Murmur variant on that hardware, Murmur3F, peaks at about 2.4 bytes/cycle.
+We expect the peak speed of CityHash128 to dominate CityHash64, which is
+aimed more toward short strings or use in hash tables.
+
+For long strings, a new function by Bob Jenkins, SpookyHash, is just
+slightly slower than CityHash128 on Intel x86-64 CPUs, but noticeably
+faster on AMD x86-64 CPUs.  For hashing long strings on AMD CPUs
+and/or CPUs without the CRC instruction, SpookyHash may be just as
+good or better than any of the CityHash variants.
+
+Performance on short strings: 64-bit CPUs
+=========================================
+
+For short strings, e.g., most hash table keys, CityHash64 is faster than
+CityHash128, and probably faster than all the aforementioned functions,
+depending on the mix of string lengths.  Here are a few results from that
+same hardware, where we (unrealistically) tested a single string length over
+and over again:
+
+Hash              Results
+------------------------------------------------------------------------------
+CityHash64 v1.0.3 7ns for 1 byte, or 6ns for 8 bytes, or 9ns for 64 bytes
+Murmur2 (64-bit)  6ns for 1 byte, or 6ns for 8 bytes, or 15ns for 64 bytes
+Murmur3F          14ns for 1 byte, or 15ns for 8 bytes, or 23ns for 64 bytes
+
+We don't have CityHash64 benchmarks results for v1.1, but we expect the
+numbers to be similar.
+
+Performance: 32-bit CPUs
+========================
+
+CityHash32 is the newest variant of CityHash.  It is intended for
+32-bit hardware in general but has been mostly tested on x86.  Our benchmarks
+suggest that Murmur3 is the nearest competitor to CityHash32 on x86.
+We don't know of anything faster that has comparable quality.  The speed rankings
+in our testing: CityHash32 > Murmur3f > Murmur3a (for long strings), and
+CityHash32 > Murmur3a > Murmur3f (for short strings).
+
+Installation
+============
+
+We provide reference implementations of several CityHash functions, written
+in C++.  The build system is based on autoconf.  It defaults the C++
+compiler flags to "-g -O2", which is probably slower than -O3 if you are
+using gcc.  YMMV.
+
+On systems with gcc, we generally recommend:
+
+./configure
+make all check CXXFLAGS="-g -O3"
+sudo make install
+
+Or, if your system has the CRC32 instruction, and you want to build everything:
+
+./configure --enable-sse4.2
+make all check CXXFLAGS="-g -O3 -msse4.2"
+sudo make install
+
+Note that our build system doesn't try to determine the appropriate compiler
+flag for enabling SSE4.2.  For gcc it is "-msse4.2".  The --enable-sse4.2
+flag to the configure script controls whether citycrc.h is installed when
+you "make install."  In general, picking the right compiler flags can be
+tricky, and may depend on your compiler, your hardware, and even how you
+plan to use the library.
+
+For generic information about how to configure this software, please try:
+
+./configure --help
+
+Failing that, please work from city.cc and city*.h, as they contain all the
+necessary code.
+
+
+Usage
+=====
+
+The above installation instructions will produce a single library.  It will
+contain CityHash32(), CityHash64(), and CityHash128(), and their variants,
+and possibly CityHashCrc128(), CityHashCrc128WithSeed(), and
+CityHashCrc256().  The functions with Crc in the name are declared in
+citycrc.h; the rest are declared in city.h.
+
+
+Limitations
+===========
+
+1) CityHash32 is intended for little-endian 32-bit code, and everything else in
+the current version of CityHash is intended for little-endian 64-bit CPUs.
+
+All functions that don't use the CRC32 instruction should work in
+little-endian 32-bit or 64-bit code.  CityHash should work on big-endian CPUs
+as well, but we haven't tested that very thoroughly yet.
+
+2) CityHash is fairly complex.  As a result of its complexity, it may not
+perform as expected on some compilers.  For example, preliminary reports
+suggest that some Microsoft compilers compile CityHash to assembly that's
+10-20% slower than it could be.
+
+
+Hash Quality
+============
+
+We like to test hash functions with SMHasher, among other things.
+SMHasher isn't perfect, but it seems to find almost any significant flaw.
+SMHasher is available at http://code.google.com/p/smhasher/
+
+SMHasher is designed to pass a 32-bit seed to the hash functions it tests.
+No CityHash function is designed to work that way, so we adapt as follows:
+For our functions that accept a seed, we use the given seed directly (padded
+with zeroes); for our functions that don't accept a seed, we hash the
+concatenation of the given seed and the input string.
+
+The CityHash functions have the following flaws according to SMHasher:
+
+(1) CityHash64: none
+
+(2) CityHash64WithSeed: none
+
+(3) CityHash64WithSeeds: did not test
+
+(4) CityHash128: none
+
+(5) CityHash128WithSeed: none
+
+(6) CityHashCrc128: none
+
+(7) CityHashCrc128WithSeed: none
+
+(8) CityHashCrc256: none
+
+(9) CityHash32: none
+
+Some minor flaws in 32-bit and 64-bit functions are harmless, as we
+expect the primary use of these functions will be in hash tables.  We
+may have gone slightly overboard in trying to please SMHasher and other
+similar tests, but we don't want anyone to choose a different hash function
+because of some minor issue reported by a quality test.
+
+
+For more information
+====================
+
+http://code.google.com/p/cityhash/
+
+cityhash-discuss@googlegroups.com
+
+Please feel free to send us comments, questions, bug reports, or patches.
diff --git a/base/third_party/cityhash/README.chromium b/base/third_party/cityhash/README.chromium
new file mode 100644
index 0000000..667d2a9d
--- /dev/null
+++ b/base/third_party/cityhash/README.chromium
@@ -0,0 +1,24 @@
+Name: CityHash
+URL: https://github.com/google/cityhash
+Version: 1.1.1
+Revision: 8af9b8c
+License: MIT
+License File: COPYING
+Security Critical: yes
+
+Description:
+This is a fast non-cryptographic hash function.
+
+There are currently two distinct sets of CityHash functions:
+v1.0.3 and v1.1+ that produce distinct outputs.
+
+The version in //third_party/smhasher is 1.0.3 and has some hash
+quality issues that led to non-backwards compatible changes in v1.1+.
+
+Local changes:
+- guarded function declaration (i.e. CityHash64) within a namespace
+(base::internal::cityhash_v111).
+- defined bswap_32/bswap_64 to use compiler builtins to make 'native_client'
+build pass.
+- remove unneeded CRC32 stuff.
+- formating to make 'git cl format' happy.
diff --git a/base/third_party/cityhash/city.cc b/base/third_party/cityhash/city.cc
new file mode 100644
index 0000000..f0af5bbd
--- /dev/null
+++ b/base/third_party/cityhash/city.cc
@@ -0,0 +1,530 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// This file provides CityHash64() and related functions.
+//
+// It's probably possible to create even faster hash functions by
+// writing a program that systematically explores some of the space of
+// possible hash functions, by using SIMD instructions, or by
+// compromising on hash quality.
+
+#include "city.h"
+
+#include <string.h>  // for memcpy and memset
+#include <algorithm>
+
+namespace base {
+namespace internal {
+namespace cityhash_v111 {
+using namespace std;
+
+static uint64 UNALIGNED_LOAD64(const char* p) {
+  uint64 result;
+  memcpy(&result, p, sizeof(result));
+  return result;
+}
+
+static uint32 UNALIGNED_LOAD32(const char* p) {
+  uint32 result;
+  memcpy(&result, p, sizeof(result));
+  return result;
+}
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+
+// Mac OS X / Darwin features
+#include <libkern/OSByteOrder.h>
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif defined(__sun) || defined(sun)
+
+#include <sys/byteorder.h>
+#define bswap_32(x) BSWAP_32(x)
+#define bswap_64(x) BSWAP_64(x)
+
+#elif defined(__FreeBSD__)
+
+#include <sys/endian.h>
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+
+#elif defined(__OpenBSD__)
+
+#include <sys/types.h>
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+
+#elif defined(__NetBSD__)
+
+#include <machine/bswap.h>
+#include <sys/types.h>
+#if defined(__BSWAP_RENAME) && !defined(__bswap_32)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+
+#else
+
+// XXX(cavalcanti): building 'native_client' fails with this header.
+//#include <byteswap.h>
+
+// Falling back to compiler builtins instead.
+#define bswap_32(x) __builtin_bswap32(x)
+#define bswap_64(x) __builtin_bswap64(x)
+
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define uint32_in_expected_order(x) (bswap_32(x))
+#define uint64_in_expected_order(x) (bswap_64(x))
+#else
+#define uint32_in_expected_order(x) (x)
+#define uint64_in_expected_order(x) (x)
+#endif
+
+#if !defined(LIKELY)
+#if HAVE_BUILTIN_EXPECT
+#define LIKELY(x) (__builtin_expect(!!(x), 1))
+#else
+#define LIKELY(x) (x)
+#endif
+#endif
+
+static uint64 Fetch64(const char* p) {
+  return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+}
+
+static uint32 Fetch32(const char* p) {
+  return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+}
+
+// Some primes between 2^63 and 2^64 for various uses.
+static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
+static const uint64 k1 = 0xb492b66fbe98f273ULL;
+static const uint64 k2 = 0x9ae16a3b2f90404fULL;
+
+// Magic numbers for 32-bit hashing.  Copied from Murmur3.
+static const uint32 c1 = 0xcc9e2d51;
+static const uint32 c2 = 0x1b873593;
+
+// A 32-bit to 32-bit integer hash copied from Murmur3.
+static uint32 fmix(uint32 h) {
+  h ^= h >> 16;
+  h *= 0x85ebca6b;
+  h ^= h >> 13;
+  h *= 0xc2b2ae35;
+  h ^= h >> 16;
+  return h;
+}
+
+static uint32 Rotate32(uint32 val, int shift) {
+  // Avoid shifting by 32: doing so yields an undefined result.
+  return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
+}
+
+#undef PERMUTE3
+#define PERMUTE3(a, b, c) \
+  do {                    \
+    std::swap(a, b);      \
+    std::swap(a, c);      \
+  } while (0)
+
+static uint32 Mur(uint32 a, uint32 h) {
+  // Helper from Murmur3 for combining two 32-bit values.
+  a *= c1;
+  a = Rotate32(a, 17);
+  a *= c2;
+  h ^= a;
+  h = Rotate32(h, 19);
+  return h * 5 + 0xe6546b64;
+}
+
+static uint32 Hash32Len13to24(const char* s, size_t len) {
+  uint32 a = Fetch32(s - 4 + (len >> 1));
+  uint32 b = Fetch32(s + 4);
+  uint32 c = Fetch32(s + len - 8);
+  uint32 d = Fetch32(s + (len >> 1));
+  uint32 e = Fetch32(s);
+  uint32 f = Fetch32(s + len - 4);
+  uint32 h = len;
+
+  return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
+}
+
+static uint32 Hash32Len0to4(const char* s, size_t len) {
+  uint32 b = 0;
+  uint32 c = 9;
+  for (size_t i = 0; i < len; i++) {
+    signed char v = s[i];
+    b = b * c1 + v;
+    c ^= b;
+  }
+  return fmix(Mur(b, Mur(len, c)));
+}
+
+static uint32 Hash32Len5to12(const char* s, size_t len) {
+  uint32 a = len, b = len * 5, c = 9, d = b;
+  a += Fetch32(s);
+  b += Fetch32(s + len - 4);
+  c += Fetch32(s + ((len >> 1) & 4));
+  return fmix(Mur(c, Mur(b, Mur(a, d))));
+}
+
+uint32 CityHash32(const char* s, size_t len) {
+  if (len <= 24) {
+    return len <= 12
+               ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len))
+               : Hash32Len13to24(s, len);
+  }
+
+  // len > 24
+  uint32 h = len, g = c1 * len, f = g;
+  uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
+  uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
+  uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
+  uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
+  uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
+  h ^= a0;
+  h = Rotate32(h, 19);
+  h = h * 5 + 0xe6546b64;
+  h ^= a2;
+  h = Rotate32(h, 19);
+  h = h * 5 + 0xe6546b64;
+  g ^= a1;
+  g = Rotate32(g, 19);
+  g = g * 5 + 0xe6546b64;
+  g ^= a3;
+  g = Rotate32(g, 19);
+  g = g * 5 + 0xe6546b64;
+  f += a4;
+  f = Rotate32(f, 19);
+  f = f * 5 + 0xe6546b64;
+  size_t iters = (len - 1) / 20;
+  do {
+    a0 = Rotate32(Fetch32(s) * c1, 17) * c2;
+    a1 = Fetch32(s + 4);
+    a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;
+    a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;
+    a4 = Fetch32(s + 16);
+    h ^= a0;
+    h = Rotate32(h, 18);
+    h = h * 5 + 0xe6546b64;
+    f += a1;
+    f = Rotate32(f, 19);
+    f = f * c1;
+    g += a2;
+    g = Rotate32(g, 18);
+    g = g * 5 + 0xe6546b64;
+    h ^= a3 + a1;
+    h = Rotate32(h, 19);
+    h = h * 5 + 0xe6546b64;
+    g ^= a4;
+    g = bswap_32(g) * 5;
+    h += a4 * 5;
+    h = bswap_32(h);
+    f += a0;
+    PERMUTE3(f, h, g);
+    s += 20;
+  } while (--iters != 0);
+  g = Rotate32(g, 11) * c1;
+  g = Rotate32(g, 17) * c1;
+  f = Rotate32(f, 11) * c1;
+  f = Rotate32(f, 17) * c1;
+  h = Rotate32(h + g, 19);
+  h = h * 5 + 0xe6546b64;
+  h = Rotate32(h, 17) * c1;
+  h = Rotate32(h + f, 19);
+  h = h * 5 + 0xe6546b64;
+  h = Rotate32(h, 17) * c1;
+  return h;
+}
+
+// Bitwise right rotate.  Normally this will compile to a single
+// instruction, especially if the shift is a manifest constant.
+static uint64 Rotate(uint64 val, int shift) {
+  // Avoid shifting by 64: doing so yields an undefined result.
+  return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+}
+
+static uint64 ShiftMix(uint64 val) {
+  return val ^ (val >> 47);
+}
+
+static uint64 HashLen16(uint64 u, uint64 v) {
+  return Hash128to64(uint128(u, v));
+}
+
+static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+  // Murmur-inspired hashing.
+  uint64 a = (u ^ v) * mul;
+  a ^= (a >> 47);
+  uint64 b = (v ^ a) * mul;
+  b ^= (b >> 47);
+  b *= mul;
+  return b;
+}
+
+static uint64 HashLen0to16(const char* s, size_t len) {
+  if (len >= 8) {
+    uint64 mul = k2 + len * 2;
+    uint64 a = Fetch64(s) + k2;
+    uint64 b = Fetch64(s + len - 8);
+    uint64 c = Rotate(b, 37) * mul + a;
+    uint64 d = (Rotate(a, 25) + b) * mul;
+    return HashLen16(c, d, mul);
+  }
+  if (len >= 4) {
+    uint64 mul = k2 + len * 2;
+    uint64 a = Fetch32(s);
+    return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
+  }
+  if (len > 0) {
+    uint8 a = s[0];
+    uint8 b = s[len >> 1];
+    uint8 c = s[len - 1];
+    uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
+    uint32 z = len + (static_cast<uint32>(c) << 2);
+    return ShiftMix(y * k2 ^ z * k0) * k2;
+  }
+  return k2;
+}
+
+// This probably works well for 16-byte strings as well, but it may be overkill
+// in that case.
+static uint64 HashLen17to32(const char* s, size_t len) {
+  uint64 mul = k2 + len * 2;
+  uint64 a = Fetch64(s) * k1;
+  uint64 b = Fetch64(s + 8);
+  uint64 c = Fetch64(s + len - 8) * mul;
+  uint64 d = Fetch64(s + len - 16) * k2;
+  return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d,
+                   a + Rotate(b + k2, 18) + c, mul);
+}
+
+// Return a 16-byte hash for 48 bytes.  Quick and dirty.
+// Callers do best to use "random-looking" values for a and b.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w,
+                                                   uint64 x,
+                                                   uint64 y,
+                                                   uint64 z,
+                                                   uint64 a,
+                                                   uint64 b) {
+  a += w;
+  b = Rotate(b + a + z, 21);
+  uint64 c = a;
+  a += x;
+  a += y;
+  b += Rotate(a, 44);
+  return make_pair(a + z, b + c);
+}
+
+// Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s,
+                                                   uint64 a,
+                                                   uint64 b) {
+  return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
+                                Fetch64(s + 24), a, b);
+}
+
+// Return an 8-byte hash for 33 to 64 bytes.
+static uint64 HashLen33to64(const char* s, size_t len) {
+  uint64 mul = k2 + len * 2;
+  uint64 a = Fetch64(s) * k2;
+  uint64 b = Fetch64(s + 8);
+  uint64 c = Fetch64(s + len - 24);
+  uint64 d = Fetch64(s + len - 32);
+  uint64 e = Fetch64(s + 16) * k2;
+  uint64 f = Fetch64(s + 24) * 9;
+  uint64 g = Fetch64(s + len - 8);
+  uint64 h = Fetch64(s + len - 16) * mul;
+  uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
+  uint64 v = ((a + g) ^ d) + f + 1;
+  uint64 w = bswap_64((u + v) * mul) + h;
+  uint64 x = Rotate(e + f, 42) + c;
+  uint64 y = (bswap_64((v + w) * mul) + g) * mul;
+  uint64 z = e + f + c;
+  a = bswap_64((x + z) * mul + y) + b;
+  b = ShiftMix((z + a) * mul + d + h) * mul;
+  return b + x;
+}
+
+uint64 CityHash64(const char* s, size_t len) {
+  if (len <= 32) {
+    if (len <= 16) {
+      return HashLen0to16(s, len);
+    } else {
+      return HashLen17to32(s, len);
+    }
+  } else if (len <= 64) {
+    return HashLen33to64(s, len);
+  }
+
+  // For strings over 64 bytes we hash the end first, and then as we
+  // loop we keep 56 bytes of state: v, w, x, y, and z.
+  uint64 x = Fetch64(s + len - 40);
+  uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
+  uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
+  pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
+  pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+  x = x * k1 + Fetch64(s);
+
+  // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
+  len = (len - 1) & ~static_cast<size_t>(63);
+  do {
+    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+    x ^= w.second;
+    y += v.first + Fetch64(s + 40);
+    z = Rotate(z + w.first, 33) * k1;
+    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+    std::swap(z, x);
+    s += 64;
+    len -= 64;
+  } while (len != 0);
+  return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
+                   HashLen16(v.second, w.second) + x);
+}
+
+uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
+  return CityHash64WithSeeds(s, len, k2, seed);
+}
+
+uint64 CityHash64WithSeeds(const char* s,
+                           size_t len,
+                           uint64 seed0,
+                           uint64 seed1) {
+  return HashLen16(CityHash64(s, len) - seed0, seed1);
+}
+
+// A subroutine for CityHash128().  Returns a decent 128-bit hash for strings
+// of any length representable in signed long.  Based on City and Murmur.
+static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
+  uint64 a = Uint128Low64(seed);
+  uint64 b = Uint128High64(seed);
+  uint64 c = 0;
+  uint64 d = 0;
+  signed long l = len - 16;
+  if (l <= 0) {  // len <= 16
+    a = ShiftMix(a * k1) * k1;
+    c = b * k1 + HashLen0to16(s, len);
+    d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
+  } else {  // len > 16
+    c = HashLen16(Fetch64(s + len - 8) + k1, a);
+    d = HashLen16(b + len, c + Fetch64(s + len - 16));
+    a += d;
+    do {
+      a ^= ShiftMix(Fetch64(s) * k1) * k1;
+      a *= k1;
+      b ^= a;
+      c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
+      c *= k1;
+      d ^= c;
+      s += 16;
+      l -= 16;
+    } while (l > 0);
+  }
+  a = HashLen16(a, c);
+  b = HashLen16(d, b);
+  return uint128(a ^ b, HashLen16(b, a));
+}
+
+uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
+  if (len < 128) {
+    return CityMurmur(s, len, seed);
+  }
+
+  // We expect len >= 128 to be the common case.  Keep 56 bytes of state:
+  // v, w, x, y, and z.
+  pair<uint64, uint64> v, w;
+  uint64 x = Uint128Low64(seed);
+  uint64 y = Uint128High64(seed);
+  uint64 z = len * k1;
+  v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
+  v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
+  w.first = Rotate(y + z, 35) * k1 + x;
+  w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
+
+  // This is the same inner loop as CityHash64(), manually unrolled.
+  do {
+    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+    x ^= w.second;
+    y += v.first + Fetch64(s + 40);
+    z = Rotate(z + w.first, 33) * k1;
+    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+    std::swap(z, x);
+    s += 64;
+    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+    x ^= w.second;
+    y += v.first + Fetch64(s + 40);
+    z = Rotate(z + w.first, 33) * k1;
+    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+    std::swap(z, x);
+    s += 64;
+    len -= 128;
+  } while (LIKELY(len >= 128));
+  x += Rotate(v.first + z, 49) * k0;
+  y = y * k0 + Rotate(w.second, 37);
+  z = z * k0 + Rotate(w.first, 27);
+  w.first *= 9;
+  v.first *= k0;
+  // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
+  for (size_t tail_done = 0; tail_done < len;) {
+    tail_done += 32;
+    y = Rotate(x + y, 42) * k0 + v.second;
+    w.first += Fetch64(s + len - tail_done + 16);
+    x = x * k0 + w.first;
+    z += w.second + Fetch64(s + len - tail_done);
+    w.second += v.first;
+    v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
+    v.first *= k0;
+  }
+  // At this point our 56 bytes of state should contain more than
+  // enough information for a strong 128-bit hash.  We use two
+  // different 56-byte-to-8-byte hashes to get a 16-byte final result.
+  x = HashLen16(x, v.first);
+  y = HashLen16(y + z, w.first);
+  return uint128(HashLen16(x + v.second, w.second) + y,
+                 HashLen16(x + w.second, y + v.second));
+}
+
+uint128 CityHash128(const char* s, size_t len) {
+  return len >= 16
+             ? CityHash128WithSeed(s + 16, len - 16,
+                                   uint128(Fetch64(s), Fetch64(s + 8) + k0))
+             : CityHash128WithSeed(s, len, uint128(k0, k1));
+}
+
+}  // namespace cityhash_v111
+}  // namespace internal
+}  // namespace base
diff --git a/base/third_party/cityhash/city.h b/base/third_party/cityhash/city.h
new file mode 100644
index 0000000..3e3dcaaa
--- /dev/null
+++ b/base/third_party/cityhash/city.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// http://code.google.com/p/cityhash/
+//
+// This file provides a few functions for hashing strings.  All of them are
+// high-quality functions in the sense that they pass standard tests such
+// as Austin Appleby's SMHasher.  They are also fast.
+//
+// For 64-bit x86 code, on short strings, we don't know of anything faster than
+// CityHash64 that is of comparable quality.  We believe our nearest competitor
+// is Murmur3.  For 64-bit x86 code, CityHash64 is an excellent choice for hash
+// tables and most other hashing (excluding cryptography).
+//
+// For 64-bit x86 code, on long strings, the picture is more complicated.
+// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
+// CityHashCrc128 appears to be faster than all competitors of comparable
+// quality.  CityHash128 is also good but not quite as fast.  We believe our
+// nearest competitor is Bob Jenkins' Spooky.  We don't have great data for
+// other 64-bit CPUs, but for long strings we know that Spooky is slightly
+// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
+// Note that CityHashCrc128 is declared in citycrc.h.
+//
+// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
+// is of comparable quality.  We believe our nearest competitor is Murmur3A.
+// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
+//
+// Functions in the CityHash family are not suitable for cryptography.
+//
+// Please see CityHash's README file for more details on our performance
+// measurements and so on.
+//
+// WARNING: This code has been only lightly tested on big-endian platforms!
+// It is known to work well on little-endian platforms that have a small penalty
+// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
+// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
+// bug reports are welcome.
+//
+// By the way, for some hash functions, given strings a and b, the hash
+// of a+b is easily derived from the hashes of a and b.  This property
+// doesn't hold for any hash functions in this file.
+
+#ifndef BASE_THIRD_PARTY_CITYHASH_CITY_H_
+#define BASE_THIRD_PARTY_CITYHASH_CITY_H_
+
+#include <stdint.h>
+#include <stdlib.h>  // for size_t.
+#include <utility>
+
+// XXX(cavalcantii): Declaring it inside of the 'base' namespace allows to
+// handle linker symbol clash error with deprecated CityHash from
+// third_party/smhasher in a few unit tests.
+namespace base {
+namespace internal {
+namespace cityhash_v111 {
+
+typedef uint8_t uint8;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef std::pair<uint64, uint64> uint128;
+
+inline uint64 Uint128Low64(const uint128& x) {
+  return x.first;
+}
+inline uint64 Uint128High64(const uint128& x) {
+  return x.second;
+}
+
+// Hash function for a byte array.
+uint64 CityHash64(const char* buf, size_t len);
+
+// Hash function for a byte array.  For convenience, a 64-bit seed is also
+// hashed into the result.
+uint64 CityHash64WithSeed(const char* buf, size_t len, uint64 seed);
+
+// Hash function for a byte array.  For convenience, two seeds are also
+// hashed into the result.
+uint64 CityHash64WithSeeds(const char* buf,
+                           size_t len,
+                           uint64 seed0,
+                           uint64 seed1);
+
+// Hash function for a byte array.
+uint128 CityHash128(const char* s, size_t len);
+
+// Hash function for a byte array.  For convenience, a 128-bit seed is also
+// hashed into the result.
+uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed);
+
+// Hash function for a byte array.  Most useful in 32-bit binaries.
+uint32 CityHash32(const char* buf, size_t len);
+
+// Hash 128 input bits down to 64 bits of output.
+// This is intended to be a reasonably good hash function.
+inline uint64 Hash128to64(const uint128& x) {
+  // Murmur-inspired hashing.
+  const uint64 kMul = 0x9ddfea08eb382d69ULL;
+  uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
+  a ^= (a >> 47);
+  uint64 b = (Uint128High64(x) ^ a) * kMul;
+  b ^= (b >> 47);
+  b *= kMul;
+  return b;
+}
+
+}  // namespace cityhash_v111
+}  // namespace internal
+}  // namespace base
+
+#endif  // CITY_HASH_H_
diff --git a/base/third_party/cityhash/patches/0000-build-bots.patch b/base/third_party/cityhash/patches/0000-build-bots.patch
new file mode 100644
index 0000000..23a7156
--- /dev/null
+++ b/base/third_party/cityhash/patches/0000-build-bots.patch
@@ -0,0 +1,227 @@
+diff --git a/base/third_party/cityhash/city.cc b/base/third_party/cityhash/city.cc
+index 41cd5ee16993..be08dc99cf18 100644
+--- a/base/third_party/cityhash/city.cc
++++ b/base/third_party/cityhash/city.cc
+@@ -27,12 +27,14 @@
+ // possible hash functions, by using SIMD instructions, or by
+ // compromising on hash quality.
+ 
+-#include "config.h"
+-#include <city.h>
++#include "city.h"
+ 
+ #include <algorithm>
+ #include <string.h>  // for memcpy and memset
+ 
++namespace base {
++namespace internal {
++namespace cityhash_v111 {
+ using namespace std;
+ 
+ static uint64 UNALIGNED_LOAD64(const char *p) {
+@@ -89,7 +91,12 @@ static uint32 UNALIGNED_LOAD32(const char *p) {
+ 
+ #else
+ 
+-#include <byteswap.h>
++// XXX(cavalcanti): building 'native_client' fails with this header.
++//#include <byteswap.h>
++
++// Falling back to compiler builtins instead.
++#define bswap_32(x) __builtin_bswap32(x)
++#define bswap_64(x) __builtin_bswap64(x)
+ 
+ #endif
+ 
+@@ -217,11 +224,11 @@ uint32 CityHash32(const char *s, size_t len) {
+   f = f * 5 + 0xe6546b64;
+   size_t iters = (len - 1) / 20;
+   do {
+-    uint32 a0 = Rotate32(Fetch32(s) * c1, 17) * c2;
+-    uint32 a1 = Fetch32(s + 4);
+-    uint32 a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;
+-    uint32 a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;
+-    uint32 a4 = Fetch32(s + 16);
++    a0 = Rotate32(Fetch32(s) * c1, 17) * c2;
++    a1 = Fetch32(s + 4);
++    a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;
++    a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;
++    a4 = Fetch32(s + 16);
+     h ^= a0;
+     h = Rotate32(h, 18);
+     h = h * 5 + 0xe6546b64;
+@@ -512,135 +519,7 @@ uint128 CityHash128(const char *s, size_t len) {
+       CityHash128WithSeed(s, len, uint128(k0, k1));
+ }
+ 
+-#ifdef __SSE4_2__
+-#include <citycrc.h>
+-#include <nmmintrin.h>
+-
+-// Requires len >= 240.
+-static void CityHashCrc256Long(const char *s, size_t len,
+-                               uint32 seed, uint64 *result) {
+-  uint64 a = Fetch64(s + 56) + k0;
+-  uint64 b = Fetch64(s + 96) + k0;
+-  uint64 c = result[0] = HashLen16(b, len);
+-  uint64 d = result[1] = Fetch64(s + 120) * k0 + len;
+-  uint64 e = Fetch64(s + 184) + seed;
+-  uint64 f = 0;
+-  uint64 g = 0;
+-  uint64 h = c + d;
+-  uint64 x = seed;
+-  uint64 y = 0;
+-  uint64 z = 0;
+-
+-  // 240 bytes of input per iter.
+-  size_t iters = len / 240;
+-  len -= iters * 240;
+-  do {
+-#undef CHUNK
+-#define CHUNK(r)                                \
+-    PERMUTE3(x, z, y);                          \
+-    b += Fetch64(s);                            \
+-    c += Fetch64(s + 8);                        \
+-    d += Fetch64(s + 16);                       \
+-    e += Fetch64(s + 24);                       \
+-    f += Fetch64(s + 32);                       \
+-    a += b;                                     \
+-    h += f;                                     \
+-    b += c;                                     \
+-    f += d;                                     \
+-    g += e;                                     \
+-    e += z;                                     \
+-    g += x;                                     \
+-    z = _mm_crc32_u64(z, b + g);                \
+-    y = _mm_crc32_u64(y, e + h);                \
+-    x = _mm_crc32_u64(x, f + a);                \
+-    e = Rotate(e, r);                           \
+-    c += e;                                     \
+-    s += 40
+-
+-    CHUNK(0); PERMUTE3(a, h, c);
+-    CHUNK(33); PERMUTE3(a, h, f);
+-    CHUNK(0); PERMUTE3(b, h, f);
+-    CHUNK(42); PERMUTE3(b, h, d);
+-    CHUNK(0); PERMUTE3(b, h, e);
+-    CHUNK(33); PERMUTE3(a, h, e);
+-  } while (--iters > 0);
+-
+-  while (len >= 40) {
+-    CHUNK(29);
+-    e ^= Rotate(a, 20);
+-    h += Rotate(b, 30);
+-    g ^= Rotate(c, 40);
+-    f += Rotate(d, 34);
+-    PERMUTE3(c, h, g);
+-    len -= 40;
+-  }
+-  if (len > 0) {
+-    s = s + len - 40;
+-    CHUNK(33);
+-    e ^= Rotate(a, 43);
+-    h += Rotate(b, 42);
+-    g ^= Rotate(c, 41);
+-    f += Rotate(d, 40);
+-  }
+-  result[0] ^= h;
+-  result[1] ^= g;
+-  g += h;
+-  a = HashLen16(a, g + z);
+-  x += y << 32;
+-  b += x;
+-  c = HashLen16(c, z) + h;
+-  d = HashLen16(d, e + result[0]);
+-  g += e;
+-  h += HashLen16(x, f);
+-  e = HashLen16(a, d) + g;
+-  z = HashLen16(b, c) + a;
+-  y = HashLen16(g, h) + c;
+-  result[0] = e + z + y + x;
+-  a = ShiftMix((a + y) * k0) * k0 + b;
+-  result[1] += a + result[0];
+-  a = ShiftMix(a * k0) * k0 + c;
+-  result[2] = a + result[1];
+-  a = ShiftMix((a + e) * k0) * k0;
+-  result[3] = a + result[2];
+-}
+-
+-// Requires len < 240.
+-static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) {
+-  char buf[240];
+-  memcpy(buf, s, len);
+-  memset(buf + len, 0, 240 - len);
+-  CityHashCrc256Long(buf, 240, ~static_cast<uint32>(len), result);
+-}
+-
+-void CityHashCrc256(const char *s, size_t len, uint64 *result) {
+-  if (LIKELY(len >= 240)) {
+-    CityHashCrc256Long(s, len, 0, result);
+-  } else {
+-    CityHashCrc256Short(s, len, result);
+-  }
+-}
+-
+-uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
+-  if (len <= 900) {
+-    return CityHash128WithSeed(s, len, seed);
+-  } else {
+-    uint64 result[4];
+-    CityHashCrc256(s, len, result);
+-    uint64 u = Uint128High64(seed) + result[0];
+-    uint64 v = Uint128Low64(seed) + result[1];
+-    return uint128(HashLen16(u, v + result[2]),
+-                   HashLen16(Rotate(v, 32), u * k0 + result[3]));
+-  }
+-}
++}  // namespace cityhash_v111
++}  // namespace internal
++}  // namespace base
+ 
+-uint128 CityHashCrc128(const char *s, size_t len) {
+-  if (len <= 900) {
+-    return CityHash128(s, len);
+-  } else {
+-    uint64 result[4];
+-    CityHashCrc256(s, len, result);
+-    return uint128(result[2], result[3]);
+-  }
+-}
+-
+-#endif
+diff --git a/base/third_party/cityhash/city.h b/base/third_party/cityhash/city.h
+index 94499ce419c7..e4672f6d44da 100644
+--- a/base/third_party/cityhash/city.h
++++ b/base/third_party/cityhash/city.h
+@@ -59,13 +59,20 @@
+ // of a+b is easily derived from the hashes of a and b.  This property
+ // doesn't hold for any hash functions in this file.
+ 
+-#ifndef CITY_HASH_H_
+-#define CITY_HASH_H_
++#ifndef BASE_THIRD_PARTY_CITYHASH_CITY_H_
++#define BASE_THIRD_PARTY_CITYHASH_CITY_H_
+ 
+ #include <stdlib.h>  // for size_t.
+ #include <stdint.h>
+ #include <utility>
+ 
++// XXX(cavalcantii): Declaring it inside of the 'base' namespace allows to
++// handle linker symbol clash error with deprecated CityHash from
++// third_party/smhasher in a few unit tests.
++namespace base {
++namespace internal {
++namespace cityhash_v111 {
++
+ typedef uint8_t uint8;
+ typedef uint32_t uint32;
+ typedef uint64_t uint64;
+@@ -109,4 +116,8 @@ inline uint64 Hash128to64(const uint128& x) {
+   return b;
+ }
+ 
++}  // namespace cityhash_v111
++}  // namespace internal
++}  // namespace base
++
+ #endif  // CITY_HASH_H_
diff --git a/base/third_party/cityhash/patches/0001-format-style.patch b/base/third_party/cityhash/patches/0001-format-style.patch
new file mode 100644
index 0000000..ba29530
--- /dev/null
+++ b/base/third_party/cityhash/patches/0001-format-style.patch
@@ -0,0 +1,309 @@
+diff --git a/base/third_party/cityhash/city.cc b/base/third_party/cityhash/city.cc
+index be08dc99cf18..f0af5bbd8507 100644
+--- a/base/third_party/cityhash/city.cc
++++ b/base/third_party/cityhash/city.cc
+@@ -29,21 +29,21 @@
+ 
+ #include "city.h"
+ 
+-#include <algorithm>
+ #include <string.h>  // for memcpy and memset
++#include <algorithm>
+ 
+ namespace base {
+ namespace internal {
+ namespace cityhash_v111 {
+ using namespace std;
+ 
+-static uint64 UNALIGNED_LOAD64(const char *p) {
++static uint64 UNALIGNED_LOAD64(const char* p) {
+   uint64 result;
+   memcpy(&result, p, sizeof(result));
+   return result;
+ }
+ 
+-static uint32 UNALIGNED_LOAD32(const char *p) {
++static uint32 UNALIGNED_LOAD32(const char* p) {
+   uint32 result;
+   memcpy(&result, p, sizeof(result));
+   return result;
+@@ -82,8 +82,8 @@ static uint32 UNALIGNED_LOAD32(const char *p) {
+ 
+ #elif defined(__NetBSD__)
+ 
+-#include <sys/types.h>
+ #include <machine/bswap.h>
++#include <sys/types.h>
+ #if defined(__BSWAP_RENAME) && !defined(__bswap_32)
+ #define bswap_32(x) bswap32(x)
+ #define bswap_64(x) bswap64(x)
+@@ -116,11 +116,11 @@ static uint32 UNALIGNED_LOAD32(const char *p) {
+ #endif
+ #endif
+ 
+-static uint64 Fetch64(const char *p) {
++static uint64 Fetch64(const char* p) {
+   return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+ }
+ 
+-static uint32 Fetch32(const char *p) {
++static uint32 Fetch32(const char* p) {
+   return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+ }
+ 
+@@ -134,8 +134,7 @@ static const uint32 c1 = 0xcc9e2d51;
+ static const uint32 c2 = 0x1b873593;
+ 
+ // A 32-bit to 32-bit integer hash copied from Murmur3.
+-static uint32 fmix(uint32 h)
+-{
++static uint32 fmix(uint32 h) {
+   h ^= h >> 16;
+   h *= 0x85ebca6b;
+   h ^= h >> 13;
+@@ -150,7 +149,11 @@ static uint32 Rotate32(uint32 val, int shift) {
+ }
+ 
+ #undef PERMUTE3
+-#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)
++#define PERMUTE3(a, b, c) \
++  do {                    \
++    std::swap(a, b);      \
++    std::swap(a, c);      \
++  } while (0)
+ 
+ static uint32 Mur(uint32 a, uint32 h) {
+   // Helper from Murmur3 for combining two 32-bit values.
+@@ -162,7 +165,7 @@ static uint32 Mur(uint32 a, uint32 h) {
+   return h * 5 + 0xe6546b64;
+ }
+ 
+-static uint32 Hash32Len13to24(const char *s, size_t len) {
++static uint32 Hash32Len13to24(const char* s, size_t len) {
+   uint32 a = Fetch32(s - 4 + (len >> 1));
+   uint32 b = Fetch32(s + 4);
+   uint32 c = Fetch32(s + len - 8);
+@@ -174,7 +177,7 @@ static uint32 Hash32Len13to24(const char *s, size_t len) {
+   return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
+ }
+ 
+-static uint32 Hash32Len0to4(const char *s, size_t len) {
++static uint32 Hash32Len0to4(const char* s, size_t len) {
+   uint32 b = 0;
+   uint32 c = 9;
+   for (size_t i = 0; i < len; i++) {
+@@ -185,7 +188,7 @@ static uint32 Hash32Len0to4(const char *s, size_t len) {
+   return fmix(Mur(b, Mur(len, c)));
+ }
+ 
+-static uint32 Hash32Len5to12(const char *s, size_t len) {
++static uint32 Hash32Len5to12(const char* s, size_t len) {
+   uint32 a = len, b = len * 5, c = 9, d = b;
+   a += Fetch32(s);
+   b += Fetch32(s + len - 4);
+@@ -193,11 +196,11 @@ static uint32 Hash32Len5to12(const char *s, size_t len) {
+   return fmix(Mur(c, Mur(b, Mur(a, d))));
+ }
+ 
+-uint32 CityHash32(const char *s, size_t len) {
++uint32 CityHash32(const char* s, size_t len) {
+   if (len <= 24) {
+-    return len <= 12 ?
+-        (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) :
+-        Hash32Len13to24(s, len);
++    return len <= 12
++               ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len))
++               : Hash32Len13to24(s, len);
+   }
+ 
+   // len > 24
+@@ -287,7 +290,7 @@ static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+   return b;
+ }
+ 
+-static uint64 HashLen0to16(const char *s, size_t len) {
++static uint64 HashLen0to16(const char* s, size_t len) {
+   if (len >= 8) {
+     uint64 mul = k2 + len * 2;
+     uint64 a = Fetch64(s) + k2;
+@@ -314,7 +317,7 @@ static uint64 HashLen0to16(const char *s, size_t len) {
+ 
+ // This probably works well for 16-byte strings as well, but it may be overkill
+ // in that case.
+-static uint64 HashLen17to32(const char *s, size_t len) {
++static uint64 HashLen17to32(const char* s, size_t len) {
+   uint64 mul = k2 + len * 2;
+   uint64 a = Fetch64(s) * k1;
+   uint64 b = Fetch64(s + 8);
+@@ -326,8 +329,12 @@ static uint64 HashLen17to32(const char *s, size_t len) {
+ 
+ // Return a 16-byte hash for 48 bytes.  Quick and dirty.
+ // Callers do best to use "random-looking" values for a and b.
+-static pair<uint64, uint64> WeakHashLen32WithSeeds(
+-    uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) {
++static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w,
++                                                   uint64 x,
++                                                   uint64 y,
++                                                   uint64 z,
++                                                   uint64 a,
++                                                   uint64 b) {
+   a += w;
+   b = Rotate(b + a + z, 21);
+   uint64 c = a;
+@@ -338,18 +345,15 @@ static pair<uint64, uint64> WeakHashLen32WithSeeds(
+ }
+ 
+ // Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
+-static pair<uint64, uint64> WeakHashLen32WithSeeds(
+-    const char* s, uint64 a, uint64 b) {
+-  return WeakHashLen32WithSeeds(Fetch64(s),
+-                                Fetch64(s + 8),
+-                                Fetch64(s + 16),
+-                                Fetch64(s + 24),
+-                                a,
+-                                b);
++static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s,
++                                                   uint64 a,
++                                                   uint64 b) {
++  return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
++                                Fetch64(s + 24), a, b);
+ }
+ 
+ // Return an 8-byte hash for 33 to 64 bytes.
+-static uint64 HashLen33to64(const char *s, size_t len) {
++static uint64 HashLen33to64(const char* s, size_t len) {
+   uint64 mul = k2 + len * 2;
+   uint64 a = Fetch64(s) * k2;
+   uint64 b = Fetch64(s + 8);
+@@ -370,7 +374,7 @@ static uint64 HashLen33to64(const char *s, size_t len) {
+   return b + x;
+ }
+ 
+-uint64 CityHash64(const char *s, size_t len) {
++uint64 CityHash64(const char* s, size_t len) {
+   if (len <= 32) {
+     if (len <= 16) {
+       return HashLen0to16(s, len);
+@@ -408,18 +412,20 @@ uint64 CityHash64(const char *s, size_t len) {
+                    HashLen16(v.second, w.second) + x);
+ }
+ 
+-uint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) {
++uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
+   return CityHash64WithSeeds(s, len, k2, seed);
+ }
+ 
+-uint64 CityHash64WithSeeds(const char *s, size_t len,
+-                           uint64 seed0, uint64 seed1) {
++uint64 CityHash64WithSeeds(const char* s,
++                           size_t len,
++                           uint64 seed0,
++                           uint64 seed1) {
+   return HashLen16(CityHash64(s, len) - seed0, seed1);
+ }
+ 
+ // A subroutine for CityHash128().  Returns a decent 128-bit hash for strings
+ // of any length representable in signed long.  Based on City and Murmur.
+-static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
++static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
+   uint64 a = Uint128Low64(seed);
+   uint64 b = Uint128High64(seed);
+   uint64 c = 0;
+@@ -449,7 +455,7 @@ static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
+   return uint128(a ^ b, HashLen16(b, a));
+ }
+ 
+-uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
++uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
+   if (len < 128) {
+     return CityMurmur(s, len, seed);
+   }
+@@ -493,7 +499,7 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
+   w.first *= 9;
+   v.first *= k0;
+   // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
+-  for (size_t tail_done = 0; tail_done < len; ) {
++  for (size_t tail_done = 0; tail_done < len;) {
+     tail_done += 32;
+     y = Rotate(x + y, 42) * k0 + v.second;
+     w.first += Fetch64(s + len - tail_done + 16);
+@@ -512,14 +518,13 @@ uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
+                  HashLen16(x + w.second, y + v.second));
+ }
+ 
+-uint128 CityHash128(const char *s, size_t len) {
+-  return len >= 16 ?
+-      CityHash128WithSeed(s + 16, len - 16,
+-                          uint128(Fetch64(s), Fetch64(s + 8) + k0)) :
+-      CityHash128WithSeed(s, len, uint128(k0, k1));
++uint128 CityHash128(const char* s, size_t len) {
++  return len >= 16
++             ? CityHash128WithSeed(s + 16, len - 16,
++                                   uint128(Fetch64(s), Fetch64(s + 8) + k0))
++             : CityHash128WithSeed(s, len, uint128(k0, k1));
+ }
+ 
+ }  // namespace cityhash_v111
+ }  // namespace internal
+ }  // namespace base
+-
+diff --git a/base/third_party/cityhash/city.h b/base/third_party/cityhash/city.h
+index e4672f6d44da..3e3dcaaaa9a5 100644
+--- a/base/third_party/cityhash/city.h
++++ b/base/third_party/cityhash/city.h
+@@ -62,8 +62,8 @@
+ #ifndef BASE_THIRD_PARTY_CITYHASH_CITY_H_
+ #define BASE_THIRD_PARTY_CITYHASH_CITY_H_
+ 
+-#include <stdlib.h>  // for size_t.
+ #include <stdint.h>
++#include <stdlib.h>  // for size_t.
+ #include <utility>
+ 
+ // XXX(cavalcantii): Declaring it inside of the 'base' namespace allows to
+@@ -78,30 +78,36 @@ typedef uint32_t uint32;
+ typedef uint64_t uint64;
+ typedef std::pair<uint64, uint64> uint128;
+ 
+-inline uint64 Uint128Low64(const uint128& x) { return x.first; }
+-inline uint64 Uint128High64(const uint128& x) { return x.second; }
++inline uint64 Uint128Low64(const uint128& x) {
++  return x.first;
++}
++inline uint64 Uint128High64(const uint128& x) {
++  return x.second;
++}
+ 
+ // Hash function for a byte array.
+-uint64 CityHash64(const char *buf, size_t len);
++uint64 CityHash64(const char* buf, size_t len);
+ 
+ // Hash function for a byte array.  For convenience, a 64-bit seed is also
+ // hashed into the result.
+-uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed);
++uint64 CityHash64WithSeed(const char* buf, size_t len, uint64 seed);
+ 
+ // Hash function for a byte array.  For convenience, two seeds are also
+ // hashed into the result.
+-uint64 CityHash64WithSeeds(const char *buf, size_t len,
+-                           uint64 seed0, uint64 seed1);
++uint64 CityHash64WithSeeds(const char* buf,
++                           size_t len,
++                           uint64 seed0,
++                           uint64 seed1);
+ 
+ // Hash function for a byte array.
+-uint128 CityHash128(const char *s, size_t len);
++uint128 CityHash128(const char* s, size_t len);
+ 
+ // Hash function for a byte array.  For convenience, a 128-bit seed is also
+ // hashed into the result.
+-uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);
++uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed);
+ 
+ // Hash function for a byte array.  Most useful in 32-bit binaries.
+-uint32 CityHash32(const char *buf, size_t len);
++uint32 CityHash32(const char* buf, size_t len);
+ 
+ // Hash 128 input bits down to 64 bits of output.
+ // This is intended to be a reasonably good hash function.
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index 1d657611..78400c7 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -679,16 +679,16 @@
     # pylint:disable=no-self-use
     if dim:
       return ''
-    style = ''
+    style = colorama.Fore.BLACK
     if priority == 'E' or priority == 'F':
-      style = colorama.Back.RED
+      style += colorama.Back.RED
     elif priority == 'W':
-      style = colorama.Back.YELLOW
+      style += colorama.Back.YELLOW
     elif priority == 'I':
-      style = colorama.Back.GREEN
+      style += colorama.Back.GREEN
     elif priority == 'D':
-      style = colorama.Back.BLUE
-    return style + colorama.Fore.BLACK
+      style += colorama.Back.BLUE
+    return style
 
   def _ParseLine(self, line):
     tokens = line.split(None, 6)
@@ -715,7 +715,7 @@
         date, invokation_time, pid, tid, priority, tag, original_message)
 
   def _PrintParsedLine(self, parsed_line, dim=False):
-    tid_style = ''
+    tid_style = colorama.Style.NORMAL
     # Make the main thread bright.
     if not dim and parsed_line.pid == parsed_line.tid:
       tid_style = colorama.Style.BRIGHT
diff --git a/build/android/docs/coverage.md b/build/android/docs/coverage.md
index 14dbef6..a9fbf91 100644
--- a/build/android/docs/coverage.md
+++ b/build/android/docs/coverage.md
@@ -5,52 +5,59 @@
 
 [TOC]
 
-## How EMMA coverage works
+## How Jacoco coverage works
 
-In order to use EMMA code coverage, we need to create build time **.em** files
-and runtime **.ec** files. Then we need to process them using the
-build/android/generate_emma_html.py script.
+In order to use Jacoco code coverage, we need to create build time pre-instrumented
+files and runtime **.exec** files. Then we need to process them using the
+**build/android/generate_jacoco_report.py** script.
 
-## How to collect EMMA coverage data
+## How to collect Jacoco coverage data
 
 1. Use the following GN build arguments:
 
-```gn
-target_os = "android"
-emma_coverage = true
-emma_filter = "org.chromium.chrome.browser.ntp.*,-*Test*,-*Fake*,-*Mock*"
-```
+   ```gn
+   target_os = "android"
+   jacoco_coverage = true
+   ```
 
-The filter syntax is as documented for the [EMMA coverage
-filters](http://emma.sourceforge.net/reference/ch02s06s02.html).
-
-Now when building, **.em** files will be created in the build directory.
+Now when building, pre-instrumented files will be created in the build directory.
 
 2. Run tests, with option `--coverage-dir <directory>`, to specify where to save
-   the .ec file. For example, you can run chrome junit tests:
+   the .exec file. For example, you can run chrome junit tests:
    `out/Debug/bin/run_chrome_junit_tests --coverage-dir /tmp/coverage`.
 
-3. Turn off strict mode when running instrumentation tests by adding
-   `--strict-mode=off` because the EMMA code causes strict mode violations by
-   accessing disk.
-
-4. Use a pre-L Android OS (running Dalvik) because code coverage is not
-   supported in ART.
-
-5. The coverage results of junit and instrumentation tests will be merged
+3. The coverage results of junit and instrumentation tests will be merged
    automatically if they are in the same directory.
 
-6. Now we have both .em and .ec files. We can create a html report using
-   `generate_emma_html.py`, for example:
+4. Now we have generated .exec files already. We can create a html/xml/csv report
+   using `generate_jacoco_report.py`, for example:
 
    ```shell
-   build/android/generate_emma_html.py \
+   build/android/generate_jacoco_report.py \
+       --format html \
+       --output-dir tmp/coverage_report/ \
        --coverage-dir /tmp/coverage/ \
        --metadata-dir out/Debug/ \
-       --output example.html
    ```
-   Then an example.html containing coverage info will be created:
+   Then an index.html containing coverage info will be created in output directory:
 
    ```
-   EMMA: writing [html] report to [<your_current_directory>/example.html] ...
+   [INFO] Loading execution data file /tmp/coverage/testTitle.exec.
+   [INFO] Loading execution data file /tmp/coverage/testSelected.exec.
+   [INFO] Loading execution data file /tmp/coverage/testClickToSelect.exec.
+   [INFO] Loading execution data file /tmp/coverage/testClickToClose.exec.
+   [INFO] Loading execution data file /tmp/coverage/testThumbnail.exec.
+   [INFO] Analyzing 58 classes.
+   ```
+
+   For xml and csv reports, we need to specify `--output-file` instead of `--output-dir` since
+   only one file will be generated as xml or csv report.
+   ```
+   --format xml \
+   --output-file tmp/coverage_report/report.xml \
+   ```
+
+   ```
+   --format csv \
+   --output-file tmp/coverage_report/report.csv \
    ```
diff --git a/build/android/generate_emma_html.py b/build/android/generate_emma_html.py
deleted file mode 100755
index 6260c249d..0000000
--- a/build/android/generate_emma_html.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Aggregates EMMA coverage files to produce html output."""
-
-from __future__ import print_function
-
-import fnmatch
-import json
-import optparse
-import os
-import sys
-
-import devil_chromium
-from devil.utils import cmd_helper
-from pylib import constants
-from pylib.constants import host_paths
-
-
-def _GetFilesWithExt(root_dir, ext):
-  """Gets all files with a given extension.
-
-  Args:
-    root_dir: Directory in which to search for files.
-    ext: Extension to look for (including dot)
-
-  Returns:
-    A list of absolute paths to files that match.
-  """
-  files = []
-  for root, _, filenames in os.walk(root_dir):
-    basenames = fnmatch.filter(filenames, '*.' + ext)
-    files.extend([os.path.join(root, basename)
-                  for basename in basenames])
-
-  return files
-
-
-def main():
-  option_parser = optparse.OptionParser()
-  option_parser.add_option('--output', help='HTML output filename.')
-  option_parser.add_option('--coverage-dir', default=None,
-                           help=('Root of the directory in which to search for '
-                                 'coverage data (.ec) files.'))
-  option_parser.add_option('--metadata-dir', default=None,
-                           help=('Root of the directory in which to search for '
-                                 'coverage metadata (.em) files.'))
-  option_parser.add_option('--cleanup', action='store_true',
-                           help=('If set, removes coverage files generated at '
-                                 'runtime.'))
-  options, _ = option_parser.parse_args()
-
-  devil_chromium.Initialize()
-
-  if not (options.coverage_dir and options.metadata_dir and options.output):
-    option_parser.error('One or more mandatory options are missing.')
-
-  coverage_files = _GetFilesWithExt(options.coverage_dir, 'ec')
-  metadata_files = _GetFilesWithExt(options.metadata_dir, 'em')
-  # Filter out zero-length files. These are created by emma_instr.py when a
-  # target has no classes matching the coverage filter.
-  metadata_files = [f for f in metadata_files if os.path.getsize(f)]
-  print('Found coverage files: %s' % str(coverage_files))
-  print('Found metadata files: %s' % str(metadata_files))
-
-  sources = []
-  for f in metadata_files:
-    sources_file = os.path.splitext(f)[0] + '_sources.txt'
-    with open(sources_file, 'r') as sf:
-      sources.extend(json.load(sf))
-
-  # Source paths should be passed to EMMA in a way that the relative file paths
-  # reflect the class package name.
-  PARTIAL_PACKAGE_NAMES = ['com/google', 'org/chromium', 'com/chrome']
-  fixed_source_paths = set()
-
-  for path in sources:
-    for partial in PARTIAL_PACKAGE_NAMES:
-      if partial in path:
-        fixed_path = os.path.join(
-            host_paths.DIR_SOURCE_ROOT, path[:path.index(partial)])
-        fixed_source_paths.add(fixed_path)
-        break
-
-  sources = list(fixed_source_paths)
-
-  input_args = []
-  for f in coverage_files + metadata_files:
-    input_args.append('-in')
-    input_args.append(f)
-
-  output_args = ['-Dreport.html.out.file', options.output,
-                 '-Dreport.html.out.encoding', 'UTF-8']
-  source_args = ['-sp', ','.join(sources)]
-
-  exit_code = cmd_helper.RunCmd(
-      ['java', '-cp',
-       os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'lib', 'emma.jar'),
-       'emma', 'report', '-r', 'html']
-      + input_args + output_args + source_args)
-
-  if options.cleanup:
-    for f in coverage_files:
-      os.remove(f)
-
-  # Command tends to exit with status 0 when it actually failed.
-  if not exit_code and not os.path.exists(options.output):
-    exit_code = 1
-
-  return exit_code
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/build/android/generate_jacoco_report.py b/build/android/generate_jacoco_report.py
new file mode 100755
index 0000000..27f6e7e
--- /dev/null
+++ b/build/android/generate_jacoco_report.py
@@ -0,0 +1,184 @@
+#!/usr/bin/env python
+
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Aggregates Jacoco coverage files to produce output."""
+
+from __future__ import print_function
+
+import argparse
+import fnmatch
+import json
+import os
+import sys
+
+import devil_chromium
+from devil.utils import cmd_helper
+from pylib.constants import host_paths
+
+# Source paths should be passed to Jacoco in a way that the relative file paths
+# reflect the class package name.
+_PARTIAL_PACKAGE_NAMES = ['com/google', 'org/chromium']
+
+# The sources_json_file is generated by jacoco_instr.py with source directories
+# and input path to non-instrumented jars.
+# e.g.
+# 'source_dirs': [
+# "chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom",
+# "chrome/android/java/src/org/chromium/chrome/browser/ui/system",
+# ...]
+# 'input_path':
+#   '$CHROMIUM_OUTPUT_DIR/\
+#    obj/chrome/android/features/tab_ui/java__process_prebuilt-filtered.jar'
+_SOURCES_JSON_FILES_SUFFIX = '__jacoco_sources.json'
+
+
+def _GetFilesWithSuffix(root_dir, suffix):
+  """Gets all files with a given suffix.
+
+  Args:
+    root_dir: Directory in which to search for files.
+    suffix: Suffix to look for.
+
+  Returns:
+    A list of absolute paths to files that match.
+  """
+  files = []
+  for root, _, filenames in os.walk(root_dir):
+    basenames = fnmatch.filter(filenames, '*' + suffix)
+    files.extend([os.path.join(root, basename) for basename in basenames])
+
+  return files
+
+
+def _AddArguments(parser):
+  """Adds arguments related to parser.
+
+  Args:
+    parser: ArgumentParser object.
+  """
+  parser.add_argument(
+      '--format',
+      required=True,
+      choices=['html', 'xml', 'csv'],
+      help='Output report format. Choose one from html, xml and csv.')
+  parser.add_argument('--output-dir', help='html report output directory.')
+  parser.add_argument('--output-file', help='xml or csv report output file.')
+  parser.add_argument(
+      '--coverage-dir',
+      required=True,
+      help=('Root of the directory in which to search for '
+            'coverage data (.exec) files.'))
+  parser.add_argument(
+      '--metadata-dir',
+      help=('Root of the directory in which to search for '
+            '*-filtered.jar and *__jacoco_sources.txt files.'))
+  parser.add_argument(
+      '--class-files',
+      nargs='+',
+      help='Location of Java non-instrumented class files. '
+      'Use non-instrumented jars instead of instrumented jars. '
+      'e.g. use chrome_java__process_prebuilt-filtered.jar instead of'
+      'chrome_java__process_prebuilt-instrumented.jar')
+  parser.add_argument(
+      '--sources',
+      nargs='+',
+      help='Location of the source files. '
+      'Specified source folders must be the direct parent of the folders '
+      'that define the Java packages.'
+      'e.g. <src_dir>/chrome/android/java/src/')
+  parser.add_argument(
+      '--cleanup',
+      action='store_true',
+      help=('If set, removes coverage files generated at '
+            'runtime.'))
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  _AddArguments(parser)
+  args = parser.parse_args()
+
+  if args.format == 'html':
+    if not args.output_dir:
+      parser.error('--output-dir needed for html report.')
+  elif not args.output_file:
+    parser.error('--output-file needed for xml or csv report.')
+
+  if not (args.metadata_dir or args.class_files):
+    parser.error('At least either --metadata-dir or --class-files needed.')
+
+  devil_chromium.Initialize()
+
+  coverage_files = _GetFilesWithSuffix(args.coverage_dir, '.exec')
+  if not coverage_files:
+    parser.error('Found no coverage file under %s' % args.coverage_dir)
+  print('Found coverage files: %s' % str(coverage_files))
+
+  class_files = []
+  sources = []
+  if args.metadata_dir:
+    sources_json_files = _GetFilesWithSuffix(args.metadata_dir,
+                                             _SOURCES_JSON_FILES_SUFFIX)
+    for f in sources_json_files:
+      with open(f, 'r') as json_file:
+        data = json.load(json_file)
+        class_files.append(data['input_path'])
+        sources.extend(data['source_dirs'])
+
+  fixed_source_paths = set()
+
+  for path in sources:
+    for partial in _PARTIAL_PACKAGE_NAMES:
+      if partial in path:
+        fixed_path = os.path.join(host_paths.DIR_SOURCE_ROOT,
+                                  path[:path.index(partial)])
+        fixed_source_paths.add(fixed_path)
+        break
+
+  sources = list(fixed_source_paths)
+
+  if args.class_files:
+    class_files += args.class_files
+  if args.sources:
+    sources += args.sources
+
+  cmd = [
+      'java', '-jar',
+      os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party', 'jacoco', 'lib',
+                   'jacococli.jar'), 'report'
+  ] + coverage_files
+  for f in class_files:
+    cmd += ['--classfiles', f]
+  for source in sources:
+    cmd += ['--sourcefiles', source]
+  if args.format == 'html':
+    cmd += ['--html', args.output_dir]
+  elif args.format == 'xml':
+    cmd += ['--xml', args.output_file]
+  else:
+    cmd += ['--csv', args.output_file]
+
+  exit_code = cmd_helper.RunCmd(cmd)
+
+  if args.cleanup:
+    for f in coverage_files:
+      os.remove(f)
+
+  # Command tends to exit with status 0 when it actually failed.
+  if not exit_code:
+    if args.format == 'html':
+      if not os.path.exists(args.output_dir) or not os.listdir(args.output_dir):
+        print('No report generated at %s' % args.output_dir)
+        exit_code = 1
+    elif not os.path.exists(args.output_file):
+      print('No report generated at %s' % args.output_file)
+      exit_code = 1
+
+  return exit_code
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/jacoco_instr.py b/build/android/gyp/jacoco_instr.py
index cd37838..4deea439 100755
--- a/build/android/gyp/jacoco_instr.py
+++ b/build/android/gyp/jacoco_instr.py
@@ -34,18 +34,19 @@
   parser.add_argument(
       '--input-path',
       required=True,
-      help=('Path to input file(s). Either the classes '
-            'directory, or the path to a jar.'))
+      help='Path to input file(s). Either the classes '
+      'directory, or the path to a jar.')
   parser.add_argument(
       '--output-path',
       required=True,
-      help=('Path to output final file(s) to. Either the '
-            'final classes directory, or the directory in '
-            'which to place the instrumented/copied jar.'))
+      help='Path to output final file(s) to. Either the '
+      'final classes directory, or the directory in '
+      'which to place the instrumented/copied jar.')
   parser.add_argument(
-      '--sources-list-file',
+      '--sources-json-file',
       required=True,
-      help='File to create with the list of sources.')
+      help='File to create with the list of source directories '
+      'and input path.')
   parser.add_argument(
       '--java-sources-file',
       required=True,
@@ -66,12 +67,16 @@
   return list(set(os.path.dirname(source_file) for source_file in source_files))
 
 
-def _CreateSourcesListFile(source_dirs, sources_list_file, src_root):
-  """Adds all normalized source directories to |sources_list_file|.
+def _CreateSourcesJsonFile(source_dirs, input_path, sources_json_file,
+                           src_root):
+  """Adds all normalized source directories and input path to
+  |sources_json_file|.
 
   Args:
     source_dirs: List of source directories.
-    sources_list_file: File into which to write the JSON list of sources.
+    input_path: The input path to non-instrumented class files.
+    sources_json_file: File into which to write the list of source directories
+    and input path.
     src_root: Root which sources added to the file should be relative to.
 
   Returns:
@@ -89,8 +94,11 @@
 
     relative_sources.append(rel_source)
 
-  with open(sources_list_file, 'w') as f:
-    json.dump(relative_sources, f)
+  data = {}
+  data['source_dirs'] = relative_sources
+  data['input_path'] = os.path.abspath(input_path)
+  with open(sources_json_file, 'w') as f:
+    json.dump(data, f)
 
 
 def _RunInstrumentCommand(parser):
@@ -134,7 +142,7 @@
   # TODO(GYP): In GN, we are passed the list of sources, detecting source
   # directories, then walking them to re-establish the list of sources.
   # This can obviously be simplified!
-  _CreateSourcesListFile(source_dirs, args.sources_list_file,
+  _CreateSourcesJsonFile(source_dirs, args.input_path, args.sources_json_file,
                          build_utils.DIR_SOURCE_ROOT)
 
   return 0
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 4d7aa82..bb958140c5 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -152,7 +152,7 @@
 
     @handle_shard_failures_with(on_failure=self.BlacklistDevice)
     def prepare_device(d):
-      d.WaitUntilFullyBooted()
+      d.WaitUntilFullyBooted(timeout=120)
 
       if self._enable_device_cache:
         cache_path = _DeviceCachePath(d)
diff --git a/build/android/pylib/valgrind_tools.py b/build/android/pylib/valgrind_tools.py
index 9fdaddb7..4689dc3 100644
--- a/build/android/pylib/valgrind_tools.py
+++ b/build/android/pylib/valgrind_tools.py
@@ -6,15 +6,11 @@
 
 from __future__ import print_function
 
-import glob
 import logging
-import os.path
-import subprocess
 import sys
 
 from devil.android import device_errors
 from devil.android.valgrind_tools import base_tool
-from pylib.constants import DIR_SOURCE_ROOT
 
 
 def SetChromeTimeoutScale(device, scale):
@@ -44,19 +40,7 @@
   @classmethod
   def CopyFiles(cls, device):
     """Copies ASan tools to the device."""
-    libs = glob.glob(os.path.join(DIR_SOURCE_ROOT,
-                                  'third_party/llvm-build/Release+Asserts/',
-                                  'lib/clang/*/lib/linux/',
-                                  'libclang_rt.asan-arm-android.so'))
-    assert len(libs) == 1
-    subprocess.call(
-        [os.path.join(
-             DIR_SOURCE_ROOT,
-             'tools/android/asan/third_party/asan_device_setup.sh'),
-         '--device', str(device),
-         '--lib', libs[0],
-         '--extra-options', AddressSanitizerTool.EXTRA_OPTIONS])
-    device.WaitUntilFullyBooted()
+    del device
 
   def GetTestWrapper(self):
     return AddressSanitizerTool.WRAPPER_NAME
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index f1f0c2d6..74b531c8 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1502,7 +1502,7 @@
                                "testonly",
                              ])
 
-      _source_dirs_listing_file = "$target_out_dir/${target_name}_sources.txt"
+      _sources_json_file = "$target_out_dir/${target_name}_sources.json"
       _jacococli_jar = "//third_party/jacoco/lib/jacococli.jar"
 
       script = "//build/android/gyp/jacoco_instr.py"
@@ -1511,7 +1511,7 @@
                  invoker.input_jar_path,
                ]
       outputs = [
-        _source_dirs_listing_file,
+        _sources_json_file,
         invoker.output_jar_path,
       ]
       args = [
@@ -1519,8 +1519,8 @@
         rebase_path(invoker.input_jar_path, root_build_dir),
         "--output-path",
         rebase_path(invoker.output_jar_path, root_build_dir),
-        "--sources-list-file",
-        rebase_path(_source_dirs_listing_file, root_build_dir),
+        "--sources-json-file",
+        rebase_path(_sources_json_file, root_build_dir),
         "--java-sources-file",
         rebase_path(invoker.java_sources_file, root_build_dir),
         "--jacococli-jar",
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 7ad064a..e893d408 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8913411792119227504
\ No newline at end of file
+8913381851204518160
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 1e12f719..232a9c4 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8913411115352177952
\ No newline at end of file
+8913398683822486480
\ No newline at end of file
diff --git a/build/util/lib/common/chrome_test_server_spawner.py b/build/util/lib/common/chrome_test_server_spawner.py
index b9844aa..19b2a1b0 100644
--- a/build/util/lib/common/chrome_test_server_spawner.py
+++ b/build/util/lib/common/chrome_test_server_spawner.py
@@ -41,10 +41,9 @@
 
 
 # Path that are needed to import necessary modules when launching a testserver.
-os.environ['PYTHONPATH'] = os.environ.get('PYTHONPATH', '') + (':%s:%s:%s:%s:%s'
+os.environ['PYTHONPATH'] = os.environ.get('PYTHONPATH', '') + (':%s:%s:%s:%s'
     % (os.path.join(_DIR_SOURCE_ROOT, 'third_party'),
        os.path.join(_DIR_SOURCE_ROOT, 'third_party', 'tlslite'),
-       os.path.join(_DIR_SOURCE_ROOT, 'third_party', 'pyftpdlib', 'src'),
        os.path.join(_DIR_SOURCE_ROOT, 'net', 'tools', 'testserver'),
        os.path.join(_DIR_SOURCE_ROOT, 'components', 'sync', 'tools',
                     'testserver')))
@@ -232,11 +231,13 @@
     self._GenerateCommandLineArguments()
     command = _DIR_SOURCE_ROOT
     if self.arguments['server-type'] == 'sync':
-      command = [os.path.join(command, 'components', 'sync', 'tools',
+      command = [sys.executable,
+                 os.path.join(command, 'components', 'sync', 'tools',
                               'testserver',
                               'sync_testserver.py')] + self.command_line
     else:
-      command = [os.path.join(command, 'net', 'tools', 'testserver',
+      command = [sys.executable,
+                 os.path.join(command, 'net', 'tools', 'testserver',
                               'testserver.py')] + self.command_line
     _logger.info('Running: %s', command)
 
diff --git a/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
index 6f2da14..a1f8b53f 100644
--- a/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
+++ b/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
@@ -65,8 +65,8 @@
       image_settings->images_to_skip = {};
       image_settings->image_to_current_frame_index = {};
 
-      PlaybackImageProvider image_provider(image_decode_cache,
-                                           std::move(image_settings));
+      PlaybackImageProvider image_provider(
+          image_decode_cache, gfx::ColorSpace(), std::move(image_settings));
       RasterSource::PlaybackSettings settings;
       settings.image_provider = &image_provider;
 
diff --git a/cc/layers/recording_source_unittest.cc b/cc/layers/recording_source_unittest.cc
index dbdcaa1..34f3508 100644
--- a/cc/layers/recording_source_unittest.cc
+++ b/cc/layers/recording_source_unittest.cc
@@ -16,6 +16,10 @@
 namespace cc {
 namespace {
 
+gfx::ColorSpace DefaultColorSpace() {
+  return gfx::ColorSpace::CreateSRGB();
+}
+
 std::unique_ptr<FakeRecordingSource> CreateRecordingSource(
     const gfx::Rect& viewport) {
   gfx::Rect layer_rect(viewport.right(), viewport.bottom());
@@ -106,7 +110,8 @@
     std::vector<const DrawImage*> images;
     raster_source->GetDiscardableImagesInRect(gfx::Rect(130, 0, 128, 128),
                                               &images);
-    DrawImage image(*images[0], scale, PaintImage::kDefaultFrameIndex);
+    DrawImage image(*images[0], scale, PaintImage::kDefaultFrameIndex,
+                    DefaultColorSpace());
     EXPECT_EQ(1u, images.size());
     EXPECT_FLOAT_EQ(scale, image.scale().width());
     EXPECT_FLOAT_EQ(scale, image.scale().height());
diff --git a/cc/paint/discardable_image_map_unittest.cc b/cc/paint/discardable_image_map_unittest.cc
index 2b9eee6..8e4a073 100644
--- a/cc/paint/discardable_image_map_unittest.cc
+++ b/cc/paint/discardable_image_map_unittest.cc
@@ -56,11 +56,14 @@
       const DiscardableImageMap& image_map,
       const gfx::Rect& rect) {
     std::vector<const DrawImage*> draw_image_ptrs;
+    // Choose a not-SRGB-and-not-invalid target color space to verify that it
+    // is passed correctly to the resulting DrawImages.
+    gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
     image_map.GetDiscardableImagesInRect(rect, &draw_image_ptrs);
     std::vector<DrawImage> draw_images;
     for (const auto* image : draw_image_ptrs)
-      draw_images.push_back(
-          DrawImage(*image, 1.f, PaintImage::kDefaultFrameIndex));
+      draw_images.push_back(DrawImage(
+          *image, 1.f, PaintImage::kDefaultFrameIndex, target_color_space));
 
     std::vector<PositionScaleDrawImage> position_draw_images;
     std::vector<DrawImage> results;
@@ -77,6 +80,7 @@
     for (size_t i = 0; i < draw_images.size(); ++i) {
       EXPECT_TRUE(draw_images[i].paint_image() ==
                   position_draw_images[i].image);
+      EXPECT_EQ(draw_images[i].target_color_space(), target_color_space);
     }
     return position_draw_images;
   }
diff --git a/cc/paint/draw_image.cc b/cc/paint/draw_image.cc
index f7d5cbe..8e920f6c 100644
--- a/cc/paint/draw_image.cc
+++ b/cc/paint/draw_image.cc
@@ -40,24 +40,28 @@
                      const SkIRect& src_rect,
                      SkFilterQuality filter_quality,
                      const SkMatrix& matrix,
-                     base::Optional<size_t> frame_index)
+                     base::Optional<size_t> frame_index,
+                     const base::Optional<gfx::ColorSpace>& color_space)
     : paint_image_(std::move(image)),
       src_rect_(src_rect),
       filter_quality_(filter_quality),
-      frame_index_(frame_index) {
+      frame_index_(frame_index),
+      target_color_space_(color_space) {
   matrix_is_decomposable_ = ExtractScale(matrix, &scale_);
 }
 
 DrawImage::DrawImage(const DrawImage& other,
                      float scale_adjustment,
-                     size_t frame_index)
+                     size_t frame_index,
+                     const gfx::ColorSpace& color_space)
     : paint_image_(other.paint_image_),
       src_rect_(other.src_rect_),
       filter_quality_(other.filter_quality_),
       scale_(SkSize::Make(other.scale_.width() * scale_adjustment,
                           other.scale_.height() * scale_adjustment)),
       matrix_is_decomposable_(other.matrix_is_decomposable_),
-      frame_index_(frame_index) {}
+      frame_index_(frame_index),
+      target_color_space_(color_space) {}
 
 DrawImage::DrawImage(const DrawImage& other) = default;
 DrawImage::DrawImage(DrawImage&& other) = default;
@@ -69,7 +73,8 @@
 bool DrawImage::operator==(const DrawImage& other) const {
   return paint_image_ == other.paint_image_ && src_rect_ == other.src_rect_ &&
          filter_quality_ == other.filter_quality_ && scale_ == other.scale_ &&
-         matrix_is_decomposable_ == other.matrix_is_decomposable_;
+         matrix_is_decomposable_ == other.matrix_is_decomposable_ &&
+         target_color_space_ == other.target_color_space_;
 }
 
 }  // namespace cc
diff --git a/cc/paint/draw_image.h b/cc/paint/draw_image.h
index 6365379..c1c6957b 100644
--- a/cc/paint/draw_image.h
+++ b/cc/paint/draw_image.h
@@ -13,12 +13,13 @@
 #include "third_party/skia/include/core/SkMatrix.h"
 #include "third_party/skia/include/core/SkRect.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size_f.h"
 
 namespace cc {
 
 // A DrawImage is a logical snapshot in time and space of a PaintImage.  It
-// includes decisions about scaling, animation frame, etc.
+// includes decisions about scaling, animation frame, final colorspace, etc.
 // It has not been decoded yet.  DrawImage turns into DecodedDrawImage via
 // ImageDecodeCache::GetDecodedImageForDraw during playback.
 class CC_PAINT_EXPORT DrawImage {
@@ -29,9 +30,14 @@
             const SkIRect& src_rect,
             SkFilterQuality filter_quality,
             const SkMatrix& matrix,
-            base::Optional<size_t> frame_index = base::nullopt);
-  // Constructs a DrawImage from |other| by adjusting its scale and frame.
-  DrawImage(const DrawImage& other, float scale_adjustment, size_t frame_index);
+            base::Optional<size_t> frame_index = base::nullopt,
+            const base::Optional<gfx::ColorSpace>& color_space = base::nullopt);
+  // Constructs a DrawImage from |other| by adjusting its scale and setting a
+  // new color_space.
+  DrawImage(const DrawImage& other,
+            float scale_adjustment,
+            size_t frame_index,
+            const gfx::ColorSpace& color_space);
   DrawImage(const DrawImage& other);
   DrawImage(DrawImage&& other);
   ~DrawImage();
@@ -46,6 +52,10 @@
   const SkIRect& src_rect() const { return src_rect_; }
   SkFilterQuality filter_quality() const { return filter_quality_; }
   bool matrix_is_decomposable() const { return matrix_is_decomposable_; }
+  const gfx::ColorSpace& target_color_space() const {
+    DCHECK(target_color_space_.has_value());
+    return *target_color_space_;
+  }
   PaintImage::FrameKey frame_key() const {
     return paint_image_.GetKeyForFrame(frame_index());
   }
@@ -61,6 +71,7 @@
   SkSize scale_;
   bool matrix_is_decomposable_;
   base::Optional<size_t> frame_index_;
+  base::Optional<gfx::ColorSpace> target_color_space_;
 };
 
 }  // namespace cc
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index c1cf6f7..9af0e518 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -82,8 +82,16 @@
             /*enable_oop_rasterization=*/false, /*support_locking=*/true);
     gpu::ContextResult result = gles2_context_provider_->BindToCurrentThread();
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
-    CHECK_EQ(gles2_context_provider_->ContextCapabilities().max_texture_size,
-             raster_context_provider_->ContextCapabilities().max_texture_size);
+    const int gles2_max_texture_size =
+        gles2_context_provider_->ContextCapabilities().max_texture_size;
+    gpu_image_cache_.reset(new GpuImageDecodeCache(
+        gles2_context_provider_.get(), false, kRGBA_8888_SkColorType,
+        kWorkingSetSize, gles2_max_texture_size,
+        PaintImage::kDefaultGeneratorClientId));
+
+    const int raster_max_texture_size =
+        raster_context_provider_->ContextCapabilities().max_texture_size;
+    ASSERT_EQ(raster_max_texture_size, gles2_max_texture_size);
   }
 
   // gpu::raster::GrShaderCache::Client implementation.
@@ -100,24 +108,12 @@
             &gr_shader_cache_, &activity_flags_);
     gpu::ContextResult result = raster_context_provider_->BindToCurrentThread();
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
-  }
-
-  void CreateGpuImageCache(const gfx::ColorSpace& color_space) {
-    const int gles2_max_texture_size =
-        raster_context_provider_->ContextCapabilities().max_texture_size;
-    gpu_image_cache_.reset(new GpuImageDecodeCache(
-        gles2_context_provider_.get(), false, kRGBA_8888_SkColorType,
-        kWorkingSetSize, gles2_max_texture_size,
-        PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace()));
-  }
-
-  void CreateOopImageCache(const gfx::ColorSpace& color_space) {
     const int raster_max_texture_size =
         raster_context_provider_->ContextCapabilities().max_texture_size;
     oop_image_cache_.reset(new GpuImageDecodeCache(
         raster_context_provider_.get(), true, kRGBA_8888_SkColorType,
         kWorkingSetSize, raster_max_texture_size,
-        PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace()));
+        PaintImage::kDefaultGeneratorClientId));
   }
 
   class RasterOptions {
@@ -156,13 +152,12 @@
 
   SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list,
                   const RasterOptions& options) {
-    CreateOopImageCache(options.color_space);
-
     GURL url("https://example.com/foo");
     TestInProcessContextProvider::ScopedRasterContextLock lock(
         raster_context_provider_.get(), url.possibly_invalid_spec().c_str());
 
     PlaybackImageProvider image_provider(oop_image_cache_.get(),
+                                         options.color_space,
                                          PlaybackImageProvider::Settings());
 
     gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
@@ -263,8 +258,6 @@
   SkBitmap RasterExpectedBitmap(
       scoped_refptr<DisplayItemList> display_item_list,
       const RasterOptions& options) {
-    CreateGpuImageCache(options.color_space);
-
     TestInProcessContextProvider::ScopedRasterContextLock lock(
         gles2_context_provider_.get());
     gles2_context_provider_->GrContext()->resetContext();
@@ -286,6 +279,7 @@
       options.shader_with_animated_images->set_has_animated_images(true);
 
     PlaybackImageProvider image_provider(gpu_image_cache_.get(),
+                                         options.color_space,
                                          PlaybackImageProvider::Settings());
 
     auto raster_source = recording.CreateRasterSource();
diff --git a/cc/raster/playback_image_provider.cc b/cc/raster/playback_image_provider.cc
index 4e8cff91..cbda15c 100644
--- a/cc/raster/playback_image_provider.cc
+++ b/cc/raster/playback_image_provider.cc
@@ -19,8 +19,10 @@
 
 PlaybackImageProvider::PlaybackImageProvider(
     ImageDecodeCache* cache,
+    const gfx::ColorSpace& target_color_space,
     base::Optional<Settings>&& settings)
     : cache_(cache),
+      target_color_space_(target_color_space),
       settings_(std::move(settings)) {
   DCHECK(cache_);
 }
@@ -53,7 +55,7 @@
                            ? PaintImage::kDefaultFrameIndex
                            : it->second;
 
-  DrawImage adjusted_image(draw_image, 1.f, frame_index);
+  DrawImage adjusted_image(draw_image, 1.f, frame_index, target_color_space_);
   if (!cache_->UseCacheForDrawImage(adjusted_image)) {
     return ScopedResult(DecodedDrawImage(
         paint_image.GetSkImage(), SkSize::Make(0, 0), SkSize::Make(1.f, 1.f),
diff --git a/cc/raster/playback_image_provider.h b/cc/raster/playback_image_provider.h
index 864ec25..70991ca 100644
--- a/cc/raster/playback_image_provider.h
+++ b/cc/raster/playback_image_provider.h
@@ -37,6 +37,7 @@
 
   // If no settings are provided, all images are skipped during rasterization.
   PlaybackImageProvider(ImageDecodeCache* cache,
+                        const gfx::ColorSpace& target_color_space,
                         base::Optional<Settings>&& settings);
   PlaybackImageProvider(const PlaybackImageProvider&) = delete;
   PlaybackImageProvider(PlaybackImageProvider&& other);
@@ -51,6 +52,7 @@
 
  private:
   ImageDecodeCache* cache_;
+  gfx::ColorSpace target_color_space_;
   base::Optional<Settings> settings_;
 };
 
diff --git a/cc/raster/playback_image_provider_unittest.cc b/cc/raster/playback_image_provider_unittest.cc
index c599509..28d26f9 100644
--- a/cc/raster/playback_image_provider_unittest.cc
+++ b/cc/raster/playback_image_provider_unittest.cc
@@ -66,7 +66,7 @@
 
 TEST(PlaybackImageProviderTest, SkipsAllImages) {
   MockDecodeCache cache;
-  PlaybackImageProvider provider(&cache, base::nullopt);
+  PlaybackImageProvider provider(&cache, gfx::ColorSpace(), base::nullopt);
 
   SkIRect rect = SkIRect::MakeWH(10, 10);
   SkMatrix matrix = SkMatrix::I();
@@ -93,7 +93,8 @@
   settings.emplace();
   settings->images_to_skip = {skip_image.stable_id()};
 
-  PlaybackImageProvider provider(&cache, std::move(settings));
+  PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+                                 std::move(settings));
 
   SkIRect rect = SkIRect::MakeWH(10, 10);
   SkMatrix matrix = SkMatrix::I();
@@ -107,7 +108,8 @@
 
   base::Optional<PlaybackImageProvider::Settings> settings;
   settings.emplace();
-  PlaybackImageProvider provider(&cache, std::move(settings));
+  PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+                                 std::move(settings));
 
   {
     SkRect rect = SkRect::MakeWH(10, 10);
@@ -135,7 +137,8 @@
   settings.emplace();
   settings->image_to_current_frame_index = image_to_frame;
 
-  PlaybackImageProvider provider(&cache, std::move(settings));
+  PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+                                 std::move(settings));
 
   SkIRect rect = SkIRect::MakeWH(10, 10);
   SkMatrix matrix = SkMatrix::I();
@@ -151,7 +154,8 @@
 
   base::Optional<PlaybackImageProvider::Settings> settings;
   settings.emplace();
-  PlaybackImageProvider provider(&cache, std::move(settings));
+  PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+                                 std::move(settings));
 
   {
     SkIRect rect = SkIRect::MakeWH(10, 10);
@@ -172,7 +176,8 @@
   cache.set_use_cache_for_draw_image(false);
   base::Optional<PlaybackImageProvider::Settings> settings;
   settings.emplace();
-  PlaybackImageProvider provider(&cache, std::move(settings));
+  PlaybackImageProvider provider(&cache, gfx::ColorSpace(),
+                                 std::move(settings));
   {
     SkIRect rect = SkIRect::MakeWH(10, 10);
     SkMatrix matrix = SkMatrix::I();
diff --git a/cc/raster/raster_source_unittest.cc b/cc/raster/raster_source_unittest.cc
index 21338cf..0bd9e4fc 100644
--- a/cc/raster/raster_source_unittest.cc
+++ b/cc/raster/raster_source_unittest.cc
@@ -266,19 +266,25 @@
 
   // Tile sized iterators. These should find only one pixel ref.
   {
+    gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
     std::vector<const DrawImage*> images;
     raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), &images);
     EXPECT_EQ(1u, images.size());
-    DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex);
+    DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex,
+                    target_color_space);
     EXPECT_EQ(discardable_image[0][0], images[0]->paint_image());
+    EXPECT_EQ(target_color_space, image.target_color_space());
   }
   // Shifted tile sized iterators. These should find only one pixel ref.
   {
+    gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
     std::vector<const DrawImage*> images;
     raster->GetDiscardableImagesInRect(gfx::Rect(260, 260, 256, 256), &images);
     EXPECT_EQ(1u, images.size());
-    DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex);
+    DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex,
+                    target_color_space);
     EXPECT_EQ(discardable_image[1][1], images[0]->paint_image());
+    EXPECT_EQ(target_color_space, image.target_color_space());
   }
   // Ensure there's no discardable pixel refs in the empty cell
   {
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 5fdf97c2..f9fed94 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -933,17 +933,6 @@
     return true;
   }
 
-  // We shouldn't be handling missed frames in the browser process (i.e. where
-  // commit_to_active_tree is set) since we don't know if we should create a
-  // frame at this time. Doing so leads to issues like crbug.com/882907. This
-  // early-out is a short term fix to keep fling animations smooth.
-  // TODO(bokan): In the long term, the display compositor should decide
-  // whether to issue a missed frame; it is tracked in
-  // https://crbug.com/930890.
-  if (args.type == viz::BeginFrameArgs::MISSED &&
-      settings_.commit_to_active_tree)
-    return true;
-
   return false;
 }
 
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 35c81fd..2f5deee 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -639,26 +639,6 @@
   EXPECT_FALSE(scheduler_->begin_frames_expected());
 }
 
-// As a short term fix for https://crbug.com/882907, we should skip MISSED
-// frames from the browser compositor.
-// TODO(bokan): In the long term, the display compositor should decide
-// whether to issue a missed frame; it is tracked in
-// https://crbug.com/930890.
-TEST_F(SchedulerTest, BrowserCompositorSkipsMissedBeginFrames) {
-  scheduler_settings_.commit_to_active_tree = true;
-  SetUpScheduler(EXTERNAL_BFS);
-  scheduler_->SetNeedsBeginMainFrame();
-
-  task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
-  viz::BeginFrameArgs args =
-      fake_external_begin_frame_source_->CreateBeginFrameArgs(
-          BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
-  args.type = viz::BeginFrameArgs::MISSED;
-
-  fake_external_begin_frame_source_->TestOnBeginFrame(args);
-  EXPECT_FALSE(client_->IsInsideBeginImplFrame());
-}
-
 TEST_F(SchedulerTest, RequestCommit) {
   SetUpScheduler(EXTERNAL_BFS);
 
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index c82d7bcc..9532c7f 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -43,8 +43,7 @@
       image_decode_cache_(
           kN32_SkColorType,
           LayerTreeSettings().decoded_image_working_set_budget_bytes,
-          PaintImage::kDefaultGeneratorClientId,
-          nullptr) {
+          PaintImage::kDefaultGeneratorClientId) {
   SetResources(resource_pool, &image_decode_cache_, GetGlobalTaskGraphRunner(),
                GetGlobalRasterBufferProvider(),
                false /* use_gpu_rasterization */);
diff --git a/cc/tiles/checker_image_tracker.cc b/cc/tiles/checker_image_tracker.cc
index 2308d922..6eda401d 100644
--- a/cc/tiles/checker_image_tracker.cc
+++ b/cc/tiles/checker_image_tracker.cc
@@ -387,6 +387,7 @@
       std::max(decode_state->scale.fHeight, draw_image.scale().fHeight));
   decode_state->filter_quality =
       std::max(decode_state->filter_quality, draw_image.filter_quality());
+  decode_state->color_space = draw_image.target_color_space();
   decode_state->frame_index = draw_image.frame_index();
 }
 
@@ -426,7 +427,7 @@
         it->second.filter_quality,
         SkMatrix::MakeScale(it->second.scale.width(),
                             it->second.scale.height()),
-        it->second.frame_index);
+        it->second.frame_index, it->second.color_space);
     outstanding_image_decode_.emplace(candidate);
     break;
   }
diff --git a/cc/tiles/checker_image_tracker.h b/cc/tiles/checker_image_tracker.h
index f59f5a27..ee5578f 100644
--- a/cc/tiles/checker_image_tracker.h
+++ b/cc/tiles/checker_image_tracker.h
@@ -139,6 +139,7 @@
     DecodePolicy policy = DecodePolicy::SYNC;
     SkFilterQuality filter_quality = kNone_SkFilterQuality;
     SkSize scale = SkSize::MakeEmpty();
+    gfx::ColorSpace color_space;
     size_t frame_index = PaintImage::kDefaultFrameIndex;
   };
 
diff --git a/cc/tiles/checker_image_tracker_unittest.cc b/cc/tiles/checker_image_tracker_unittest.cc
index 44cba67..47dc8ab1 100644
--- a/cc/tiles/checker_image_tracker_unittest.cc
+++ b/cc/tiles/checker_image_tracker_unittest.cc
@@ -125,7 +125,7 @@
                          .TakePaintImage(),
                      SkIRect::MakeWH(dimension, dimension),
                      kNone_SkFilterQuality, SkMatrix::I(),
-                     PaintImage::kDefaultFrameIndex);
+                     PaintImage::kDefaultFrameIndex, gfx::ColorSpace());
   }
 
   bool ShouldCheckerImage(const DrawImage& draw_image, WhichTree tree) {
@@ -433,7 +433,8 @@
           .set_paint_image_generator(CreatePaintImageGenerator(image_size))
           .TakePaintImage(),
       SkIRect::MakeWH(image_size.width(), image_size.height()),
-      kNone_SkFilterQuality, SkMatrix::I(), PaintImage::kDefaultFrameIndex);
+      kNone_SkFilterQuality, SkMatrix::I(), PaintImage::kDefaultFrameIndex,
+      gfx::ColorSpace());
   EXPECT_FALSE(
       ShouldCheckerImage(completed_paint_image, WhichTree::PENDING_TREE));
 }
@@ -460,10 +461,12 @@
   SetUpTracker(true);
 
   DrawImage image = CreateImage(ImageType::CHECKERABLE);
-  DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex);
+  DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex,
+                          gfx::ColorSpace());
   DrawImage scaled_image2 =
       DrawImage(image.paint_image(), image.src_rect(), kHigh_SkFilterQuality,
-                SkMatrix::MakeScale(1.8f), PaintImage::kDefaultFrameIndex);
+                SkMatrix::MakeScale(1.8f), PaintImage::kDefaultFrameIndex,
+                gfx::ColorSpace());
 
   std::vector<DrawImage> draw_images = {scaled_image1, scaled_image2};
   CheckerImageTracker::ImageDecodeQueue image_decode_queue =
@@ -538,7 +541,7 @@
   DrawImage image = CreateImage(ImageType::CHECKERABLE);
   image = DrawImage(image.paint_image(), SkIRect::MakeWH(200, 200),
                     image.filter_quality(), SkMatrix::I(),
-                    PaintImage::kDefaultFrameIndex);
+                    PaintImage::kDefaultFrameIndex, image.target_color_space());
   EXPECT_FALSE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
 }
 
diff --git a/cc/tiles/decoded_image_tracker.cc b/cc/tiles/decoded_image_tracker.cc
index 197b749..5db3f19 100644
--- a/cc/tiles/decoded_image_tracker.cc
+++ b/cc/tiles/decoded_image_tracker.cc
@@ -39,6 +39,7 @@
 
 void DecodedImageTracker::QueueImageDecode(
     const PaintImage& image,
+    const gfx::ColorSpace& target_color_space,
     base::OnceCallback<void(bool)> callback) {
   size_t frame_index = PaintImage::kDefaultFrameIndex;
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
@@ -49,7 +50,7 @@
   // our own.
   auto image_bounds = SkIRect::MakeWH(image.width(), image.height());
   DrawImage draw_image(image, image_bounds, kNone_SkFilterQuality,
-                       SkMatrix::I(), frame_index);
+                       SkMatrix::I(), frame_index, target_color_space);
   image_controller_->QueueImageDecode(
       draw_image, base::BindOnce(&DecodedImageTracker::ImageDecodeFinished,
                                  base::Unretained(this), std::move(callback),
diff --git a/cc/tiles/decoded_image_tracker.h b/cc/tiles/decoded_image_tracker.h
index a5f99ab..4803dfa 100644
--- a/cc/tiles/decoded_image_tracker.h
+++ b/cc/tiles/decoded_image_tracker.h
@@ -38,6 +38,7 @@
   // completion. The callback takes a bool indicating whether the decode was
   // successful or not.
   void QueueImageDecode(const PaintImage& image,
+                        const gfx::ColorSpace& target_color_space,
                         base::OnceCallback<void(bool)> callback);
 
   // Unlock all locked images - used to respond to memory pressure or
diff --git a/cc/tiles/decoded_image_tracker_unittest.cc b/cc/tiles/decoded_image_tracker_unittest.cc
index e481894..8ffb481 100644
--- a/cc/tiles/decoded_image_tracker_unittest.cc
+++ b/cc/tiles/decoded_image_tracker_unittest.cc
@@ -86,18 +86,44 @@
 TEST_F(DecodedImageTrackerTest, QueueImageLocksImages) {
   bool locked = false;
   decoded_image_tracker()->QueueImageDecode(
-      CreateDiscardablePaintImage(gfx::Size(1, 1)),
+      CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
   EXPECT_EQ(1u, image_controller()->num_locked_images());
 }
 
+TEST_F(DecodedImageTrackerTest, Colorspace) {
+  bool locked = false;
+  gfx::ColorSpace decoded_color_space(
+      gfx::ColorSpace::PrimaryID::XYZ_D50,
+      gfx::ColorSpace::TransferID::IEC61966_2_1);
+  gfx::ColorSpace srgb_color_space = gfx::ColorSpace::CreateSRGB();
+  auto paint_image = CreateDiscardablePaintImage(gfx::Size(1, 1));
+  decoded_image_tracker()->QueueImageDecode(
+      paint_image, decoded_color_space,
+      base::BindOnce([](bool* locked, bool success) { *locked = true; },
+                     base::Unretained(&locked)));
+
+  // Check that the decoded color space images are locked, but if the color
+  // space differs then that image is not locked. Note that we use the high
+  // filter quality here, since it shouldn't matter and the checks should
+  // succeed anyway.
+  DrawImage locked_draw_image(
+      paint_image, SkIRect::MakeWH(1, 1), kHigh_SkFilterQuality, SkMatrix::I(),
+      PaintImage::kDefaultFrameIndex, decoded_color_space);
+  EXPECT_TRUE(image_controller()->IsDrawImageLocked(locked_draw_image));
+  DrawImage srgb_draw_image(paint_image, SkIRect::MakeWH(1, 1),
+                            kHigh_SkFilterQuality, SkMatrix::I(),
+                            PaintImage::kDefaultFrameIndex, srgb_color_space);
+  EXPECT_FALSE(image_controller()->IsDrawImageLocked(srgb_draw_image));
+}
+
 TEST_F(DecodedImageTrackerTest, ImagesTimeOut) {
   // Add an image, this will start a 250ms timeout to release it.
   bool locked = false;
   decoded_image_tracker()->QueueImageDecode(
-      CreateDiscardablePaintImage(gfx::Size(1, 1)),
+      CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
@@ -109,7 +135,7 @@
 
   // Add an image, this will not start a new timeout, as one is pending.
   decoded_image_tracker()->QueueImageDecode(
-      CreateDiscardablePaintImage(gfx::Size(1, 1)),
+      CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
@@ -130,7 +156,7 @@
   bool locked = false;
   auto paint_image_1 = CreateDiscardablePaintImage(gfx::Size(1, 1));
   decoded_image_tracker()->QueueImageDecode(
-      paint_image_1,
+      paint_image_1, gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
@@ -138,7 +164,7 @@
 
   auto paint_image_2 = CreateDiscardablePaintImage(gfx::Size(1, 1));
   decoded_image_tracker()->QueueImageDecode(
-      paint_image_2,
+      paint_image_2, gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
@@ -146,9 +172,11 @@
 
   // Create dummy draw images for each:
   DrawImage draw_image_1(paint_image_1, SkIRect::MakeWH(1, 1),
-                         kHigh_SkFilterQuality, SkMatrix::I(), 0);
+                         kHigh_SkFilterQuality, SkMatrix::I(), 0,
+                         gfx::ColorSpace());
   DrawImage draw_image_2(paint_image_2, SkIRect::MakeWH(1, 1),
-                         kHigh_SkFilterQuality, SkMatrix::I(), 0);
+                         kHigh_SkFilterQuality, SkMatrix::I(), 0,
+                         gfx::ColorSpace());
 
   // Both should be in the cache:
   EXPECT_TRUE(image_controller()->IsDrawImageLocked(draw_image_1));
@@ -166,13 +194,13 @@
   // Insert two images:
   bool locked = false;
   decoded_image_tracker()->QueueImageDecode(
-      CreateDiscardablePaintImage(gfx::Size(1, 1)),
+      CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
   EXPECT_EQ(1u, image_controller()->num_locked_images());
   decoded_image_tracker()->QueueImageDecode(
-      CreateDiscardablePaintImage(gfx::Size(1, 1)),
+      CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
                      base::Unretained(&locked)));
   EXPECT_TRUE(locked);
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 8cbdc23..70596745 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -437,20 +437,24 @@
 GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image)
     : frame_key(draw_image.frame_key()),
       upload_scale_mip_level(CalculateUploadScaleMipLevel(draw_image)),
-      filter_quality(CalculateDesiredFilterQuality(draw_image)) {}
+      filter_quality(CalculateDesiredFilterQuality(draw_image)),
+      target_color_space(draw_image.target_color_space()) {}
 
 bool GpuImageDecodeCache::InUseCacheKey::operator==(
     const InUseCacheKey& other) const {
   return frame_key == other.frame_key &&
          upload_scale_mip_level == other.upload_scale_mip_level &&
-         filter_quality == other.filter_quality;
+         filter_quality == other.filter_quality &&
+         target_color_space == other.target_color_space;
 }
 
 size_t GpuImageDecodeCache::InUseCacheKeyHash::operator()(
     const InUseCacheKey& cache_key) const {
-  return base::HashInts(cache_key.frame_key.hash(),
-                        base::HashInts(cache_key.upload_scale_mip_level,
-                                       cache_key.filter_quality));
+  return base::HashInts(
+      cache_key.target_color_space.GetHash(),
+      base::HashInts(cache_key.frame_key.hash(),
+                     base::HashInts(cache_key.upload_scale_mip_level,
+                                    cache_key.filter_quality)));
 }
 
 GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry(
@@ -773,17 +777,20 @@
                         usage_stats_.first_lock_wasted);
 }
 
-GpuImageDecodeCache::ImageData::ImageData(PaintImage::Id paint_image_id,
-                                          DecodedDataMode mode,
-                                          size_t size,
-                                          SkFilterQuality quality,
-                                          int upload_scale_mip_level,
-                                          bool needs_mips,
-                                          bool is_bitmap_backed,
-                                          bool is_yuv_format)
+GpuImageDecodeCache::ImageData::ImageData(
+    PaintImage::Id paint_image_id,
+    DecodedDataMode mode,
+    size_t size,
+    const gfx::ColorSpace& target_color_space,
+    SkFilterQuality quality,
+    int upload_scale_mip_level,
+    bool needs_mips,
+    bool is_bitmap_backed,
+    bool is_yuv_format)
     : paint_image_id(paint_image_id),
       mode(mode),
       size(size),
+      target_color_space(target_color_space),
       quality(quality),
       upload_scale_mip_level(upload_scale_mip_level),
       needs_mips(needs_mips),
@@ -853,8 +860,7 @@
     SkColorType color_type,
     size_t max_working_set_bytes,
     int max_texture_size,
-    PaintImage::GeneratorClientId generator_client_id,
-    sk_sp<SkColorSpace> target_color_space)
+    PaintImage::GeneratorClientId generator_client_id)
     : color_type_(color_type),
       use_transfer_cache_(use_transfer_cache),
       context_(context),
@@ -862,8 +868,7 @@
       generator_client_id_(generator_client_id),
       persistent_cache_(PersistentCache::NO_AUTO_EVICT),
       max_working_set_bytes_(max_working_set_bytes),
-      max_working_set_items_(kMaxItemsInWorkingSet),
-      target_color_space_(std::move(target_color_space)) {
+      max_working_set_items_(kMaxItemsInWorkingSet) {
   // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
   // Don't register a dump provider in these cases.
   if (base::ThreadTaskRunnerHandle::IsSet()) {
@@ -1791,7 +1796,10 @@
 
   image_data->decode.mark_used();
   sk_sp<SkColorSpace> color_space =
-      SupportsColorSpaceConversion() ? target_color_space_ : nullptr;
+      SupportsColorSpaceConversion() &&
+              draw_image.target_color_space().IsValid()
+          ? draw_image.target_color_space().ToSkColorSpace()
+          : nullptr;
   // The value of |decoded_target_colorspace| takes into account the fact
   // that we might need to ignore an embedded image color space if |color_type_|
   // does not support color space conversions or that color conversion might
@@ -1874,7 +1882,7 @@
       uploaded_image = CreateImageFromYUVATexturesInternal(
           uploaded_y_image.get(), uploaded_u_image.get(),
           uploaded_v_image.get(), image_width, image_height, &yuva_color_space,
-          decoded_target_colorspace);
+          color_space, decoded_target_colorspace);
     }
 
     // At-raster may have decoded this while we were unlocked. If so, ignore our
@@ -2032,6 +2040,7 @@
 
   return base::WrapRefCounted(new ImageData(
       draw_image.paint_image().stable_id(), mode, data_size,
+      draw_image.target_color_space(),
       CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level,
       needs_mips, is_bitmap_backed, is_yuv));
 }
@@ -2322,6 +2331,10 @@
                              image_data->upload_scale_mip_level;
   bool quality_is_compatible =
       CalculateDesiredFilterQuality(draw_image) <= image_data->quality;
+  bool color_is_compatible =
+      image_data->target_color_space == draw_image.target_color_space();
+  if (!color_is_compatible)
+    return false;
   if (is_scaled && (!scale_is_compatible || !quality_is_compatible))
     return false;
   return true;
@@ -2423,7 +2436,7 @@
     return nullptr;
 
   if (mode == DecodedDataMode::kCpu)
-    return target_color_space_;
+    return image.target_color_space().ToSkColorSpace();
 
   // For kGpu or kTransferCache images color conversion is handled during
   // upload, so keep the original colorspace here.
@@ -2443,6 +2456,7 @@
     const size_t image_width,
     const size_t image_height,
     const SkYUVColorSpace* yuva_color_space,
+    sk_sp<SkColorSpace> target_color_space,
     sk_sp<SkColorSpace> decoded_color_space) const {
   DCHECK(uploaded_y_image);
   DCHECK(uploaded_u_image);
@@ -2460,8 +2474,6 @@
   indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
   indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR};
 
-  sk_sp<SkColorSpace> target_color_space =
-      SupportsColorSpaceConversion() ? target_color_space_ : nullptr;
   if (target_color_space && SkColorSpace::Equals(target_color_space.get(),
                                                  decoded_color_space.get())) {
     target_color_space = nullptr;
@@ -2551,13 +2563,18 @@
     SkYUVColorSpace yuva_color_space = SkYUVColorSpace::kRec601_SkYUVColorSpace;
     size_t width = image_y_with_mips_owned->width();
     size_t height = image_y_with_mips_owned->height();
+    sk_sp<SkColorSpace> color_space =
+        SupportsColorSpaceConversion() &&
+                draw_image.target_color_space().IsValid()
+            ? draw_image.target_color_space().ToSkColorSpace()
+            : nullptr;
     sk_sp<SkColorSpace> decoded_color_space =
         ColorSpaceForImageDecode(draw_image, image_data->mode);
     sk_sp<SkImage> yuv_image_with_mips_owned =
         CreateImageFromYUVATexturesInternal(
             image_y_with_mips_owned.get(), image_u_with_mips_owned.get(),
             image_v_with_mips_owned.get(), width, height, &yuva_color_space,
-            decoded_color_space);
+            color_space, decoded_color_space);
     // In case of lost context
     if (!yuv_image_with_mips_owned) {
       DLOG(WARNING) << "TODO(crbug.com/740737): Context was lost. Early out.";
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index 3c3ff525..b47df03c 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -108,8 +108,7 @@
                                SkColorType color_type,
                                size_t max_working_set_bytes,
                                int max_texture_size,
-                               PaintImage::GeneratorClientId client_id,
-                               sk_sp<SkColorSpace> target_color_space);
+                               PaintImage::GeneratorClientId client_id);
   ~GpuImageDecodeCache() override;
 
   // Returns the GL texture ID backing the given SkImage.
@@ -443,6 +442,7 @@
     ImageData(PaintImage::Id paint_image_id,
               DecodedDataMode mode,
               size_t size,
+              const gfx::ColorSpace& target_color_space,
               SkFilterQuality quality,
               int upload_scale_mip_level,
               bool needs_mips,
@@ -456,6 +456,7 @@
     const PaintImage::Id paint_image_id;
     const DecodedDataMode mode;
     const size_t size;
+    gfx::ColorSpace target_color_space;
     SkFilterQuality quality;
     int upload_scale_mip_level;
     bool needs_mips = false;
@@ -501,6 +502,7 @@
     PaintImage::FrameKey frame_key;
     int upload_scale_mip_level;
     SkFilterQuality filter_quality;
+    gfx::ColorSpace target_color_space;
   };
   struct InUseCacheKeyHash {
     size_t operator()(const InUseCacheKey&) const;
@@ -551,6 +553,7 @@
       const size_t image_width,
       const size_t image_height,
       const SkYUVColorSpace* yuva_color_space,
+      sk_sp<SkColorSpace> target_color_space,
       sk_sp<SkColorSpace> decoded_color_space) const;
 
   scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData(
@@ -658,7 +661,6 @@
   // Images that are backed by planar textures must be handled differently
   // to avoid inadvertently flattening to RGB and creating additional textures.
   std::vector<sk_sp<SkImage>> yuv_images_pending_deletion_;
-  const sk_sp<SkColorSpace> target_color_space_;
 
   std::vector<uint32_t> ids_pending_unlock_;
   std::vector<uint32_t> ids_pending_deletion_;
diff --git a/cc/tiles/gpu_image_decode_cache_perftest.cc b/cc/tiles/gpu_image_decode_cache_perftest.cc
index f7d485e..a3b7e866 100644
--- a/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -47,20 +47,19 @@
                kTimeCheckInterval),
         context_provider_(base::MakeRefCounted<TestInProcessContextProvider>(
             UseTransferCache(),
-            false /* support_locking */)) {
+            false /* support_locking */)),
+        cache_(context_provider_.get(),
+               UseTransferCache(),
+               kRGBA_8888_SkColorType,
+               kCacheSize,
+               MaxTextureSize(),
+               PaintImage::kDefaultGeneratorClientId) {
     // Initializing context here is ok because image decode cache does not use
     // context provider in its constructor.
     gpu::ContextResult result = context_provider_->BindToCurrentThread();
     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
   }
 
-  void CreateCache(sk_sp<SkColorSpace> color_space = nullptr) {
-    cache_ = std::make_unique<GpuImageDecodeCache>(
-        context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType,
-        kCacheSize, MaxTextureSize(), PaintImage::kDefaultGeneratorClientId,
-        std::move(color_space));
-  }
-
  protected:
   size_t MaxTextureSize() const {
     switch (GetParam()) {
@@ -89,7 +88,7 @@
 
   base::LapTimer timer_;
   scoped_refptr<TestInProcessContextProvider> context_provider_;
-  std::unique_ptr<GpuImageDecodeCache> cache_;
+  GpuImageDecodeCache cache_;
 };
 
 INSTANTIATE_TEST_SUITE_P(P,
@@ -99,7 +98,6 @@
                                          TestMode::kSw));
 
 TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) {
-  CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace());
   timer_.Reset();
   do {
     DrawImage image(
@@ -108,10 +106,11 @@
             .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
             .TakePaintImage(),
         SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
-        CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u);
+        CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
+        gfx::ColorSpace::CreateXYZD50());
 
-    DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
-    cache_->DrawWithImageFinished(image, decoded_image);
+    DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+    cache_.DrawWithImageFinished(image, decoded_image);
     timer_.NextLap();
   } while (!timer_.HasTimeLimitExpired());
 
@@ -132,7 +131,6 @@
       context_provider_->GrContext(), SkBudgeted::kNo,
       SkImageInfo::MakeN32Premul(2048, 2048));
 
-  CreateCache();
   timer_.Reset();
   do {
     DrawImage image(
@@ -141,9 +139,9 @@
             .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
             .TakePaintImage(),
         SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
-        CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u);
+        CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u, gfx::ColorSpace());
 
-    DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
+    DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
 
     if (GetParam() == TestMode::kGpu) {
       SkPaint paint;
@@ -154,7 +152,7 @@
       surface->flush();
     }
 
-    cache_->DrawWithImageFinished(image, decoded_image);
+    cache_.DrawWithImageFinished(image, decoded_image);
     timer_.NextLap();
   } while (!timer_.HasTimeLimitExpired());
 
@@ -164,21 +162,21 @@
 
 TEST_P(GpuImageDecodeCachePerfTest, AcquireExistingImages) {
   timer_.Reset();
-  CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace());
   DrawImage image(
       PaintImageBuilder::WithDefault()
           .set_id(PaintImage::GetNextId())
           .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
           .TakePaintImage(),
       SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
-      CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u);
+      CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
+      gfx::ColorSpace::CreateXYZD50());
 
-  DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
-  cache_->DrawWithImageFinished(image, decoded_image);
+  DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+  cache_.DrawWithImageFinished(image, decoded_image);
 
   do {
-    DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
-    cache_->DrawWithImageFinished(image, decoded_image);
+    DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image);
+    cache_.DrawWithImageFinished(image, decoded_image);
     timer_.NextLap();
   } while (!timer_.HasTimeLimitExpired());
 
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index 087f8b26..77f3210c 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -283,15 +283,10 @@
   }
 
   std::unique_ptr<GpuImageDecodeCache> CreateCache() {
-    return CreateCache(DefaultColorSpace());
-  }
-
-  std::unique_ptr<GpuImageDecodeCache> CreateCache(
-      const gfx::ColorSpace& color_space) {
     return std::make_unique<GpuImageDecodeCache>(
         context_provider_.get(), use_transfer_cache_, color_type_,
         kGpuMemoryLimitBytes, max_texture_size_,
-        PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace());
+        PaintImage::kDefaultGeneratorClientId);
   }
 
   // Returns dimensions for an image that will not fit in GPU memory and hence
@@ -446,7 +441,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -455,7 +450,7 @@
   DrawImage another_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(another_result.need_unref);
@@ -477,7 +472,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -490,7 +485,7 @@
   DrawImage another_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo());
 
@@ -518,7 +513,7 @@
 
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kHigh_SkFilterQuality, matrix,
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -526,7 +521,8 @@
 
   DrawImage another_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()),
-      kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+      kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
+      DefaultColorSpace());
   ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(another_result.need_unref);
@@ -548,7 +544,7 @@
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -559,7 +555,7 @@
       second_image,
       SkIRect::MakeWH(second_image.width(), second_image.height()), quality,
       CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -584,7 +580,7 @@
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -598,7 +594,7 @@
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -608,7 +604,7 @@
   DrawImage third_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
       third_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(third_result.need_unref);
@@ -630,7 +626,7 @@
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -639,7 +635,7 @@
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -649,7 +645,7 @@
   DrawImage third_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
       third_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(third_result.need_unref);
@@ -673,7 +669,8 @@
   PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
-      kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+      kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
+      DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -686,7 +683,8 @@
 
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
-      kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+      kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
+      DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -707,7 +705,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -749,7 +747,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -791,7 +789,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -822,7 +820,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -865,7 +863,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -912,7 +910,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -941,7 +939,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -971,7 +969,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1005,7 +1003,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1041,7 +1039,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1075,7 +1073,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1087,7 +1085,7 @@
   DrawImage larger_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef(
       larger_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(larger_result.need_unref);
@@ -1129,7 +1127,7 @@
   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality, matrix,
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1140,7 +1138,8 @@
 
   DrawImage higher_quality_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()),
-      kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+      kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
+      DefaultColorSpace());
   ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef(
       higher_quality_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(hq_result.need_unref);
@@ -1182,7 +1181,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1221,7 +1220,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1264,7 +1263,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1307,7 +1306,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
@@ -1345,7 +1344,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
@@ -1382,7 +1381,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1410,7 +1409,7 @@
                                          image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1436,7 +1435,7 @@
   DrawImage draw_image(
       image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1462,7 +1461,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   {
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
@@ -1524,7 +1523,7 @@
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -1539,7 +1538,7 @@
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -1572,7 +1571,7 @@
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -1591,7 +1590,7 @@
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -1615,9 +1614,10 @@
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
 
   // Create an image with kLow_FilterQuality.
-  DrawImage low_draw_image(
-      image, SkIRect::MakeWH(image.width(), image.height()),
-      kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+  DrawImage low_draw_image(image,
+                           SkIRect::MakeWH(image.width(), image.height()),
+                           kLow_SkFilterQuality, matrix,
+                           PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef(
       low_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(low_result.need_unref);
@@ -1627,7 +1627,8 @@
   // should get a new task/ref.
   DrawImage medium_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()),
-      kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+      kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
+      DefaultColorSpace());
   ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef(
       medium_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(medium_result.need_unref);
@@ -1637,7 +1638,8 @@
   // Get the same image at kHigh_FilterQuality. We should re-use medium.
   DrawImage high_quality_draw_image(
       image, SkIRect::MakeWH(image.width(), image.height()),
-      kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex);
+      kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex,
+      DefaultColorSpace());
   ImageDecodeCache::TaskResult high_quality_result =
       cache->GetTaskForImageAndRef(high_quality_draw_image,
                                    ImageDecodeCache::TracingInfo());
@@ -1666,7 +1668,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1688,7 +1690,7 @@
   DrawImage draw_image_mips(
       image, SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_draw_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips));
   cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image);
@@ -1702,7 +1704,7 @@
   SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable);
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality, matrix,
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
@@ -1730,7 +1732,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1781,13 +1783,13 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize());
   DrawImage draw_image2(
       image2, SkIRect::MakeWH(image2.width(), image2.height()), quality,
       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // Add an image to the cache and un-ref it.
   {
@@ -1864,7 +1866,7 @@
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), quality,
         CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -1894,7 +1896,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1919,16 +1921,64 @@
   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
 }
 
-TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImage) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
   auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
+  gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB();
+  gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50();
+
+  PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
+  DrawImage first_draw_image(
+      first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
+      quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, color_space_a);
+  ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
+      first_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(first_result.need_unref);
+  EXPECT_TRUE(first_result.task);
+
+  DrawImage second_draw_image(
+      first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
+      quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, color_space_b);
+  ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
+      second_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(second_result.need_unref);
+  EXPECT_TRUE(second_result.task);
+  EXPECT_TRUE(first_result.task.get() != second_result.task.get());
+
+  DrawImage third_draw_image(
+      first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
+      quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, color_space_a);
+  ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
+      third_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(third_result.need_unref);
+  EXPECT_TRUE(third_result.task.get() == first_result.task.get());
+
+  TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
+  TestTileTaskRunner::ProcessTask(first_result.task.get());
+  TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
+  TestTileTaskRunner::ProcessTask(second_result.task.get());
+
+  cache->UnrefImage(first_draw_image);
+  cache->UnrefImage(second_draw_image);
+  cache->UnrefImage(third_draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) {
+  auto cache = CreateCache();
+  bool is_decomposable = true;
+  SkFilterQuality quality = kHigh_SkFilterQuality;
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
+
   PaintImage image = CreateLargePaintImageForSoftwareFallback();
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, color_space);
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1966,9 +2016,10 @@
 
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
-  DrawImage draw_image(
-      image, SkIRect::MakeWH(image.width(), image.height()), quality,
-      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 1u);
+  DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+                       quality,
+                       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+                       1u, DefaultColorSpace());
   auto decoded_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
   ASSERT_TRUE(decoded_image.image());
@@ -1978,7 +2029,8 @@
   cache->DrawWithImageFinished(draw_image, decoded_image);
 
   // Scaled.
-  DrawImage scaled_draw_image(draw_image, 0.5f, 2u);
+  DrawImage scaled_draw_image(draw_image, 0.5f, 2u,
+                              draw_image.target_color_space());
   decoded_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(scaled_draw_image));
   ASSERT_TRUE(decoded_image.image());
@@ -1994,7 +2046,8 @@
   ASSERT_LT(subset_height, test_image_size.height());
   DrawImage subset_draw_image(
       image, SkIRect::MakeWH(subset_width, subset_height), quality,
-      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u);
+      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u,
+      DefaultColorSpace());
   decoded_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image));
   ASSERT_TRUE(decoded_image.image());
@@ -2014,7 +2067,7 @@
   DrawImage first_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -2028,7 +2081,7 @@
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -2069,7 +2122,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   const size_t bytes_for_test_image =
       GetBytesNeededForSingleImage(test_image_size);
 
@@ -2116,7 +2169,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // The image counts against our budget.
   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
@@ -2130,7 +2183,7 @@
       CreatePaintImageInternal(GetNormalImageSize()),
       SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // Should be at raster.
   ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
@@ -2157,7 +2210,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   const size_t bytes_for_test_image =
       GetBytesNeededForSingleImage(test_image_size);
@@ -2179,7 +2232,7 @@
       CreatePaintImageInternal(test_image_size),
       SkIRect::MakeWH(image.width(), image.height()), quality,
       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // Should be at raster.
   ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
@@ -2198,16 +2251,16 @@
 
 TEST_P(GpuImageDecodeCacheTest,
        ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) {
-  gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
-  auto cache = CreateCache(color_space);
+  auto cache = CreateCache();
   bool is_decomposable = true;
   const SkFilterQuality quality = kHigh_SkFilterQuality;
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
 
   PaintImage image = CreateLargePaintImageForSoftwareFallback();
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, color_space);
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -2253,16 +2306,16 @@
 
 TEST_P(GpuImageDecodeCacheTest,
        ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) {
-  gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
-  auto cache = CreateCache(color_space);
+  auto cache = CreateCache();
   bool is_decomposable = true;
   const SkFilterQuality quality = kHigh_SkFilterQuality;
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
 
   PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12));
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, color_space);
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -2314,7 +2367,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2339,7 +2392,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   auto result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -2363,7 +2416,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   auto result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -2380,8 +2433,7 @@
     // YUV bitmap images do not happen, so this test will always skip for YUV.
     return;
   }
-  auto color_space = gfx::ColorSpace::CreateDisplayP3D65();
-  auto cache = CreateCache(color_space);
+  auto cache = CreateCache();
   const bool should_cache_sw_image =
       cache->SupportsColorSpaceConversion() && !use_transfer_cache_;
 
@@ -2389,10 +2441,10 @@
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
   PaintImage image = CreateBitmapImageInternal(GetLargeImageSize());
-  DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
-                       quality,
-                       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+  DrawImage draw_image(
+      image, SkIRect::MakeWH(image.width(), image.height()), quality,
+      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65());
   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2404,8 +2456,9 @@
   auto sw_image = cache->GetSWImageDecodeForTesting(draw_image);
   ASSERT_EQ(!!sw_image, should_cache_sw_image);
   if (should_cache_sw_image) {
-    EXPECT_TRUE(SkColorSpace::Equals(sw_image->colorSpace(),
-                                     color_space.ToSkColorSpace().get()));
+    EXPECT_TRUE(SkColorSpace::Equals(
+        sw_image->colorSpace(),
+        gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get()));
   }
 }
 
@@ -2422,7 +2475,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
@@ -2447,7 +2500,7 @@
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), quality,
         CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     DecodedDrawImage decoded_draw_image =
         EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
 
@@ -2504,7 +2557,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
   const int expected_width =
@@ -2551,7 +2604,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_image =
       EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
   ASSERT_TRUE(decoded_image.image());
@@ -2571,16 +2624,15 @@
 
 TEST_P(GpuImageDecodeCacheTest, BasicMips) {
   auto decode_and_check_mips = [this](SkFilterQuality filter_quality,
-                                      SkSize scale,
-                                      const gfx::ColorSpace& color_space,
+                                      SkSize scale, gfx::ColorSpace color_space,
                                       bool should_have_mips) {
-    auto cache = CreateCache(color_space);
+    auto cache = CreateCache();
     bool is_decomposable = true;
 
     PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
     DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                          filter_quality, CreateMatrix(scale, is_decomposable),
-                         PaintImage::kDefaultFrameIndex);
+                         PaintImage::kDefaultFrameIndex, color_space);
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -2656,7 +2708,7 @@
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
         CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -2701,7 +2753,7 @@
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
         CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -2754,7 +2806,7 @@
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
         CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -2792,7 +2844,7 @@
     DrawImage draw_image(
         image, SkIRect::MakeWH(image.width(), image.height()), filter_quality,
         CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -2873,7 +2925,7 @@
                                        almost_too_large_image.height()),
                        quality,
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
 
diff --git a/cc/tiles/image_controller_unittest.cc b/cc/tiles/image_controller_unittest.cc
index 05c82a4..1c3e0d3b 100644
--- a/cc/tiles/image_controller_unittest.cc
+++ b/cc/tiles/image_controller_unittest.cc
@@ -233,7 +233,7 @@
   return DrawImage(CreateDiscardablePaintImage(size),
                    SkIRect::MakeWH(size.width(), size.height()),
                    kNone_SkFilterQuality, SkMatrix::I(),
-                   PaintImage::kDefaultFrameIndex);
+                   PaintImage::kDefaultFrameIndex, gfx::ColorSpace());
 }
 
 DrawImage CreateBitmapDrawImage(gfx::Size size) {
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 2a1b59d..110d8251 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -16,7 +16,6 @@
 #include "cc/base/histograms.h"
 #include "cc/raster/tile_task.h"
 #include "cc/tiles/mipmap_util.h"
-#include "ui/gfx/color_space.h"
 #include "ui/gfx/skia_util.h"
 
 using base::trace_event::MemoryAllocatorDump;
@@ -143,10 +142,8 @@
 SoftwareImageDecodeCache::SoftwareImageDecodeCache(
     SkColorType color_type,
     size_t locked_memory_limit_bytes,
-    PaintImage::GeneratorClientId generator_client_id,
-    sk_sp<SkColorSpace> target_color_space)
+    PaintImage::GeneratorClientId generator_client_id)
     : decoded_images_(ImageMRUCache::NO_AUTO_EVICT),
-      target_color_space_(std::move(target_color_space)),
       locked_images_budget_(locked_memory_limit_bytes),
       color_type_(color_type),
       generator_client_id_(generator_client_id),
@@ -367,9 +364,8 @@
   // If we can use the original decode, we'll definitely need a decode.
   if (key.type() == CacheKey::kOriginal) {
     base::AutoUnlock release(lock_);
-    local_cache_entry =
-        Utils::DoDecodeImage(key, paint_image, color_type_, target_color_space_,
-                             generator_client_id_);
+    local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_,
+                                             generator_client_id_);
   } else {
     // Attempt to find a cached decode to generate a scaled/subrected decode
     // from.
@@ -396,9 +392,8 @@
     DCHECK(!should_decode_to_scale || !key.is_nearest_neighbor());
     if (should_decode_to_scale) {
       base::AutoUnlock release(lock_);
-      local_cache_entry =
-          Utils::DoDecodeImage(key, paint_image, color_type_,
-                               target_color_space_, generator_client_id_);
+      local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_,
+                                               generator_client_id_);
     }
 
     // Couldn't decode to scale or find a cached candidate. Create the
@@ -423,9 +418,9 @@
           key.type() == CacheKey::kSubrectOriginal
               ? SkIRect::MakeWH(paint_image.width(), paint_image.height())
               : gfx::RectToSkIRect(key.src_rect());
-      DrawImage candidate_draw_image(paint_image, src_rect,
-                                     kNone_SkFilterQuality, SkMatrix::I(),
-                                     key.frame_key().frame_index());
+      DrawImage candidate_draw_image(
+          paint_image, src_rect, kNone_SkFilterQuality, SkMatrix::I(),
+          key.frame_key().frame_index(), key.target_color_space());
       candidate_key.emplace(
           CacheKey::FromDrawImage(candidate_draw_image, color_type_));
     }
@@ -526,7 +521,9 @@
   // Cache images that need to be converted to a non-sRGB color space.
   // TODO(ccameron): Consider caching when any color conversion is required.
   // https://crbug.com/791828
-  if (target_color_space_ && !target_color_space_->isSRGB()) {
+  const gfx::ColorSpace& dst_color_space = draw_image.target_color_space();
+  if (dst_color_space.IsValid() &&
+      dst_color_space != gfx::ColorSpace::CreateSRGB()) {
     return true;
   }
 
diff --git a/cc/tiles/software_image_decode_cache.h b/cc/tiles/software_image_decode_cache.h
index eb7cc16..30040d1 100644
--- a/cc/tiles/software_image_decode_cache.h
+++ b/cc/tiles/software_image_decode_cache.h
@@ -34,8 +34,7 @@
 
   SoftwareImageDecodeCache(SkColorType color_type,
                            size_t locked_memory_limit_bytes,
-                           PaintImage::GeneratorClientId generator_client_id,
-                           sk_sp<SkColorSpace> target_color_space);
+                           PaintImage::GeneratorClientId generator_client_id);
   ~SoftwareImageDecodeCache() override;
 
   // ImageDecodeCache overrides.
@@ -151,7 +150,6 @@
                      PaintImage::FrameKeyHash>
       frame_key_to_image_keys_;
 
-  const sk_sp<SkColorSpace> target_color_space_;
   MemoryBudget locked_images_budget_;
 
   const SkColorType color_type_;
diff --git a/cc/tiles/software_image_decode_cache_perftest.cc b/cc/tiles/software_image_decode_cache_perftest.cc
index f873c977..fb99fb7 100644
--- a/cc/tiles/software_image_decode_cache_perftest.cc
+++ b/cc/tiles/software_image_decode_cache_perftest.cc
@@ -63,7 +63,8 @@
                              PaintImage::GetNextContentId())
                   .TakePaintImage(),
               subrect, quality,
-              CreateMatrix(SkSize::Make(scale.first, scale.second)), 0u);
+              CreateMatrix(SkSize::Make(scale.first, scale.second)), 0u,
+              gfx::ColorSpace());
         }
       }
     }
diff --git a/cc/tiles/software_image_decode_cache_unittest.cc b/cc/tiles/software_image_decode_cache_unittest.cc
index 18f6d88..3e31e7a 100644
--- a/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/cc/tiles/software_image_decode_cache_unittest.cc
@@ -23,13 +23,9 @@
 class TestSoftwareImageDecodeCache : public SoftwareImageDecodeCache {
  public:
   TestSoftwareImageDecodeCache()
-      : TestSoftwareImageDecodeCache(DefaultColorSpace()) {}
-
-  explicit TestSoftwareImageDecodeCache(const gfx::ColorSpace& color_space)
       : SoftwareImageDecodeCache(kN32_SkColorType,
                                  kLockedMemoryLimitBytes,
-                                 PaintImage::kDefaultGeneratorClientId,
-                                 color_space.ToSkColorSpace()) {}
+                                 PaintImage::kDefaultGeneratorClientId) {}
 };
 
 SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
@@ -58,7 +54,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kNone_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -80,7 +76,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kLow_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -98,7 +94,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kMedium_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -117,7 +113,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kLow_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kARGB_4444_SkColorType);
@@ -136,7 +132,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kHigh_SkFilterQuality,
       CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kARGB_4444_SkColorType);
@@ -155,7 +151,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kLow_SkFilterQuality,
       CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -175,7 +171,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.4f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -194,7 +190,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -214,7 +210,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -235,7 +231,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -256,7 +252,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -277,7 +273,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -298,7 +294,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -318,7 +314,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -338,7 +334,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -358,7 +354,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -377,7 +373,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -396,7 +392,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -415,7 +411,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -435,7 +431,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.2f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -454,7 +450,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(2.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -477,7 +473,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.45f, 0.45f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -497,7 +493,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -517,7 +513,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -538,7 +534,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -559,7 +555,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -594,7 +590,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kMedium_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.2f, 0.2f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -614,7 +610,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -628,7 +624,7 @@
   DrawImage another_draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.5f, 1.5), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto another_key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       another_draw_image, kN32_SkColorType);
@@ -651,7 +647,7 @@
       paint_image,
       SkIRect::MakeXYWH(25, 35, paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -672,7 +668,7 @@
       paint_image,
       SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage(
       draw_image, kN32_SkColorType);
@@ -693,7 +689,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -702,7 +698,7 @@
   DrawImage another_draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult another_result = cache.GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(another_result.need_unref);
@@ -723,7 +719,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -753,7 +749,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kHigh_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult high_quality_result =
       cache.GetTaskForImageAndRef(high_quality_draw_image,
                                   ImageDecodeCache::TracingInfo());
@@ -764,7 +760,7 @@
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       kNone_SkFilterQuality,
       CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult none_quality_result =
       cache.GetTaskForImageAndRef(none_quality_draw_image,
                                   ImageDecodeCache::TracingInfo());
@@ -788,7 +784,7 @@
   DrawImage half_size_draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult half_size_result = cache.GetTaskForImageAndRef(
       half_size_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(half_size_result.need_unref);
@@ -797,7 +793,7 @@
   DrawImage quarter_size_draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult quarter_size_result =
       cache.GetTaskForImageAndRef(quarter_size_draw_image,
                                   ImageDecodeCache::TracingInfo());
@@ -822,7 +818,7 @@
       first_paint_image,
       SkIRect::MakeWH(first_paint_image.width(), first_paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(first_result.need_unref);
@@ -833,7 +829,7 @@
       second_paint_image,
       SkIRect::MakeWH(second_paint_image.width(), second_paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(second_result.need_unref);
@@ -847,6 +843,63 @@
   cache.UnrefImage(second_draw_image);
 }
 
+// crbug.com/709341
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_GetTaskForImageDifferentColorSpace \
+  DISABLED_GetTaskForImageDifferentColorSpace
+#else
+#define MAYBE_GetTaskForImageDifferentColorSpace \
+  GetTaskForImageDifferentColorSpace
+#endif
+TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
+  TestSoftwareImageDecodeCache cache;
+  bool is_decomposable = true;
+  SkFilterQuality quality = kHigh_SkFilterQuality;
+
+  gfx::ColorSpace color_space_a(gfx::ColorSpace::PrimaryID::XYZ_D50,
+                                gfx::ColorSpace::TransferID::IEC61966_2_1);
+  gfx::ColorSpace color_space_b(gfx::ColorSpace::PrimaryID::SMPTE170M,
+                                gfx::ColorSpace::TransferID::IEC61966_2_1);
+  gfx::ColorSpace color_space_c = gfx::ColorSpace::CreateSRGB();
+
+  PaintImage paint_image = CreatePaintImage(100, 100, color_space_a);
+  DrawImage first_draw_image(
+      paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
+      quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, color_space_b);
+  ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef(
+      first_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(first_result.need_unref);
+  EXPECT_TRUE(first_result.task);
+
+  DrawImage second_draw_image(
+      paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
+      quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, color_space_c);
+  ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef(
+      second_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(second_result.need_unref);
+  EXPECT_TRUE(second_result.task);
+  EXPECT_TRUE(first_result.task.get() != second_result.task.get());
+
+  DrawImage third_draw_image(
+      paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
+      quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, color_space_b);
+  ImageDecodeCache::TaskResult third_result = cache.GetTaskForImageAndRef(
+      third_draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(third_result.need_unref);
+  EXPECT_TRUE(third_result.task);
+  EXPECT_TRUE(first_result.task.get() == third_result.task.get());
+
+  TestTileTaskRunner::ProcessTask(first_result.task.get());
+  TestTileTaskRunner::ProcessTask(second_result.task.get());
+
+  cache.UnrefImage(first_draw_image);
+  cache.UnrefImage(second_draw_image);
+  cache.UnrefImage(third_draw_image);
+}
+
 TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) {
   TestSoftwareImageDecodeCache cache;
   bool is_decomposable = true;
@@ -856,7 +909,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -885,7 +938,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -920,7 +973,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -961,7 +1014,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1001,7 +1054,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1034,7 +1087,7 @@
       paint_image,
       SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
   EXPECT_TRUE(result.need_unref);
@@ -1065,7 +1118,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   DecodedDrawImage decoded_draw_image =
       cache.GetDecodedImageForDraw(draw_image);
@@ -1090,7 +1143,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   DecodedDrawImage decoded_draw_image =
       cache.GetDecodedImageForDraw(draw_image);
@@ -1120,7 +1173,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1144,7 +1197,7 @@
       paint_image,
       SkIRect::MakeXYWH(150, 150, paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1167,7 +1220,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1195,7 +1248,7 @@
   PaintImage paint_image = CreatePaintImage(100, 100);
   DrawImage draw_image(paint_image, SkIRect::MakeXYWH(10, 10, 80, 80), quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1228,7 +1281,7 @@
   PaintImage paint_image = CreatePaintImage(100, 100);
   DrawImage draw_image(paint_image, SkIRect::MakeXYWH(10, 10, 80, 80), quality,
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1259,7 +1312,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1290,7 +1343,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1321,7 +1374,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1352,7 +1405,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1383,7 +1436,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1414,7 +1467,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1445,7 +1498,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1476,7 +1529,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.001f, 0.001f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1500,11 +1553,11 @@
   DrawImage draw_image_50(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DrawImage draw_image_49(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result_50 = cache.GetTaskForImageAndRef(
       draw_image_50, ImageDecodeCache::TracingInfo());
@@ -1551,7 +1604,7 @@
     DrawImage draw_image(
         paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
         quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, DefaultColorSpace());
     ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo());
     EXPECT_TRUE(result.need_unref);
@@ -1586,9 +1639,10 @@
 
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
-  DrawImage draw_image(
-      image, SkIRect::MakeWH(image.width(), image.height()), quality,
-      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 1u);
+  DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+                       quality,
+                       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+                       1u, DefaultColorSpace());
   auto decoded_image = cache.GetDecodedImageForDraw(draw_image);
   ASSERT_TRUE(decoded_image.image());
   ASSERT_EQ(generator->frames_decoded().size(), 1u);
@@ -1597,7 +1651,8 @@
   cache.DrawWithImageFinished(draw_image, decoded_image);
 
   // Scaled.
-  DrawImage scaled_draw_image(draw_image, 0.5f, 2u);
+  DrawImage scaled_draw_image(draw_image, 0.5f, 2u,
+                              draw_image.target_color_space());
   decoded_image = cache.GetDecodedImageForDraw(scaled_draw_image);
   ASSERT_TRUE(decoded_image.image());
   ASSERT_EQ(generator->frames_decoded().size(), 1u);
@@ -1608,7 +1663,8 @@
   // Subset.
   DrawImage subset_draw_image(
       image, SkIRect::MakeWH(5, 5), quality,
-      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u);
+      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u,
+      DefaultColorSpace());
   decoded_image = cache.GetDecodedImageForDraw(subset_draw_image);
   ASSERT_TRUE(decoded_image.image());
   ASSERT_EQ(generator->frames_decoded().size(), 1u);
@@ -1628,7 +1684,7 @@
                                   DefaultColorSpace().ToSkColorSpace(), false);
   DrawImage draw_image(paint_image, SkIRect::MakeXYWH(0, 0, 10, 10), quality,
                        CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   ImageDecodeCache::TaskResult result =
       cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
@@ -1661,7 +1717,7 @@
       gfx::Size(100, 100), DefaultColorSpace().ToSkColorSpace());
   DrawImage draw_image(paint_image, SkIRect::MakeWH(100, 100), quality,
                        CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_draw_image =
       cache.GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
@@ -1671,7 +1727,7 @@
   DrawImage empty_draw_image(
       paint_image, SkIRect::MakeEmpty(), quality,
       CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage empty_decoded_draw_image =
       cache.GetDecodedImageForDraw(empty_draw_image);
   EXPECT_FALSE(empty_decoded_draw_image.image());
@@ -1679,16 +1735,16 @@
 }
 
 TEST(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) {
-  gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65();
-  TestSoftwareImageDecodeCache cache(target_color_space);
+  TestSoftwareImageDecodeCache cache;
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
+  gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65();
 
   PaintImage paint_image = CreateBitmapImage(gfx::Size(100, 100));
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, target_color_space);
 
   DecodedDrawImage decoded_draw_image =
       cache.GetDecodedImageForDraw(draw_image);
@@ -1712,7 +1768,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
 
   // The cache should not support this image.
   EXPECT_FALSE(cache.UseCacheForDrawImage(draw_image));
@@ -1738,7 +1794,7 @@
           paint_image,
           SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
           CreateMatrix(SkSize::Make(scale, scale), is_decomposable),
-          PaintImage::kDefaultFrameIndex);
+          PaintImage::kDefaultFrameIndex, DefaultColorSpace());
       DecodedDrawImage decoded_draw_image =
           cache.GetDecodedImageForDraw(draw_image);
       EXPECT_TRUE(decoded_draw_image.image());
@@ -1777,7 +1833,7 @@
   DrawImage draw_image1(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_image1 = cache.GetDecodedImageForDraw(draw_image1);
   ASSERT_TRUE(decoded_image1.image());
   EXPECT_EQ(decoded_image1.image()->width(), 50);
@@ -1794,7 +1850,7 @@
   DrawImage draw_image2(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.25, 0.25), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_image2 = cache.GetDecodedImageForDraw(draw_image2);
   ASSERT_TRUE(decoded_image2.image());
   EXPECT_EQ(decoded_image2.image()->width(), 25);
@@ -1834,7 +1890,7 @@
   // subrect vetoes decode to scale.
   DrawImage draw_image(paint_image, SkIRect::MakeWH(50, 50), quality,
                        CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
-                       PaintImage::kDefaultFrameIndex);
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
   ASSERT_TRUE(decoded_image.image());
   EXPECT_EQ(decoded_image.image()->width(), 25);
@@ -1870,7 +1926,7 @@
   DrawImage draw_image(
       paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()),
       quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
-      PaintImage::kDefaultFrameIndex);
+      PaintImage::kDefaultFrameIndex, DefaultColorSpace());
   DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
   ASSERT_TRUE(decoded_image.image());
   EXPECT_EQ(decoded_image.image()->width(), 100);
diff --git a/cc/tiles/software_image_decode_cache_unittest_combinations.cc b/cc/tiles/software_image_decode_cache_unittest_combinations.cc
index 03d3e09e..5052a2a 100644
--- a/cc/tiles/software_image_decode_cache_unittest_combinations.cc
+++ b/cc/tiles/software_image_decode_cache_unittest_combinations.cc
@@ -50,7 +50,7 @@
             ? SkIRect::MakeWH(paint_image().width(), paint_image().height())
             : src_rect,
         kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(scale, scale), true),
-        PaintImage::kDefaultFrameIndex);
+        PaintImage::kDefaultFrameIndex, GetColorSpace());
   }
 
   SoftwareImageDecodeCache& cache() { return *cache_; }
@@ -80,8 +80,7 @@
   std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
     return std::make_unique<SoftwareImageDecodeCache>(
         kN32_SkColorType, kLockedMemoryLimitBytes,
-        PaintImage::kDefaultGeneratorClientId,
-        GetColorSpace().ToSkColorSpace());
+        PaintImage::kDefaultGeneratorClientId);
   }
 };
 
@@ -90,8 +89,7 @@
   std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
     return std::make_unique<SoftwareImageDecodeCache>(
         kARGB_4444_SkColorType, kLockedMemoryLimitBytes,
-        PaintImage::kDefaultGeneratorClientId,
-        GetColorSpace().ToSkColorSpace());
+        PaintImage::kDefaultGeneratorClientId);
   }
 };
 
@@ -100,8 +98,7 @@
   std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
     return std::make_unique<SoftwareImageDecodeCache>(
         kRGBA_F16_SkColorType, kLockedMemoryLimitBytes,
-        PaintImage::kDefaultGeneratorClientId,
-        GetColorSpace().ToSkColorSpace());
+        PaintImage::kDefaultGeneratorClientId);
   }
 };
 
@@ -138,6 +135,9 @@
                          const DrawImage& draw_image,
                          const gfx::Size& expected_size) override {
     auto decoded = cache().GetDecodedImageForDraw(draw_image);
+    EXPECT_TRUE(SkColorSpace::Equals(
+        decoded.image()->colorSpace(),
+        draw_image.target_color_space().ToSkColorSpace().get()));
     SCOPED_TRACE(base::StringPrintf("Failure from line %d", line));
     EXPECT_EQ(decoded.image()->width(), expected_size.width());
     EXPECT_EQ(decoded.image()->height(), expected_size.height());
diff --git a/cc/tiles/software_image_decode_cache_utils.cc b/cc/tiles/software_image_decode_cache_utils.cc
index fac25c22..b3dae15 100644
--- a/cc/tiles/software_image_decode_cache_utils.cc
+++ b/cc/tiles/software_image_decode_cache_utils.cc
@@ -59,7 +59,6 @@
     const CacheKey& key,
     const PaintImage& paint_image,
     SkColorType color_type,
-    sk_sp<SkColorSpace> color_space,
     PaintImage::GeneratorClientId client_id) {
   SkISize target_size =
       SkISize::Make(key.target_size().width(), key.target_size().height());
@@ -75,7 +74,7 @@
                "SoftwareImageDecodeCacheUtils::DoDecodeImage - "
                "decode");
   bool result = paint_image.Decode(target_pixels->data(), &target_info,
-                                   std::move(color_space),
+                                   key.target_color_space().ToSkColorSpace(),
                                    key.frame_key().frame_index(), client_id);
   if (!result) {
     target_pixels->Unlock();
@@ -181,7 +180,7 @@
   // the filter quality doesn't matter. Early out instead.
   if (target_size.IsEmpty()) {
     return CacheKey(frame_key, stable_id, kSubrectAndScale, false, src_rect,
-                    target_size);
+                    target_size, image.target_color_space());
   }
 
   ProcessingType type = kOriginal;
@@ -234,7 +233,7 @@
   }
 
   return CacheKey(frame_key, stable_id, type, is_nearest_neighbor, src_rect,
-                  target_size);
+                  target_size, image.target_color_space());
 }
 
 SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(
@@ -243,13 +242,15 @@
     ProcessingType type,
     bool is_nearest_neighbor,
     const gfx::Rect& src_rect,
-    const gfx::Size& target_size)
+    const gfx::Size& target_size,
+    const gfx::ColorSpace& target_color_space)
     : frame_key_(frame_key),
       stable_id_(stable_id),
       type_(type),
       is_nearest_neighbor_(is_nearest_neighbor),
       src_rect_(src_rect),
-      target_size_(target_size) {
+      target_size_(target_size),
+      target_color_space_(target_color_space) {
   if (type == kOriginal) {
     hash_ = frame_key_.hash();
   } else {
@@ -266,6 +267,8 @@
     hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash),
                            frame_key_.hash());
   }
+  // Include the target color space in the hash regardless of scaling.
+  hash_ = base::HashInts(hash_, target_color_space.GetHash());
 }
 
 SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(const CacheKey& other) =
@@ -287,6 +290,7 @@
   }
   str << "]\nis_nearest_neightbor[" << is_nearest_neighbor_ << "]\nsrc_rect["
       << src_rect_.ToString() << "]\ntarget_size[" << target_size_.ToString()
+      << "]\ntarget_color_space[" << target_color_space_.ToString()
       << "]\nhash[" << hash_ << "]";
   return str.str();
 }
diff --git a/cc/tiles/software_image_decode_cache_utils.h b/cc/tiles/software_image_decode_cache_utils.h
index 42d7b020..835d68c 100644
--- a/cc/tiles/software_image_decode_cache_utils.h
+++ b/cc/tiles/software_image_decode_cache_utils.h
@@ -16,6 +16,7 @@
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/core/SkSize.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -56,6 +57,7 @@
       // image.
       DCHECK(!is_nearest_neighbor_ || type_ == kOriginal);
       return frame_key_ == other.frame_key_ && type_ == other.type_ &&
+             target_color_space_ == other.target_color_space_ &&
              (type_ == kOriginal || (src_rect_ == other.src_rect_ &&
                                      target_size_ == other.target_size_));
     }
@@ -68,6 +70,9 @@
     bool is_nearest_neighbor() const { return is_nearest_neighbor_; }
     gfx::Rect src_rect() const { return src_rect_; }
     gfx::Size target_size() const { return target_size_; }
+    const gfx::ColorSpace& target_color_space() const {
+      return target_color_space_;
+    }
 
     size_t get_hash() const { return hash_; }
 
@@ -89,7 +94,8 @@
              ProcessingType type,
              bool is_nearest_neighbor,
              const gfx::Rect& src_rect,
-             const gfx::Size& size);
+             const gfx::Size& size,
+             const gfx::ColorSpace& target_color_space);
 
     PaintImage::FrameKey frame_key_;
     // The stable id is does not factor into the cache key's value for hashing
@@ -100,6 +106,7 @@
     bool is_nearest_neighbor_;
     gfx::Rect src_rect_;
     gfx::Size target_size_;
+    gfx::ColorSpace target_color_space_;
     size_t hash_;
   };
 
@@ -179,7 +186,6 @@
       const CacheKey& key,
       const PaintImage& image,
       SkColorType color_type,
-      sk_sp<SkColorSpace> color_space,
       PaintImage::GeneratorClientId client_id);
   static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate(
       const CacheKey& key,
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 827d7e10..165bb015 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -682,6 +682,8 @@
   MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(),
                            resource_pool_->resource_count());
 
+  gfx::ColorSpace raster_color_space = client_->GetRasterColorSpace();
+
   std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
       client_->BuildRasterQueue(global_state_.tree_priority,
                                 RasterTilePriorityQueue::Type::ALL));
@@ -734,7 +736,8 @@
       DCHECK(prioritized_tile.should_decode_checkered_images_for_tile());
 
       AddCheckeredImagesToDecodeQueue(
-          prioritized_tile, CheckerImageTracker::DecodeType::kRaster,
+          prioritized_tile, raster_color_space,
+          CheckerImageTracker::DecodeType::kRaster,
           &work_to_schedule.checker_image_decode_queue);
       continue;
     }
@@ -790,13 +793,15 @@
       if (tile->raster_task_scheduled_with_checker_images() &&
           prioritized_tile.should_decode_checkered_images_for_tile()) {
         AddCheckeredImagesToDecodeQueue(
-            prioritized_tile, CheckerImageTracker::DecodeType::kRaster,
+            prioritized_tile, raster_color_space,
+            CheckerImageTracker::DecodeType::kRaster,
             &work_to_schedule.checker_image_decode_queue);
       }
     } else {
       // Creating the raster task here will acquire resources, but
       // this resource usage has already been accounted for above.
-      auto raster_task = CreateRasterTask(prioritized_tile, &work_to_schedule);
+      auto raster_task = CreateRasterTask(
+          prioritized_tile, client_->GetRasterColorSpace(), &work_to_schedule);
       if (!raster_task) {
         continue;
       }
@@ -836,7 +841,8 @@
       if (tile->draw_info().is_checker_imaged() ||
           tile->raster_task_scheduled_with_checker_images()) {
         AddCheckeredImagesToDecodeQueue(
-            prioritized_tile, CheckerImageTracker::DecodeType::kRaster,
+            prioritized_tile, raster_color_space,
+            CheckerImageTracker::DecodeType::kRaster,
             &work_to_schedule.checker_image_decode_queue);
       }
     }
@@ -893,6 +899,7 @@
 
 void TileManager::PartitionImagesForCheckering(
     const PrioritizedTile& prioritized_tile,
+    const gfx::ColorSpace& raster_color_space,
     std::vector<DrawImage>* sync_decoded_images,
     std::vector<PaintImage>* checkered_images,
     const gfx::Rect* invalidated_rect,
@@ -915,7 +922,7 @@
       (*image_to_frame_index)[image.stable_id()] = frame_index;
 
     DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(),
-                         frame_index);
+                         frame_index, raster_color_space);
     if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree))
       checkered_images->push_back(draw_image.paint_image());
     else
@@ -925,6 +932,7 @@
 
 void TileManager::AddCheckeredImagesToDecodeQueue(
     const PrioritizedTile& prioritized_tile,
+    const gfx::ColorSpace& raster_color_space,
     CheckerImageTracker::DecodeType decode_type,
     CheckerImageTracker::ImageDecodeQueue* image_decode_queue) {
   Tile* tile = prioritized_tile.tile();
@@ -937,7 +945,7 @@
     size_t frame_index = client_->GetFrameIndexForImage(
         original_draw_image->paint_image(), tree);
     DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(),
-                         frame_index);
+                         frame_index, raster_color_space);
     if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) {
       image_decode_queue->emplace_back(draw_image.paint_image(), decode_type);
     }
@@ -973,6 +981,8 @@
 
   graph_.Reset();
 
+  gfx::ColorSpace raster_color_space = client_->GetRasterColorSpace();
+
   scoped_refptr<TileTask> required_for_activation_done_task =
       CreateTaskSetFinishedTask(
           &TileManager::DidFinishRunningTileTasksRequiredForActivation);
@@ -1028,8 +1038,9 @@
   for (const PrioritizedTile& prioritized_tile : tiles_to_process_for_images) {
     std::vector<DrawImage> sync_decoded_images;
     std::vector<PaintImage> checkered_images;
-    PartitionImagesForCheckering(prioritized_tile, &sync_decoded_images,
-                                 &checkered_images, nullptr);
+    PartitionImagesForCheckering(prioritized_tile, raster_color_space,
+                                 &sync_decoded_images, &checkered_images,
+                                 nullptr);
 
     // Add the sync decoded images to |new_locked_images| so they can be added
     // to the task graph.
@@ -1121,6 +1132,7 @@
 
 scoped_refptr<TileTask> TileManager::CreateRasterTask(
     const PrioritizedTile& prioritized_tile,
+    const gfx::ColorSpace& raster_color_space,
     PrioritizedWorkToSchedule* work_to_schedule) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                "TileManager::CreateRasterTask");
@@ -1137,7 +1149,7 @@
         tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(),
         &invalidated_rect);
   }
-  const gfx::ColorSpace& raster_color_space = client_->GetRasterColorSpace();
+
   bool partial_tile_decode = false;
   if (resource) {
     resource_content_id = tile->invalidated_id();
@@ -1168,8 +1180,8 @@
   base::flat_map<PaintImage::Id, size_t> image_id_to_current_frame_index;
   if (!skip_images) {
     PartitionImagesForCheckering(
-        prioritized_tile, &sync_decoded_images, &checkered_images,
-        partial_tile_decode ? &invalidated_rect : nullptr,
+        prioritized_tile, raster_color_space, &sync_decoded_images,
+        &checkered_images, partial_tile_decode ? &invalidated_rect : nullptr,
         &image_id_to_current_frame_index);
   }
 
@@ -1233,7 +1245,7 @@
   }
 
   PlaybackImageProvider image_provider(image_controller_.cache(),
-                                       std::move(settings));
+                                       raster_color_space, std::move(settings));
   PaintWorkletImageProvider paint_worklet_image_provider(
       image_controller_.paint_worklet_image_cache());
   DispatchingImageProvider dispatching_image_provider(
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 650742f9..015ce53 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -355,6 +355,7 @@
   void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile);
   scoped_refptr<TileTask> CreateRasterTask(
       const PrioritizedTile& prioritized_tile,
+      const gfx::ColorSpace& raster_color_space,
       PrioritizedWorkToSchedule* work_to_schedule);
 
   std::unique_ptr<EvictionTilePriorityQueue>
@@ -387,12 +388,14 @@
 
   void PartitionImagesForCheckering(
       const PrioritizedTile& prioritized_tile,
+      const gfx::ColorSpace& raster_color_space,
       std::vector<DrawImage>* sync_decoded_images,
       std::vector<PaintImage>* checkered_images,
       const gfx::Rect* invalidated_rect,
       base::flat_map<PaintImage::Id, size_t>* image_to_frame_index = nullptr);
   void AddCheckeredImagesToDecodeQueue(
       const PrioritizedTile& prioritized_tile,
+      const gfx::ColorSpace& raster_color_space,
       CheckerImageTracker::DecodeType decode_type,
       CheckerImageTracker::ImageDecodeQueue* image_decode_queue);
 
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 8883b4e..9c6d1e05 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -3369,9 +3369,9 @@
 
   // Add the images to our decoded_image_tracker.
   host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode(
-      image1, base::DoNothing());
+      image1, gfx::ColorSpace(), base::DoNothing());
   host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode(
-      image2, base::DoNothing());
+      image2, gfx::ColorSpace(), base::DoNothing());
   EXPECT_EQ(0u, host_impl()
                     ->tile_manager()
                     ->decoded_image_tracker()
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 4162c6b..a3824f9 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -467,7 +467,7 @@
 void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
   // LayerTreeHost may have changed the GPU rasterization flags state, which
   // may require an update of the tree resources.
-  UpdateTreeResourcesIfNeeded();
+  UpdateTreeResourcesForGpuRasterizationIfNeeded();
   sync_tree()->set_needs_update_draw_properties();
 
   // We need an update immediately post-commit to have the opportunity to create
@@ -2402,16 +2402,8 @@
   return true;
 }
 
-void LayerTreeHostImpl::UpdateTreeResourcesIfNeeded() {
-  // For simplicity, clobber all resources when the color space changes.
-  // This is mostly to clear the image decode caches, which don't handle
-  // multiple color space at once.
-  int color_space_id = -1;
-  GetRasterColorSpaceAndId(&color_space_id);
-  bool color_space_changed = last_color_space_id_ != color_space_id;
-  last_color_space_id_ = color_space_id;
-
-  if (!UpdateGpuRasterizationStatus() && !color_space_changed)
+void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() {
+  if (!UpdateGpuRasterizationStatus())
     return;
 
   // Clean up and replace existing tile manager with another one that uses
@@ -3105,15 +3097,13 @@
         viz::ResourceFormatToClosestSkColorType(/*gpu_compositing=*/true,
                                                 tile_format),
         settings_.decoded_image_working_set_budget_bytes, max_texture_size_,
-        paint_image_generator_client_id_,
-        GetRasterColorSpace().ToSkColorSpace());
+        paint_image_generator_client_id_);
   } else {
     bool gpu_compositing = !!layer_tree_frame_sink_->context_provider();
     image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
         viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format),
         settings_.decoded_image_working_set_budget_bytes,
-        paint_image_generator_client_id_,
-        GetRasterColorSpace().ToSkColorSpace());
+        paint_image_generator_client_id_);
   }
 
   // Pass the single-threaded synchronous task graph runner to the worker pool
@@ -3218,8 +3208,9 @@
   // Optimistically specify the current raster color space, since we assume that
   // it won't change.
   tile_manager_.decoded_image_tracker().QueueImageDecode(
-      image, base::BindOnce(&LayerTreeHostImpl::ImageDecodeFinished,
-                            base::Unretained(this), request_id));
+      image, GetRasterColorSpace(),
+      base::BindOnce(&LayerTreeHostImpl::ImageDecodeFinished,
+                     base::Unretained(this), request_id));
   tile_manager_.checker_image_tracker().DisallowCheckeringForImage(image);
 }
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 267baa0..ee459299 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -828,7 +828,7 @@
 
   // Returns true if status changed.
   bool UpdateGpuRasterizationStatus();
-  void UpdateTreeResourcesIfNeeded();
+  void UpdateTreeResourcesForGpuRasterizationIfNeeded();
 
   Viewport* viewport() const { return viewport_.get(); }
 
@@ -1194,7 +1194,6 @@
   base::circular_deque<FrameTokenInfo> frame_token_infos_;
   ui::FrameMetrics frame_metrics_;
   ui::SkippedFrameTracker skipped_frame_tracker_;
-  int last_color_space_id_ = -1;
   bool is_animating_for_snap_;
 
   const PaintImage::GeneratorClientId paint_image_generator_client_id_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 5b6f640..29fbffe 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -10162,11 +10162,6 @@
   // RequiresHighResToDraw is set when new output surface is used.
   EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
 
-  // The first commit will also set RequiresHighResToDraw due to the
-  // raster color space changing.
-  host_impl_->ResetRequiresHighResToDraw();
-  host_impl_->CommitComplete();
-  EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
   host_impl_->ResetRequiresHighResToDraw();
 
   host_impl_->SetContentHasSlowPaths(false);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 9a7103b..54f5029 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -8341,7 +8341,8 @@
 
     image_ = DrawImage(CreateDiscardablePaintImage(gfx::Size(400, 400)),
                        SkIRect::MakeWH(400, 400), kNone_SkFilterQuality,
-                       SkMatrix::I(), PaintImage::kDefaultFrameIndex);
+                       SkMatrix::I(), PaintImage::kDefaultFrameIndex,
+                       gfx::ColorSpace());
     auto callback = base::BindRepeating(
         &LayerTreeHostTestQueueImageDecode::ImageDecodeFinished,
         base::Unretained(this));
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 1bcb233..c1a65c4 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -249,6 +249,7 @@
           "/DELAYLOAD:shell32.dll",
           "/DELAYLOAD:shlwapi.dll",
           "/DELAYLOAD:user32.dll",
+          "/DELAYLOAD:userenv.dll",
           "/DELAYLOAD:uxtheme.dll",
           "/DELAYLOAD:wer.dll",
           "/DELAYLOAD:wevtapi.dll",
@@ -454,6 +455,7 @@
       "/DELAYLOAD:imagehlp.dll",
       "/DELAYLOAD:imm32.dll",
       "/DELAYLOAD:iphlpapi.dll",
+      "/DELAYLOAD:msi.dll",
       "/DELAYLOAD:netapi32.dll",
       "/DELAYLOAD:ole32.dll",
       "/DELAYLOAD:oleacc.dll",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 7ea4889..e43a57f 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -778,7 +778,7 @@
         {% endfor %}
         <!-- Activities for WebAPKs. -->
         <activity android:name="org.chromium.chrome.browser.webapps.SameTaskWebApkActivity"
-            android:theme="@style/Theme.Chromium.Webapp"
+            android:theme="@style/Theme.Chromium.Webapp.Translucent"
             android:label="@string/webapp_activity_title"
             android:exported="false"
             android:persistableMode="persistNever"
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
index f899bd8..50ae6ad0 100644
--- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
+++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -787,7 +787,7 @@
         android:persistableMode="persistNever"
         android:resizeableActivity="true"
         android:supportsPictureInPicture="true"
-        android:theme="@style/Theme.Chromium.Webapp"
+        android:theme="@style/Theme.Chromium.Webapp.Translucent"
         android:windowSoftInputMode="adjustResize">
       <intent-filter>
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 731f3d6..a5eb7ca 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -133,6 +133,10 @@
         <item name="android:windowDisablePreview">true</item>
     </style>
 
+    <style name="Theme.Chromium.Webapp.Translucent" parent="Theme.Chromium.Webapp">
+        <item name="android:windowIsTranslucent">true</item>
+    </style>
+
     <style name="Base.Theme.Chromium.Preferences" parent="Theme.Chromium.WithActionBar">
         <item name="android:spinnerItemStyle">@style/PreferenceSpinnerItem</item>
         <item name="floatLabelTextAppearance">@style/TextAppearance.BlackCaption</item>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHBubbleDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHBubbleDelegateImpl.java
index 692f40c..9c4881fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHBubbleDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/IPHBubbleDelegateImpl.java
@@ -8,7 +8,6 @@
 import android.support.annotation.Nullable;
 import android.view.View;
 
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.download.DownloadInfoBarController;
 import org.chromium.chrome.browser.download.DownloadManagerService;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
@@ -16,8 +15,6 @@
 import org.chromium.chrome.browser.infobar.IPHInfoBarSupport.TrackerParameters;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.widget.textbubble.TextBubble;
-import org.chromium.components.feature_engagement.EventConstants;
-import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
 
 /**
@@ -38,7 +35,6 @@
     // IPHInfoBarSupport.IPHBubbleDelegate implementation.
     @Override
     public PopupState createStateForInfoBar(View anchorView, @InfoBarIdentifier int infoBarId) {
-        logEvent(infoBarId);
         TrackerParameters params = getTrackerParameters(infoBarId);
         if (params == null || !mTracker.shouldTriggerHelpUI(params.feature)) return null;
 
@@ -57,21 +53,8 @@
         mTracker.dismissed(state.feature);
     }
 
-    private void logEvent(@InfoBarIdentifier int infoBarId) {
-        switch (infoBarId) {
-            case InfoBarIdentifier.DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE:
-                mTracker.notifyEvent(EventConstants.DATA_SAVER_PREVIEW_INFOBAR_SHOWN);
-                break;
-            default:
-                break;
-        }
-    }
-
     private @Nullable TrackerParameters getTrackerParameters(@InfoBarIdentifier int infoBarId) {
         switch (infoBarId) {
-            case InfoBarIdentifier.DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE:
-                return new TrackerParameters(FeatureConstants.DATA_SAVER_PREVIEW_FEATURE,
-                        R.string.iph_data_saver_preview_text, R.string.iph_data_saver_preview_text);
             case InfoBarIdentifier.DOWNLOAD_PROGRESS_INFOBAR_ANDROID:
                 DownloadInfoBarController controller =
                         DownloadManagerService.getDownloadManagerService()
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 c066e11..32109ad 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
@@ -113,6 +113,7 @@
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.widget.Toast;
@@ -1455,6 +1456,12 @@
         if (TextUtils.isEmpty(homePageUrl) || isNewTabPageButtonEnabled) {
             homePageUrl = UrlConstants.NTP_URL;
         }
+        boolean is_chrome_internal =
+                homePageUrl.startsWith(ContentUrlConstants.ABOUT_URL_SHORT_PREFIX)
+                || homePageUrl.startsWith(UrlConstants.CHROME_URL_SHORT_PREFIX)
+                || homePageUrl.startsWith(UrlConstants.CHROME_NATIVE_URL_SHORT_PREFIX);
+        RecordHistogram.recordBooleanHistogram(
+                "Navigation.Home.IsChromeInternal", is_chrome_internal);
         if (isNewTabPageButtonEnabled) {
             recordToolbarUseForIPH(EventConstants.CLEAR_TAB_BUTTON_CLICKED);
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameTaskWebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameTaskWebApkActivity.java
index 548d344..338f3aa0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameTaskWebApkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SameTaskWebApkActivity.java
@@ -4,5 +4,5 @@
 
 package org.chromium.chrome.browser.webapps;
 
-/** WebApkActivity variant with documentLaunchMode="none". */
+/** WebApkActivity variant which is translucent and has documentLaunchMode="none". */
 public class SameTaskWebApkActivity extends WebApkActivity {}
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 71408f6f..590b4f5 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3857,9 +3857,6 @@
       <message name="IDS_IPH_DOWNLOAD_HOME_ACCESSIBILITY_TEXT" desc="The in-product-help accessibility text to open download home after a restart.">
         Find your files and pages in Downloads from the More Options button
       </message>
-      <message name="IDS_IPH_DATA_SAVER_PREVIEW_TEXT" desc="In-product help for when a lite mode preview page and infobar are shown.">
-          Chrome is using less data to show you this page
-      </message>
       <message name="IDS_IPH_DATA_SAVER_DETAIL_TEXT" desc="The in-product-help message to open lite mode.">
         See how much data you've saved
       </message>
diff --git a/chrome/app/android/chrome_main_delegate_android.cc b/chrome/app/android/chrome_main_delegate_android.cc
index 6bd5baf..aeb941b 100644
--- a/chrome/app/android/chrome_main_delegate_android.cc
+++ b/chrome/app/android/chrome_main_delegate_android.cc
@@ -72,25 +72,32 @@
 int ChromeMainDelegateAndroid::RunProcess(
     const std::string& process_type,
     const content::MainFunctionParams& main_function_params) {
-  TRACE_EVENT0("startup", "ChromeMainDelegateAndroid::RunProcess")
-  if (process_type.empty()) {
-    SecureDataDirectory();
+  TRACE_EVENT0("startup", "ChromeMainDelegateAndroid::RunProcess");
+  // Defer to the default main method outside the browser process.
+  if (!process_type.empty())
+    return -1;
 
-    // Because the browser process can be started asynchronously as a series of
-    // UI thread tasks a second request to start it can come in while the
-    // first request is still being processed. Chrome must keep the same
-    // browser runner for the second request.
-    // Also only record the start time the first time round, since this is the
-    // start time of the application, and will be same for all requests.
-    if (!browser_runner_.get()) {
-      startup_metric_utils::RecordMainEntryPointTime(
-          chrome::android::GetMainEntryPointTimeTicks());
-      browser_runner_ = content::BrowserMainRunner::Create();
-    }
-    return browser_runner_->Initialize(main_function_params);
+  SecureDataDirectory();
+
+  // Because the browser process can be started asynchronously as a series of
+  // UI thread tasks a second request to start it can come in while the
+  // first request is still being processed. Chrome must keep the same
+  // browser runner for the second request.
+  // Also only record the start time the first time round, since this is the
+  // start time of the application, and will be same for all requests.
+  if (!browser_runner_) {
+    startup_metric_utils::RecordMainEntryPointTime(
+        chrome::android::GetMainEntryPointTimeTicks());
+    browser_runner_ = content::BrowserMainRunner::Create();
   }
 
-  return ChromeMainDelegate::RunProcess(process_type, main_function_params);
+  int exit_code = browser_runner_->Initialize(main_function_params);
+  // On Android we do not run BrowserMain(), so the above initialization of a
+  // BrowserMainRunner is all we want to occur. Return >= 0 to avoid running
+  // BrowserMain, while preserving any error codes > 0.
+  if (exit_code > 0)
+    return exit_code;
+  return 0;
 }
 
 void ChromeMainDelegateAndroid::ProcessExiting(
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index ed8a7af..4f16780 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -1044,7 +1044,9 @@
 // ANDROID doesn't support "service", so no CloudPrintServiceProcessMain, and
 // arraysize doesn't support empty array. So we comment out the block for
 // Android.
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+  NOTREACHED();  // Android provides a subclass and shares no code here.
+#else
   static const MainFunction kMainFunctions[] = {
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW) && !defined(CHROME_MULTIPLE_DLL_CHILD) && \
     !defined(OS_CHROMEOS)
@@ -1070,7 +1072,7 @@
     if (process_type == kMainFunctions[i].name)
       return kMainFunctions[i].function(main_function_params);
   }
-#endif
+#endif  // !defined(OS_ANDROID)
 
   return -1;
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index b9ce254e..cfcbd55 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4545,26 +4545,17 @@
         </message>
       </if>
 
-      <!-- Preview InfoBar -->
-      <message name="IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE" desc="The text of the infobar notifying the user that mobile data usage was reduced by showing a preview version of the web page instead of the full page.">
-         Saved data
-      </message>
-      <message name="IDS_PREVIEWS_INFOBAR_FASTER_PAGE_TITLE" desc="The text of the infobar notifying the user that a preview page has been shown to load faster.">
-         Faster page loaded
-      </message>
-      <message name="IDS_PREVIEWS_INFOBAR_LINK" desc="The text of the link to load the original page from the infobar notifying the user that a preview page has been shown.">
-         Show original
-      </message>
-      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES" desc="The desciption stating how old a preview version of a page is in minutes. This is shown on the infobar notifying the user that a preview page has been shown. The number of minutes will always be at least two so 'minutes' should be translated in the plural.">
+      <!-- Preview Stale Page UI -->
+      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES" desc="The desciption stating how old a preview version of a page is in minutes. This is shown on the UI notifying the user that a preview page has been shown. The number of minutes will always be at least two so 'minutes' should be translated in the plural.">
          Updated <ph name="MINUTES">$1<ex>30</ex></ph> min ago
       </message>
-      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_ONE_HOUR" desc="The desciption stating a preview version of a page is one hour old. This is shown on the infobar notifying the user that a preview page has been shown.">
+      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_ONE_HOUR" desc="The desciption stating a preview version of a page is one hour old. This is shown on the UI notifying the user that a preview page has been shown.">
          Updated 1hr ago
       </message>
-      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_HOURS" desc="The desciption stating how old a preview version of a page is in hours. This is shown on the infobar notifying the user that a preview page has been shown.">
+      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_HOURS" desc="The desciption stating how old a preview version of a page is in hours. This is shown on the UI notifying the user that a preview page has been shown.">
          Updated <ph name="HOURS">$1<ex>4</ex></ph> hrs ago
       </message>
-      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_UPDATED_NOW" desc="The desciption stating that a preview version of a page was just updated. This is shown on the infobar notifying the user that a preview page has been shown.">
+      <message name="IDS_PREVIEWS_INFOBAR_TIMESTAMP_UPDATED_NOW" desc="The desciption stating that a preview version of a page was just updated. This is shown on the UI notifying the user that a preview page has been shown.">
          Updated just now
       </message>
 
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index f88cc98..f1a980ced 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -57,7 +57,7 @@
     Google Chrome may use web services to improve your browsing experience. You may optionally disable these services. <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
   </message>
   <message name="IDS_SETTINGS_SPELLING_DESCRIPTION_UNIFIED_CONSENT" desc="Description of using a web serviced to help resolve spelling errors. It is important to convey that what the user types will be sent to Google.">
-    To fix spelling errors, Chrome sends the text you type in text fields to Google
+    To fix spelling errors, Chrome sends the text you type in the browser to Google
   </message>
   <message name="IDS_SETTINGS_RESTART_TO_APPLY_CHANGES" desc="Description in the snackbar to restart Chrome and apply changes.">
     To apply your changes, relaunch Chrome
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f1a55bc..3d12ebde 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1324,8 +1324,6 @@
     "previews/previews_content_util.cc",
     "previews/previews_content_util.h",
     "previews/previews_https_notification_infobar_decider.h",
-    "previews/previews_infobar_delegate.cc",
-    "previews/previews_infobar_delegate.h",
     "previews/previews_lite_page_decider.cc",
     "previews/previews_lite_page_decider.h",
     "previews/previews_lite_page_infobar_delegate.cc",
diff --git a/chrome/browser/badging/badge_service_impl.cc b/chrome/browser/badging/badge_service_impl.cc
index fc0ccf6c..f74851d2 100644
--- a/chrome/browser/badging/badge_service_impl.cc
+++ b/chrome/browser/badging/badge_service_impl.cc
@@ -80,8 +80,10 @@
 }
 
 bool BadgeServiceImpl::IsInApp() {
-  web_app::AppBrowserController* app_controller =
-      chrome::FindBrowserWithWebContents(web_contents_)->app_controller();
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
+  if (!browser)
+    return false;
+  web_app::AppBrowserController* app_controller = browser->app_controller();
   return app_controller &&
          extensions::IsSameScope(app_controller->GetAppLaunchURL(),
                                  web_contents_->GetLastCommittedURL(),
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index ec92b3c..4b5b363 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -343,6 +343,9 @@
 }
 
 void AppLaunchController::CleanUp() {
+  DCHECK(!cleaned_up_);
+  cleaned_up_ = true;
+
   ClearNetworkWaitTimer();
   kiosk_profile_loader_.reset();
   startup_app_launcher_.reset();
@@ -371,6 +374,9 @@
 }
 
 void AppLaunchController::OnAppWindowCreated() {
+  if (cleaned_up_)
+    return;
+
   SYSLOG(INFO) << "App window created, closing splash screen.";
   CleanUp();
 }
@@ -528,6 +534,9 @@
 }
 
 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
+  if (cleaned_up_)
+    return;
+
   DCHECK_NE(KioskAppLaunchError::NONE, error);
   SYSLOG(ERROR) << "Kiosk launch failed, error=" << error;
 
diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h
index e014080..e2ddc7f1 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.h
+++ b/chrome/browser/chromeos/login/app_launch_controller.h
@@ -139,6 +139,7 @@
   content::NotificationRegistrar registrar_;
   bool login_screen_visible_ = false;
   bool launcher_ready_ = false;
+  bool cleaned_up_ = false;
 
   // A timer to ensure the app splash is shown for a minimum amount of time.
   base::OneShotTimer splash_wait_timer_;
diff --git a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
index 68511bf..661c61a0 100644
--- a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
+++ b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
@@ -169,8 +169,7 @@
   back_->set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON |
                                      ui::EF_MIDDLE_MOUSE_BUTTON);
   back_->set_tag(IDC_BACK);
-  back_->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
-                           views::ImageButton::ALIGN_TOP);
+  back_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_RIGHT);
   back_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK));
   back_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK));
   back_->SetID(VIEW_ID_BACK_BUTTON);
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index 0265663..fc1fd89a 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -21,6 +21,7 @@
 #include "chromeos/dbus/image_loader_client.h"
 #include "components/component_updater/component_updater_paths.h"
 #include "components/crx_file/id_util.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/sha2.h"
 
@@ -61,6 +62,13 @@
 // TODO(xiaochu): add metrics for component usage (https://crbug.com/793052).
 void LogCustomUninstall(base::Optional<bool> result) {}
 
+void FinishCustomUninstallOnUIThread(const std::string& name) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  chromeos::DBusThreadManager::Get()->GetImageLoaderClient()->UnmountComponent(
+      name, base::BindOnce(&LogCustomUninstall));
+}
+
 std::string GenerateId(const std::string& sha2hashstr) {
   // kIdSize is the count of a pair of hex in the sha2hash array.
   // In string representation of sha2hash, size is doubled since each hex is
@@ -144,8 +152,9 @@
 void CrOSComponentInstallerPolicy::OnCustomUninstall() {
   cros_component_installer_->UnregisterCompatiblePath(name_);
 
-  chromeos::DBusThreadManager::Get()->GetImageLoaderClient()->UnmountComponent(
-      name_, base::BindOnce(&LogCustomUninstall));
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&FinishCustomUninstallOnUIThread, name_));
 }
 
 void CrOSComponentInstallerPolicy::ComponentReady(
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_io_data.cc
index d77e4c6d..58080f9 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_io_data.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_io_data.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/previews/previews_infobar_delegate.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
@@ -19,7 +18,6 @@
 #include "chrome/common/channel_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/data_reduction_proxy/content/browser/content_lofi_decider.h"
-#include "components/data_reduction_proxy/content/browser/content_lofi_ui_service.h"
 #include "components/data_reduction_proxy/content/browser/content_resource_type_provider.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
@@ -39,51 +37,6 @@
 class BrowserContext;
 }
 
-namespace {
-
-// Adds the preview navigation to the black list.
-void AddPreviewNavigationToBlackListCallback(
-    content::BrowserContext* browser_context,
-    const GURL& url,
-    previews::PreviewsType type,
-    uint64_t page_id,
-    bool opt_out) {
-  PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(browser_context));
-  if (previews_service && previews_service->previews_ui_service()) {
-    previews_service->previews_ui_service()->AddPreviewNavigation(
-        url, type, opt_out, page_id);
-  }
-}
-
-// If this is the first Lo-Fi response for a page load, a
-// PreviewsInfoBarDelegate is created, which handles showing Lo-Fi UI.
-void OnLoFiResponseReceivedOnUI(content::WebContents* web_contents) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  PreviewsUITabHelper* ui_tab_helper =
-      PreviewsUITabHelper::FromWebContents(web_contents);
-
-  if (!ui_tab_helper)
-    return;
-
-  uint64_t page_id = 0;
-  if (ui_tab_helper && ui_tab_helper->previews_user_data()) {
-    page_id = ui_tab_helper->previews_user_data()->page_id();
-  }
-
-  ui_tab_helper->ShowUIElement(
-      previews::PreviewsType::LOFI, true /* is_data_saver_user */,
-      base::BindOnce(&AddPreviewNavigationToBlackListCallback,
-                     web_contents->GetBrowserContext(),
-                     web_contents->GetController()
-                         .GetLastCommittedEntry()
-                         ->GetRedirectChain()[0],
-                     previews::PreviewsType::LOFI, page_id));
-}
-
-}  // namespace
-
 std::unique_ptr<data_reduction_proxy::DataReductionProxyIOData>
 CreateDataReductionProxyChromeIOData(
     Profile* profile,
@@ -108,9 +61,6 @@
       std::make_unique<data_reduction_proxy::ContentLoFiDecider>());
   data_reduction_proxy_io_data->set_resource_type_provider(
       std::make_unique<data_reduction_proxy::ContentResourceTypeProvider>());
-  data_reduction_proxy_io_data->set_lofi_ui_service(
-      std::make_unique<data_reduction_proxy::ContentLoFiUIService>(
-          ui_task_runner, base::Bind(&OnLoFiResponseReceivedOnUI)));
 
   return data_reduction_proxy_io_data;
 }
diff --git a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
index 831b2dd..5c76287 100644
--- a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
+++ b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
@@ -25,6 +25,8 @@
 #include "ui/base/webui/web_ui_util.h"
 
 #if defined(OS_CHROMEOS)
+#include "base/strings/string_split.h"
+#include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/system_logs/iwlwifi_dump_log_source.h"
 #include "chrome/browser/chromeos/system_logs/single_debug_daemon_log_source.h"
@@ -32,6 +34,8 @@
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/kiosk_next_shell_client.h"
+#include "components/feedback/feedback_util.h"
 #include "components/feedback/system_logs/system_logs_source.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
@@ -213,6 +217,25 @@
       ->component_loader()
       ->Remove(extension_misc::kFeedbackExtensionId);
 }
+
+api::feedback_private::LandingPageType
+ChromeFeedbackPrivateDelegate::GetLandingPageType(
+    const feedback::FeedbackData& feedback_data) const {
+  if (KioskNextShellClient::Get() &&
+      KioskNextShellClient::Get()->has_launched()) {
+    return api::feedback_private::LANDING_PAGE_TYPE_NOLANDINGPAGE;
+  }
+
+  // Googlers using eve get a custom landing page.
+  if (!feedback_util::IsGoogleEmail(feedback_data.user_email()))
+    return api::feedback_private::LANDING_PAGE_TYPE_NORMAL;
+
+  const std::vector<std::string> board =
+      base::SplitString(base::SysInfo::GetLsbReleaseBoard(), "-",
+                        base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  return board[0] == "eve" ? api::feedback_private::LANDING_PAGE_TYPE_TECHSTOP
+                           : api::feedback_private::LANDING_PAGE_TYPE_NORMAL;
+}
 #endif  // defined(OS_CHROMEOS)
 
 std::string ChromeFeedbackPrivateDelegate::GetSignedInUserEmail(
diff --git a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h
index 2469dad..63b7db75 100644
--- a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h
+++ b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h
@@ -29,6 +29,8 @@
   void FetchExtraLogs(scoped_refptr<feedback::FeedbackData> feedback_data,
                       FetchExtraLogsCallback callback) const override;
   void UnloadFeedbackExtension(content::BrowserContext* context) const override;
+  api::feedback_private::LandingPageType GetLandingPageType(
+      const feedback::FeedbackData& feedback_data) const override;
 #endif  // defined(OS_CHROMEOS)
   std::string GetSignedInUserEmail(
       content::BrowserContext* context) const override;
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc
index e0c76240..89944c3 100644
--- a/chrome/browser/feedback/show_feedback_page.cc
+++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/feedback/feedback_util.h"
 #include "extensions/browser/api/feedback_private/feedback_private_api.h"
 
 #if defined(OS_CHROMEOS)
@@ -26,8 +27,6 @@
 namespace {
 
 #if defined(OS_CHROMEOS)
-constexpr char kGoogleDotCom[] = "@google.com";
-
 // Returns if the feedback page is considered to be triggered from user
 // interaction.
 bool IsFromUserInteraction(FeedbackSource source) {
@@ -44,7 +43,8 @@
   }
 }
 #endif
-}
+
+}  // namespace
 
 void ShowFeedbackPage(Browser* browser,
                       FeedbackSource source,
@@ -80,8 +80,8 @@
 #if defined(OS_CHROMEOS)
   auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
   if (identity_manager &&
-      base::EndsWith(identity_manager->GetPrimaryAccountInfo().email,
-                     kGoogleDotCom, base::CompareCase::INSENSITIVE_ASCII)) {
+      feedback_util::IsGoogleEmail(
+          identity_manager->GetPrimaryAccountInfo().email)) {
     flow = feedback_private::FeedbackFlow::FEEDBACK_FLOW_GOOGLEINTERNAL;
     include_bluetooth_logs = IsFromUserInteraction(source);
   }
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index caa1061..d14243c 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/plugins/plugin_metadata.h"
 #include "chrome/browser/plugins/plugin_observer.h"
 #include "chrome/browser/plugins/reload_plugin_infobar_delegate.h"
-#include "chrome/browser/previews/previews_infobar_delegate.h"
 #include "chrome/browser/previews/previews_lite_page_infobar_delegate.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_service.h"
@@ -229,8 +228,6 @@
       {"obsolete_system", IBD::OBSOLETE_SYSTEM_INFOBAR_DELEGATE},
       {"page_info", IBD::PAGE_INFO_INFOBAR_DELEGATE},
       {"translate", IBD::TRANSLATE_INFOBAR_DELEGATE_NON_AURA},
-      {"data_reduction_proxy_preview",
-       IBD::DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE},
       {"automation", IBD::AUTOMATION_INFOBAR_DELEGATE},
       {"previews_lite_page", IBD::LITE_PAGE_PREVIEWS_INFOBAR},
       {"flash_deprecation", IBD::FLASH_DEPRECATION_INFOBAR_DELEGATE},
@@ -403,11 +400,6 @@
       break;
     }
 
-    case IBD::DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE:
-      PreviewsInfoBarDelegate::Create(
-          GetWebContents(), previews::PreviewsType::LOFI, true, nullptr);
-      break;
-
     case IBD::AUTOMATION_INFOBAR_DELEGATE:
       AutomationInfoBarDelegate::Create();
       break;
@@ -572,10 +564,6 @@
 }
 #endif
 
-IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_data_reduction_proxy_preview) {
-  ShowAndVerifyUi();
-}
-
 IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_automation) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/local_discovery/service_discovery_client_mdns.cc b/chrome/browser/local_discovery/service_discovery_client_mdns.cc
index 2b3a4f5b..78820fb 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mdns.cc
+++ b/chrome/browser/local_discovery/service_discovery_client_mdns.cc
@@ -17,7 +17,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/local_discovery/service_discovery_client_impl.h"
-#include "components/net_log/chrome_net_log.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
@@ -127,9 +126,8 @@
 
 class SocketFactory : public net::MDnsSocketFactory {
  public:
-  SocketFactory(const net::InterfaceIndexFamilyList& interfaces,
-                net::NetLog* net_log)
-      : interfaces_(interfaces), net_log_(net_log) {}
+  explicit SocketFactory(const net::InterfaceIndexFamilyList& interfaces)
+      : interfaces_(interfaces) {}
 
   // net::MDnsSocketFactory implementation:
   void CreateSockets(std::vector<std::unique_ptr<net::DatagramServerSocket>>*
@@ -138,7 +136,7 @@
       DCHECK(interfaces_[i].second == net::ADDRESS_FAMILY_IPV4 ||
              interfaces_[i].second == net::ADDRESS_FAMILY_IPV6);
       std::unique_ptr<net::DatagramServerSocket> socket(CreateAndBindMDnsSocket(
-          interfaces_[i].second, interfaces_[i].first, net_log_));
+          interfaces_[i].second, interfaces_[i].first, nullptr /* net_log */));
       if (socket)
         sockets->push_back(std::move(socket));
     }
@@ -147,15 +145,13 @@
  private:
   net::InterfaceIndexFamilyList interfaces_;
 
-  // Owned by |g_browser_process|.
-  net::NetLog* const net_log_;
+  DISALLOW_COPY_AND_ASSIGN(SocketFactory);
 };
 
 void InitMdns(const MdnsInitCallback& on_initialized,
               const net::InterfaceIndexFamilyList& interfaces,
-              net::MDnsClient* mdns,
-              net::NetLog* net_log) {
-  SocketFactory socket_factory(interfaces, net_log);
+              net::MDnsClient* mdns) {
+  SocketFactory socket_factory(interfaces);
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
       base::BindOnce(on_initialized, mdns->StartListening(&socket_factory)));
@@ -425,8 +421,7 @@
       base::BindOnce(&InitMdns,
                      base::Bind(&ServiceDiscoveryClientMdns::OnMdnsInitialized,
                                 weak_ptr_factory_.GetWeakPtr()),
-                     interfaces, base::Unretained(mdns_.get()),
-                     g_browser_process->net_log()));
+                     interfaces, base::Unretained(mdns_.get())));
 }
 
 void ServiceDiscoveryClientMdns::OnMdnsInitialized(int net_error) {
diff --git a/chrome/browser/media/media_engagement_autoplay_browsertest.cc b/chrome/browser/media/media_engagement_autoplay_browsertest.cc
index b9920a0..01375f2 100644
--- a/chrome/browser/media/media_engagement_autoplay_browsertest.cc
+++ b/chrome/browser/media/media_engagement_autoplay_browsertest.cc
@@ -367,16 +367,6 @@
   ExpectAutoplayAllowedIfEnabled();
 }
 
-IN_PROC_BROWSER_TEST_P(MediaEngagementAutoplayBrowserTest,
-                       BypassAutoplayHighEngagement_HTTPSOnly) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(media::kMediaEngagementHTTPSOnly);
-
-  SetScores(PrimaryOrigin(), 20, 20);
-  LoadTestPage("engagement_autoplay_test.html");
-  ExpectAutoplayDenied();
-}
-
 INSTANTIATE_TEST_SUITE_P(/* no prefix */,
                          MediaEngagementAutoplayBrowserTest,
                          testing::Bool());
diff --git a/chrome/browser/media/media_engagement_contents_observer.cc b/chrome/browser/media/media_engagement_contents_observer.cc
index d637ecd1..0814fc74 100644
--- a/chrome/browser/media/media_engagement_contents_observer.cc
+++ b/chrome/browser/media/media_engagement_contents_observer.cc
@@ -581,9 +581,6 @@
   MediaEngagementScore score = service_->CreateEngagementScore(origin);
   bool has_high_engagement = score.high_score();
 
-  if (base::FeatureList::IsEnabled(media::kMediaEngagementHTTPSOnly))
-    DCHECK(!has_high_engagement || (origin.scheme() == url::kHttpsScheme));
-
   // If the preloaded feature flag is enabled and the number of visits is less
   // than the number of visits required to have an MEI score we should check the
   // global data.
diff --git a/chrome/browser/media/media_engagement_score.cc b/chrome/browser/media/media_engagement_score.cc
index b7ecfac..6b889bc 100644
--- a/chrome/browser/media/media_engagement_score.cc
+++ b/chrome/browser/media/media_engagement_score.cc
@@ -109,13 +109,6 @@
   if (!score_dict_)
     return;
 
-  // This is to prevent using previously saved data to mark an HTTP website as
-  // allowed to autoplay.
-  if (base::FeatureList::IsEnabled(media::kMediaEngagementHTTPSOnly) &&
-      origin_.scheme() != url::kHttpsScheme) {
-    return;
-  }
-
   GetIntegerFromScore(score_dict_.get(), kVisitsKey, &visits_);
   GetIntegerFromScore(score_dict_.get(), kMediaPlaybacksKey, &media_playbacks_);
   GetIntegerFromScore(score_dict_.get(), kAudiblePlaybacksKey,
@@ -216,12 +209,6 @@
   if (!score_dict_)
     return false;
 
-  // This is to prevent saving data that we would otherwise not use.
-  if (base::FeatureList::IsEnabled(media::kMediaEngagementHTTPSOnly) &&
-      origin_.scheme() != url::kHttpsScheme) {
-    return false;
-  }
-
   if (base::Value* value = score_dict_->FindKeyOfType(
           kHasHighScoreKey, base::Value::Type::BOOLEAN)) {
     is_high = value->GetBool();
diff --git a/chrome/browser/media/media_engagement_score_details.mojom b/chrome/browser/media/media_engagement_score_details.mojom
index 342c65c..2f1ec13 100644
--- a/chrome/browser/media/media_engagement_score_details.mojom
+++ b/chrome/browser/media/media_engagement_score_details.mojom
@@ -46,7 +46,6 @@
   bool feature_record_data;
   bool feature_bypass_autoplay;
   bool feature_preload_data;
-  bool feature_https_only;
   bool feature_autoplay_disable_settings;
   bool feature_autoplay_whitelist_settings;
   bool pref_disable_unified_autoplay;
diff --git a/chrome/browser/media/media_engagement_score_unittest.cc b/chrome/browser/media/media_engagement_score_unittest.cc
index 0e85003..a20c41e 100644
--- a/chrome/browser/media/media_engagement_score_unittest.cc
+++ b/chrome/browser/media/media_engagement_score_unittest.cc
@@ -108,8 +108,7 @@
       int visits_with_media_tag,
       int high_score_changes,
       int media_element_playbacks,
-      int audio_context_playbacks,
-      bool update_score_expectation) {
+      int audio_context_playbacks) {
     MediaEngagementScore* initial_score =
         new MediaEngagementScore(&test_clock, url::Origin(),
                                  std::move(score_dict), nullptr /* settings */);
@@ -125,7 +124,7 @@
 
     // Increment the scores and check that the values were stored correctly.
     UpdateScore(initial_score);
-    EXPECT_EQ(update_score_expectation, initial_score->UpdateScoreDict());
+    EXPECT_TRUE(initial_score->UpdateScoreDict());
     delete initial_score;
   }
 
@@ -202,7 +201,7 @@
 TEST_F(MediaEngagementScoreTest, EmptyDictionary) {
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
   TestScoreInitializesAndUpdates(std::move(dict), 0, 0, base::Time(), false, 0,
-                                 0, 0, 0, 0, 0, true);
+                                 0, 0, 0, 0, 0);
 }
 
 // Test that scores are read / written correctly from / to partially empty
@@ -212,7 +211,7 @@
   dict->SetInteger(MediaEngagementScore::kVisitsKey, 2);
 
   TestScoreInitializesAndUpdates(std::move(dict), 2, 0, base::Time(), false, 0,
-                                 0, 0, 0, 0, 0, true);
+                                 0, 0, 0, 0, 0);
 }
 
 // Test that scores are read / written correctly from / to populated score
@@ -233,7 +232,7 @@
                    2);
 
   TestScoreInitializesAndUpdates(std::move(dict), 20, 12, test_clock.Now(),
-                                 true, 2, 4, 6, 3, 1, 2, true);
+                                 true, 2, 4, 6, 3, 1, 2);
 }
 
 // Test getting and commiting the score works correctly with different
@@ -723,27 +722,3 @@
     EXPECT_EQ(media_element_playbacks, stored_media_element_playbacks);
   }
 }
-
-// Test that scores are read / written correctly from / to populated score
-// dictionaries.
-TEST_F(MediaEngagementScoreTest, PopulatedDictionary_HTTPSOnly) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(media::kMediaEngagementHTTPSOnly);
-
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetInteger(MediaEngagementScore::kVisitsKey, 20);
-  dict->SetInteger(MediaEngagementScore::kMediaPlaybacksKey, 12);
-  dict->SetDouble(MediaEngagementScore::kLastMediaPlaybackTimeKey,
-                  test_clock.Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
-  dict->SetBoolean(MediaEngagementScore::kHasHighScoreKey, true);
-  dict->SetInteger(MediaEngagementScore::kAudiblePlaybacksKey, 2);
-  dict->SetInteger(MediaEngagementScore::kSignificantPlaybacksKey, 4);
-  dict->SetInteger(MediaEngagementScore::kVisitsWithMediaTagKey, 6);
-  dict->SetInteger(MediaEngagementScore::kHighScoreChanges, 3);
-  dict->SetInteger(MediaEngagementScore::kSignificantMediaPlaybacksKey, 1);
-  dict->SetInteger(MediaEngagementScore::kSignificantAudioContextPlaybacksKey,
-                   2);
-
-  TestScoreInitializesAndUpdates(std::move(dict), 0, 0, base::Time(), false, 0,
-                                 0, 0, 0, 0, 0, false);
-}
diff --git a/chrome/browser/media/media_engagement_service.cc b/chrome/browser/media/media_engagement_service.cc
index 7383f18..3c2a0a6 100644
--- a/chrome/browser/media/media_engagement_service.cc
+++ b/chrome/browser/media/media_engagement_service.cc
@@ -330,9 +330,6 @@
 
 bool MediaEngagementService::ShouldRecordEngagement(
     const url::Origin& origin) const {
-  if (base::FeatureList::IsEnabled(media::kMediaEngagementHTTPSOnly))
-    return origin.scheme() == url::kHttpsScheme;
-
   return (origin.scheme() == url::kHttpsScheme ||
           origin.scheme() == url::kHttpScheme);
 }
@@ -361,11 +358,6 @@
       continue;
     }
 
-    if (base::FeatureList::IsEnabled(media::kMediaEngagementHTTPSOnly) &&
-        origin.scheme() != url::kHttpsScheme) {
-      continue;
-    }
-
     const auto& result = filtered_results.find(origin);
     if (result != filtered_results.end()) {
       DCHECK(result->second->incognito && !site.incognito);
diff --git a/chrome/browser/media/media_engagement_service_unittest.cc b/chrome/browser/media/media_engagement_service_unittest.cc
index c592853..d2e5797 100644
--- a/chrome/browser/media/media_engagement_service_unittest.cc
+++ b/chrome/browser/media/media_engagement_service_unittest.cc
@@ -283,55 +283,27 @@
   EXPECT_EQ(0u, GetAllScoreDetails().size());
 
   RecordVisitAndPlaybackAndAdvanceClock(
-      url::Origin::Create(GURL("http://www.example.com")));
-  RecordVisitAndPlaybackAndAdvanceClock(
-      url::Origin::Create(GURL("https://www.example.com")));
-  EXPECT_EQ(2u, GetAllScoreDetails().size());
-}
-
-TEST_F(MediaEngagementServiceTest, MojoSerialization_HTTPSOnly) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(media::kMediaEngagementHTTPSOnly);
-
-  EXPECT_EQ(0u, GetAllScoreDetails().size());
-
-  RecordVisitAndPlaybackAndAdvanceClock(
-      url::Origin::Create(GURL("http://www.example.com")));
-  RecordVisitAndPlaybackAndAdvanceClock(
-      url::Origin::Create(GURL("https://www.example.com")));
+      url::Origin::Create(GURL("https://www.google.com")));
   EXPECT_EQ(1u, GetAllScoreDetails().size());
 }
 
 TEST_F(MediaEngagementServiceTest, RestrictedToHTTPAndHTTPS) {
-  std::vector<url::Origin> origins = {
-      url::Origin::Create(GURL("ftp://www.google.com/")),
-      url::Origin::Create(GURL("file://blah")),
-      url::Origin::Create(GURL("chrome://")),
-      url::Origin::Create(GURL("about://config")),
-  };
+  url::Origin origin1 = url::Origin::Create(GURL("ftp://www.google.com/"));
+  url::Origin origin2 = url::Origin::Create(GURL("file://blah"));
+  url::Origin origin3 = url::Origin::Create(GURL("chrome://"));
+  url::Origin origin4 = url::Origin::Create(GURL("about://config"));
 
-  for (const url::Origin& origin : origins) {
-    RecordVisitAndPlaybackAndAdvanceClock(origin);
-    ExpectScores(origin, 0.0, 0, 0, TimeNotSet());
-  }
-}
+  RecordVisitAndPlaybackAndAdvanceClock(origin1);
+  ExpectScores(origin1, 0.0, 0, 0, TimeNotSet());
 
-TEST_F(MediaEngagementServiceTest, RestrictedToHTTPS) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(media::kMediaEngagementHTTPSOnly);
+  RecordVisitAndPlaybackAndAdvanceClock(origin2);
+  ExpectScores(origin2, 0.0, 0, 0, TimeNotSet());
 
-  std::vector<url::Origin> origins = {
-      url::Origin::Create(GURL("ftp://www.google.com/")),
-      url::Origin::Create(GURL("file://blah")),
-      url::Origin::Create(GURL("chrome://")),
-      url::Origin::Create(GURL("about://config")),
-      url::Origin::Create(GURL("http://example.com")),
-  };
+  RecordVisitAndPlaybackAndAdvanceClock(origin4);
+  ExpectScores(origin4, 0.0, 0, 0, TimeNotSet());
 
-  for (const url::Origin& origin : origins) {
-    RecordVisitAndPlaybackAndAdvanceClock(origin);
-    ExpectScores(origin, 0.0, 0, 0, TimeNotSet());
-  }
+  RecordVisitAndPlaybackAndAdvanceClock(origin4);
+  ExpectScores(origin4, 0.0, 0, 0, TimeNotSet());
 }
 
 TEST_F(MediaEngagementServiceTest,
diff --git a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
index 3fd7a07..75f40bc 100644
--- a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
@@ -231,8 +231,10 @@
     builder.Setresource_loading_hints(1);
   if (offline_preview_seen_)
     builder.Setoffline_preview(1);
+  // 2 is set here for legacy reasons as it denotes an optout through the
+  // omnibox ui as opposed to the now deprecated infobar.
   if (opt_out_occurred_)
-    builder.Setopt_out(previews::params::IsPreviewsOmniboxUiEnabled() ? 2 : 1);
+    builder.Setopt_out(2);
   if (origin_opt_out_occurred_)
     builder.Setorigin_opt_out(1);
   if (save_data_enabled_)
diff --git a/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc
index be26e3a..f7cc229 100644
--- a/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc
@@ -442,42 +442,7 @@
               base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, LitePageOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
-          PreviewsType::LITE_PAGE, true /* lite_page_received */,
-          false /* lite_page_redirect_received */, false /* noscript_on */,
-          false /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-
-  ValidateUKM(false /* server_lofi_expected */,
-              false /* client_lofi_expected */, true /* lite_page_expected */,
-              false /* lite_page_redirect_expected */,
-              false /* noscript_expected */,
-              false /* resource_loading_hints_expected */,
-              1 /* opt_out_value */, false /* origin_opt_out_expected */,
-              false /* save_data_enabled_expected */,
-              false /* offline_preview_expected */, false /* previews_likely */,
-              CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-              base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, LitePageOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
           PreviewsType::LITE_PAGE, true /* lite_page_received */,
           false /* lite_page_redirect_received */, false /* noscript_on */,
@@ -524,42 +489,7 @@
               base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, LitePageRedirectOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
-          PreviewsType::LITE_PAGE_REDIRECT, false /* lite_page_received */,
-          true /* lite_page_redirect_received */, false /* noscript_on */,
-          false /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-
-  ValidateUKM(false /* server_lofi_expected */,
-              false /* client_lofi_expected */, false /* lite_page_expected */,
-              true /* lite_page_redirect_expected */,
-              false /* noscript_expected */,
-              false /* resource_loading_hints_expected */,
-              1 /* opt_out_value */, false /* origin_opt_out_expected */,
-              false /* save_data_enabled_expected */,
-              false /* offline_preview_expected */, false /* previews_likely */,
-              CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-              base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, LitePageRedirectOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
           PreviewsType::LITE_PAGE_REDIRECT, false /* lite_page_received */,
           true /* lite_page_redirect_received */, false /* noscript_on */,
@@ -605,41 +535,7 @@
       base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, NoScriptOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
-          PreviewsType::NOSCRIPT, false /* lite_page_received */,
-          false /* lite_page_redirect_received */, true /* noscript_on */,
-          false /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-
-  ValidateUKM(
-      false /* server_lofi_expected */, false /* client_lofi_expected */,
-      false /* lite_page_expected */, false /* lite_page_redirect_expected */,
-      true /* noscript_expected */, false /* resource_loading_hints_expected */,
-      1 /* opt_out_value */, false /* origin_opt_out_expected */,
-      false /* save_data_enabled_expected */,
-      false /* offline_preview_expected */, false /* previews_likely */,
-      CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-      base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, NoScriptOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
           PreviewsType::NOSCRIPT, false /* lite_page_received */,
           false /* lite_page_redirect_received */, true /* noscript_on */,
@@ -707,41 +603,7 @@
       base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, ResourceLoadingHintsOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
-          PreviewsType::RESOURCE_LOADING_HINTS, false /* lite_page_received */,
-          false /* lite_page_redirect_received */, false /* noscript_on */,
-          true /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-
-  ValidateUKM(
-      false /* server_lofi_expected */, false /* client_lofi_expected */,
-      false /* lite_page_expected */, false /* lite_page_redirect_expected */,
-      false /* noscript_expected */, true /* resource_loading_hints_expected */,
-      1 /* opt_out_value */, false /* origin_opt_out_expected */,
-      false /* save_data_enabled_expected */,
-      false /* offline_preview_expected */, false /* previews_likely */,
-      CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-      base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, ResourceLoadingHintsOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */,
           PreviewsType::RESOURCE_LOADING_HINTS, false /* lite_page_received */,
           false /* lite_page_redirect_received */, false /* noscript_on */,
@@ -809,63 +671,7 @@
               base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, ClientLoFiOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */, PreviewsType::LOFI,
-          false /* lite_page_received */,
-          false /* lite_page_redirect_received */, false /* noscript_on */,
-          false /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data =
-      std::make_unique<data_reduction_proxy::DataReductionProxyData>();
-  data->set_client_lofi_requested(true);
-
-  // Prepare 3 resources of varying size and configurations, 2 of which have
-  // client LoFi set.
-  page_load_metrics::ExtraRequestCompleteInfo resources[] = {
-      {GURL(kDefaultTestUrl), net::IPEndPoint(), -1, false /*was_cached*/,
-       1024 * 40 /* raw_body_bytes */,
-       1024 * 40 * 5 /* original_network_content_length */, std::move(data),
-       content::ResourceType::kImage, 0, nullptr /* load_timing_info */},
-      // Uncached non-proxied request.
-      {GURL(kDefaultTestUrl), net::IPEndPoint(), -1, false /*was_cached*/,
-       1024 * 40 /* raw_body_bytes */,
-       1024 * 40 /* original_network_content_length */,
-       nullptr /* data_reduction_proxy_data */, content::ResourceType::kImage,
-       0, nullptr /* load_timing_info */},
-  };
-
-  for (const auto& request : resources)
-    SimulateLoadedResource(request);
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-
-  ValidateUKM(false /* server_lofi_expected */, true /* client_lofi_expected */,
-              false /* lite_page_expected */,
-              false /* lite_page_redirect_expected */,
-              false /* noscript_expected */,
-              false /* resource_loading_hints_expected */,
-              1 /* opt_out_value */, false /* origin_opt_out_expected */,
-              false /* save_data_enabled_expected */,
-              false /* offline_preview_expected */, false /* previews_likely */,
-              CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-              base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, ClientLoFiOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */, PreviewsType::LOFI,
           false /* lite_page_received */,
           false /* lite_page_redirect_received */, false /* noscript_on */,
@@ -955,64 +761,7 @@
               base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, ServerLoFiOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */, PreviewsType::LOFI,
-          false /* lite_page_received */,
-          false /* lite_page_redirect_received */, false /* noscript_on */,
-          false /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data =
-      std::make_unique<data_reduction_proxy::DataReductionProxyData>();
-  data->set_used_data_reduction_proxy(true);
-  data->set_lofi_received(true);
-
-  // Prepare 3 resources of varying size and configurations, 2 of which have
-  // client LoFi set.
-  page_load_metrics::ExtraRequestCompleteInfo resources[] = {
-      {GURL(kDefaultTestUrl), net::IPEndPoint(), -1, false /*was_cached*/,
-       1024 * 40 /* raw_body_bytes */,
-       1024 * 40 * 5 /* original_network_content_length */, std::move(data),
-       content::ResourceType::kImage, 0, nullptr /* load_timing_info */},
-      {GURL(kDefaultTestUrl), net::IPEndPoint(), -1, false /*was_cached*/,
-       1024 * 40 /* raw_body_bytes */,
-       1024 * 40 /* original_network_content_length */,
-       nullptr /* data_reduction_proxy_data */, content::ResourceType::kImage,
-       0, nullptr /* load_timing_info */},
-  };
-
-  for (const auto& request : resources)
-    SimulateLoadedResource(request);
-
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-
-  ValidateUKM(true /* server_lofi_expected */, false /* client_lofi_expected */,
-              false /* lite_page_expected */,
-              false /* lite_page_redirect_expected */,
-              false /* noscript_expected */,
-              false /* resource_loading_hints_expected */,
-              1 /* opt_out_value */, false /* origin_opt_out_expected */,
-              false /* save_data_enabled_expected */,
-              false /* offline_preview_expected */, false /* previews_likely */,
-              CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-              base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, ServerLoFiOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */, PreviewsType::LOFI,
           false /* lite_page_received */,
           false /* lite_page_redirect_received */, false /* noscript_on */,
@@ -1108,68 +857,7 @@
               base::nullopt /* navigation_restart_penalty */);
 }
 
-TEST_F(PreviewsUKMObserverTest, BothLoFiOptOut) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {} /* enabled features */,
-      {previews::features::
-           kAndroidOmniboxPreviewsBadge} /* disabled features */);
-
-  RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */, PreviewsType::LOFI,
-          false /* lite_page_received */,
-          false /* lite_page_redirect_received */, false /* noscript_on */,
-          false /* resource_loading_hints_on */, false /* origin_opt_out */,
-          false /* save_data_enabled */, false /* is_offline_preview */,
-          CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-          base::nullopt /* navigation_restart_penalty */);
-
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data1 =
-      std::make_unique<data_reduction_proxy::DataReductionProxyData>();
-  data1->set_used_data_reduction_proxy(true);
-  data1->set_lofi_received(true);
-
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data2 =
-      std::make_unique<data_reduction_proxy::DataReductionProxyData>();
-  data2->set_used_data_reduction_proxy(true);
-  data2->set_client_lofi_requested(true);
-
-  // Prepare 4 resources of varying size and configurations, 1 has Client LoFi,
-  // 1 has Server LoFi.
-  page_load_metrics::ExtraRequestCompleteInfo resources[] = {
-      // Uncached proxied request with .1 compression ratio.
-      {GURL(kDefaultTestUrl), net::IPEndPoint(), -1, false /*was_cached*/,
-       1024 * 40 /* raw_body_bytes */,
-       1024 * 40 * 10 /* original_network_content_length */, std::move(data1),
-       content::ResourceType::kImage, 0, nullptr /* load_timing_info */},
-      // Uncached proxied request with .5 compression ratio.
-      {GURL(kDefaultTestUrl), net::IPEndPoint(), -1, false /*was_cached*/,
-       1024 * 40 /* raw_body_bytes */,
-       1024 * 40 * 5 /* original_network_content_length */, std::move(data2),
-       content::ResourceType::kImage, 0, nullptr /* load_timing_info */},
-  };
-
-  for (const auto& request : resources)
-    SimulateLoadedResource(request);
-  observer()->BroadcastEventToObservers(PreviewsUITabHelper::OptOutEventKey());
-  NavigateToUntrackedUrl();
-  ValidateUKM(true /* server_lofi_expected */, true /* client_lofi_expected */,
-              false /* lite_page_expected */,
-              false /* lite_page_redirect_expected */,
-              false /* noscript_expected */,
-              false /* resource_loading_hints_expected */,
-              1 /* opt_out_value */, false /* origin_opt_out_expected */,
-              false /* save_data_enabled_expected */,
-              false /* offline_preview_expected */, false /* previews_likely */,
-              CoinFlipHoldbackResult::kNotSet, {} /* eligibility_reasons */,
-              base::nullopt /* navigation_restart_penalty */);
-}
-
 TEST_F(PreviewsUKMObserverTest, BothLoFiOptOutChip) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kAndroidOmniboxPreviewsBadge} /* enabled features */,
-      {} /*disabled features */);
-
   RunTest(content::PREVIEWS_UNSPECIFIED /* allowed_state */, PreviewsType::LOFI,
           false /* lite_page_received */,
           false /* lite_page_redirect_received */, false /* noscript_on */,
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index d93a39be..118ee49 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -1451,6 +1451,12 @@
     return link_position;
   }
 
+  content::WebContents* GetWebContentsForInputRouting() {
+    return content::MimeHandlerViewMode::UsesCrossProcessFrame()
+               ? guest_contents_
+               : GetActiveWebContents();
+  }
+
  private:
   WebContents* guest_contents_;
 };
@@ -1463,9 +1469,9 @@
   content::WindowedNotificationObserver observer(
       chrome::NOTIFICATION_TAB_ADDED,
       content::NotificationService::AllSources());
-  content::SimulateMouseClickAt(web_contents, kDefaultKeyModifier,
-                                blink::WebMouseEvent::Button::kLeft,
-                                GetLinkPosition());
+  content::SimulateMouseClickAt(
+      GetWebContentsForInputRouting(), kDefaultKeyModifier,
+      blink::WebMouseEvent::Button::kLeft, GetLinkPosition());
   observer.Wait();
 
   int tab_count = browser()->tab_strip_model()->count();
@@ -1492,7 +1498,7 @@
   content::WindowedNotificationObserver observer(
       chrome::NOTIFICATION_TAB_ADDED,
       content::NotificationService::AllSources());
-  content::SimulateMouseClickAt(web_contents, 0,
+  content::SimulateMouseClickAt(GetWebContentsForInputRouting(), 0,
                                 blink::WebMouseEvent::Button::kMiddle,
                                 GetLinkPosition());
   observer.Wait();
@@ -1523,9 +1529,9 @@
   content::WindowedNotificationObserver observer(
       chrome::NOTIFICATION_BROWSER_OPENED,
       content::NotificationService::AllSources());
-  content::SimulateMouseClickAt(web_contents, blink::WebInputEvent::kShiftKey,
-                                blink::WebMouseEvent::Button::kLeft,
-                                GetLinkPosition());
+  content::SimulateMouseClickAt(
+      GetWebContentsForInputRouting(), blink::WebInputEvent::kShiftKey,
+      blink::WebMouseEvent::Button::kLeft, GetLinkPosition());
   observer.Wait();
 
   ASSERT_EQ(2U, chrome::GetTotalBrowserCount());
@@ -2099,6 +2105,11 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(PDFExtensionTest, MAYBE_EmbeddedPdfGetsFocus) {
+  if (content::MimeHandlerViewMode::UsesCrossProcessFrame()) {
+    // This test verifies focus for a BrowserPlugin and is not relevant with
+    // MHVICPF since no BrowserPlugin is created with this flag.
+    return;
+  }
   GURL test_iframe_url(embedded_test_server()->GetURL(
       "/pdf/test-offset-cross-site-iframe.html"));
   ui_test_utils::NavigateToURL(browser(), test_iframe_url);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index ca88397..ad8ac8e 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -713,7 +713,6 @@
   PushMessagingAppIdentifier::RegisterProfilePrefs(registry);
   RegisterBrowserUserPrefs(registry);
   safe_browsing::RegisterProfilePrefs(registry);
-  secure_origin_whitelist::RegisterPrefs(registry);
   SafeBrowsingTriggeredPopupBlocker::RegisterProfilePrefs(registry);
   SessionStartupPref::RegisterProfilePrefs(registry);
   sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc
index 911437b..7ccb55f 100644
--- a/chrome/browser/previews/previews_browsertest.cc
+++ b/chrome/browser/previews/previews_browsertest.cc
@@ -218,7 +218,7 @@
   EXPECT_FALSE(noscript_css_requested());
 
   // Verify info bar not presented via histogram check.
-  histogram_tester.ExpectTotalCount("Previews.InfoBarAction.NoScript", 0);
+  histogram_tester.ExpectTotalCount("Previews.PreviewShown.NoScript", 0);
 }
 
 // This test class enables NoScriptPreviews but without OptimizationHints.
@@ -315,7 +315,7 @@
 
   // Verify info bar presented via histogram check.
   RetryForHistogramUntilCountReached(&histogram_tester,
-                                     "Previews.InfoBarAction.NoScript", 1);
+                                     "Previews.PreviewShown.NoScript", 1);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -369,7 +369,7 @@
 
   // Verify info bar presented via histogram check.
   RetryForHistogramUntilCountReached(&histogram_tester,
-                                     "Previews.InfoBarAction.NoScript", 1);
+                                     "Previews.PreviewShown.NoScript", 1);
 }
 
 IN_PROC_BROWSER_TEST_F(
diff --git a/chrome/browser/previews/previews_infobar_delegate.cc b/chrome/browser/previews/previews_infobar_delegate.cc
deleted file mode 100644
index 61c9feb..0000000
--- a/chrome/browser/previews/previews_infobar_delegate.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/previews/previews_infobar_delegate.h"
-
-#include "base/feature_list.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/previews/previews_ui_tab_helper.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/infobars/core/infobar.h"
-#include "components/previews/content/previews_ui_service.h"
-#include "components/previews/core/previews_features.h"
-#include "components/previews/core/previews_logger.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/l10n/l10n_util.h"
-
-#if defined(OS_ANDROID)
-#include "chrome/browser/ui/android/infobars/previews_infobar.h"
-#endif
-
-namespace {
-
-static const char kPreviewInfobarEventType[] = "InfoBar";
-
-void RecordPreviewsInfoBarAction(
-    previews::PreviewsType previews_type,
-    PreviewsInfoBarDelegate::PreviewsInfoBarAction action) {
-  int32_t max_limit =
-      static_cast<int32_t>(PreviewsInfoBarDelegate::INFOBAR_INDEX_BOUNDARY);
-  base::LinearHistogram::FactoryGet(
-      base::StringPrintf("Previews.InfoBarAction.%s",
-                         GetStringNameForType(previews_type).c_str()),
-      1, max_limit, max_limit + 1,
-      base::HistogramBase::kUmaTargetedHistogramFlag)
-      ->Add(static_cast<int32_t>(action));
-}
-
-}  // namespace
-
-PreviewsInfoBarDelegate::~PreviewsInfoBarDelegate() {
-  RecordPreviewsInfoBarAction(previews_type_, infobar_dismissed_action_);
-}
-
-// static
-void PreviewsInfoBarDelegate::Create(
-    content::WebContents* web_contents,
-    previews::PreviewsType previews_type,
-    bool is_data_saver_user,
-    previews::PreviewsUIService* previews_ui_service) {
-  PreviewsUITabHelper* ui_tab_helper =
-      PreviewsUITabHelper::FromWebContents(web_contents);
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents);
-
-  // The WebContents may not have TabHelpers set. If TabHelpers are not set,
-  // don't show Previews infobars.
-  if (!ui_tab_helper || !infobar_service)
-    return;
-  if (ui_tab_helper->displayed_preview_ui())
-    return;
-
-  std::unique_ptr<PreviewsInfoBarDelegate> delegate(new PreviewsInfoBarDelegate(
-      ui_tab_helper, previews_type, is_data_saver_user));
-
-#if defined(OS_ANDROID)
-  std::unique_ptr<infobars::InfoBar> infobar_ptr(
-      PreviewsInfoBar::CreateInfoBar(infobar_service, std::move(delegate)));
-#else
-  std::unique_ptr<infobars::InfoBar> infobar_ptr(
-      infobar_service->CreateConfirmInfoBar(std::move(delegate)));
-#endif
-
-  infobar_service->AddInfoBar(std::move(infobar_ptr));
-  uint64_t page_id = (ui_tab_helper->previews_user_data())
-                         ? ui_tab_helper->previews_user_data()->page_id()
-                         : 0;
-
-  if (previews_ui_service) {
-    // Not in incognito mode or guest mode.
-    previews_ui_service->previews_logger()->LogMessage(
-        kPreviewInfobarEventType,
-        previews::GetDescriptionForInfoBarDescription(previews_type),
-        web_contents->GetController()
-            .GetLastCommittedEntry()
-            ->GetRedirectChain()[0] /* GURL */,
-        base::Time::Now(), page_id);
-  }
-
-  RecordPreviewsInfoBarAction(previews_type, INFOBAR_SHOWN);
-  ui_tab_helper->set_displayed_preview_ui(true);
-}
-
-PreviewsInfoBarDelegate::PreviewsInfoBarDelegate(
-    PreviewsUITabHelper* ui_tab_helper,
-    previews::PreviewsType previews_type,
-    bool is_data_saver_user)
-    : ConfirmInfoBarDelegate(),
-      ui_tab_helper_(ui_tab_helper),
-      previews_type_(previews_type),
-      infobar_dismissed_action_(INFOBAR_DISMISSED_BY_TAB_CLOSURE),
-      message_text_(l10n_util::GetStringUTF16(
-          is_data_saver_user ? IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE
-                             : IDS_PREVIEWS_INFOBAR_FASTER_PAGE_TITLE)) {
-  DCHECK(previews_type_ != previews::PreviewsType::NONE &&
-         previews_type_ != previews::PreviewsType::UNSPECIFIED);
-}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-PreviewsInfoBarDelegate::GetIdentifier() const {
-  return DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE;
-}
-
-int PreviewsInfoBarDelegate::GetIconId() const {
-#if defined(OS_ANDROID)
-  return IDR_ANDROID_INFOBAR_PREVIEWS;
-#else
-  return kNoIconID;
-#endif
-}
-
-bool PreviewsInfoBarDelegate::ShouldExpire(
-    const NavigationDetails& details) const {
-  infobar_dismissed_action_ = details.is_reload
-                                  ? INFOBAR_DISMISSED_BY_RELOAD
-                                  : INFOBAR_DISMISSED_BY_NAVIGATION;
-  return InfoBarDelegate::ShouldExpire(details);
-}
-
-void PreviewsInfoBarDelegate::InfoBarDismissed() {
-  infobar_dismissed_action_ = INFOBAR_DISMISSED_BY_USER;
-}
-
-base::string16 PreviewsInfoBarDelegate::GetMessageText() const {
-// Android has a custom infobar that calls GetStalePreviewTimestampText() and
-// adds the timestamp in a separate description view. Other OS's can enable
-// previews for debugging purposes and don't have a custom infobar with a
-// description view, so the timestamp should be appended to the message.
-#if defined(OS_ANDROID)
-  return message_text_;
-#else
-  base::string16 timestamp = GetStalePreviewTimestampText();
-  if (timestamp.empty())
-    return message_text_;
-  // This string concatenation wouldn't fly for l10n, but this is only a hack
-  // for Chromium devs and not expected to ever appear for users.
-  return message_text_ + base::ASCIIToUTF16(" - ") + timestamp;
-#endif
-}
-
-int PreviewsInfoBarDelegate::GetButtons() const {
-  return BUTTON_NONE;
-}
-
-base::string16 PreviewsInfoBarDelegate::GetLinkText() const {
-  return l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_LINK);
-}
-
-bool PreviewsInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
-  infobar_dismissed_action_ = INFOBAR_LOAD_ORIGINAL_CLICKED;
-
-  ui_tab_helper_->ReloadWithoutPreviews(previews_type_);
-
-  return true;
-}
-
-base::string16 PreviewsInfoBarDelegate::GetStalePreviewTimestampText() const {
-  if (!ui_tab_helper_)
-    return base::string16();
-
-  const base::string16 text = ui_tab_helper_->GetStalePreviewTimestampText();
-  if (text.length() > 0)
-    ui_tab_helper_->set_displayed_preview_timestamp(true);
-  return text;
-}
diff --git a/chrome/browser/previews/previews_infobar_delegate.h b/chrome/browser/previews/previews_infobar_delegate.h
deleted file mode 100644
index 76e6443..0000000
--- a/chrome/browser/previews/previews_infobar_delegate.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_PREVIEWS_PREVIEWS_INFOBAR_DELEGATE_H_
-
-#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "chrome/browser/previews/previews_ui_tab_helper.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/previews/core/previews_experiments.h"
-
-class PreviewsUITabHelper;
-
-namespace content {
-class WebContents;
-}
-
-namespace previews {
-class PreviewsUIService;
-}
-
-// Shows an infobar that lets the user know that a preview page has been loaded,
-// and gives the user a link to reload the original page. This infobar will only
-// be shown once per page load. Records UMA data for user interactions with the
-// infobar.
-class PreviewsInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // Actions on the previews infobar. This enum must remain synchronized with
-  // the enum of the same name in metrics/histograms/histograms.xml.
-  enum PreviewsInfoBarAction {
-    INFOBAR_SHOWN = 0,
-    INFOBAR_LOAD_ORIGINAL_CLICKED = 1,
-    INFOBAR_DISMISSED_BY_USER = 2,
-    INFOBAR_DISMISSED_BY_NAVIGATION = 3,
-    INFOBAR_DISMISSED_BY_RELOAD = 4,
-    INFOBAR_DISMISSED_BY_TAB_CLOSURE = 5,
-    INFOBAR_INDEX_BOUNDARY
-  };
-
-  ~PreviewsInfoBarDelegate() override;
-
-  // Creates a preview infobar and corresponding delegate and adds the infobar
-  // to InfoBarService. |on_dismiss_callback| is called when the InfoBar is
-  // dismissed.
-  static void Create(content::WebContents* web_contents,
-                     previews::PreviewsType previews_type,
-                     bool is_data_saver_user,
-                     previews::PreviewsUIService* previews_ui_service);
-
-  // ConfirmInfoBarDelegate overrides:
-  int GetIconId() const override;
-  base::string16 GetMessageText() const override;
-  base::string16 GetLinkText() const override;
-
-  base::string16 GetStalePreviewTimestampText() const;
-
- private:
-  PreviewsInfoBarDelegate(PreviewsUITabHelper* ui_tab_helper,
-                          previews::PreviewsType previews_type,
-                          bool is_data_saver_user);
-
-  // ConfirmInfoBarDelegate overrides:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  bool ShouldExpire(const NavigationDetails& details) const override;
-  void InfoBarDismissed() override;
-  int GetButtons() const override;
-  bool LinkClicked(WindowOpenDisposition disposition) override;
-
-  PreviewsUITabHelper* ui_tab_helper_;
-  previews::PreviewsType previews_type_;
-  mutable PreviewsInfoBarAction infobar_dismissed_action_;
-
-  const base::string16 message_text_;
-
-  DISALLOW_COPY_AND_ASSIGN(PreviewsInfoBarDelegate);
-};
-
-#endif  // CHROME_BROWSER_PREVIEWS_PREVIEWS_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/previews/previews_infobar_delegate_unittest.cc b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
deleted file mode 100644
index bd649274..0000000
--- a/chrome/browser/previews/previews_infobar_delegate_unittest.cc
+++ /dev/null
@@ -1,683 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/previews/previews_infobar_delegate.h"
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_param_associator.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/optional.h"
-#include "base/run_loop.h"
-#include "base/strings/string16.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/default_clock.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
-#include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/infobars/mock_infobar_service.h"
-#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
-#include "chrome/browser/page_load_metrics/page_load_tracker.h"
-#include "chrome/browser/previews/previews_ui_tab_helper.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/blacklist/opt_out_blacklist/opt_out_blacklist_data.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar.h"
-#include "components/infobars/core/infobar_delegate.h"
-#include "components/network_time/network_time_test_utils.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/previews/content/previews_decider_impl.h"
-#include "components/previews/content/previews_ui_service.h"
-#include "components/previews/core/previews_experiments.h"
-#include "components/previews/core/previews_features.h"
-#include "components/previews/core/previews_logger.h"
-#include "components/proxy_config/proxy_config_pref_names.h"
-#include "components/variations/variations_associated_data.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/reload_type.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "content/public/common/referrer.h"
-#include "content/public/test/navigation_simulator.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/web_contents_tester.h"
-#include "services/network/test/test_network_quality_tracker.h"
-#include "services/network/test/test_shared_url_loader_factory.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/page_transition_types.h"
-#include "ui/base/window_open_disposition.h"
-
-namespace {
-
-const char kTestUrl[] = "http://www.test.com/";
-
-// Key of the UMA Previews.InfoBarAction.LoFi histogram.
-const char kUMAPreviewsInfoBarActionLoFi[] = "Previews.InfoBarAction.LoFi";
-
-// Key of the UMA Previews.InfoBarAction.Offline histogram.
-const char kUMAPreviewsInfoBarActionOffline[] =
-    "Previews.InfoBarAction.Offline";
-
-// Key of the UMA Previews.InfoBarAction.LitePage histogram.
-const char kUMAPreviewsInfoBarActionLitePage[] =
-    "Previews.InfoBarAction.LitePage";
-
-// Key of the UMA Previews.StalePreviewTimestampShown histogram.
-const char kUMAPreviewsStalePreviewTimestamp[] =
-    "Previews.StalePreviewTimestampShown";
-
-// Dummy method for creating TestPreviewsUIService.
-bool IsPreviewsEnabled(previews::PreviewsType type) {
-  return true;
-}
-
-class TestPreviewsWebContentsObserver
-    : public content::WebContentsObserver,
-      public content::WebContentsUserData<TestPreviewsWebContentsObserver> {
- public:
-  explicit TestPreviewsWebContentsObserver(content::WebContents* web_contents)
-      : content::WebContentsObserver(web_contents),
-        last_navigation_reload_type_(content::ReloadType::NONE) {}
-  ~TestPreviewsWebContentsObserver() override {}
-
-  content::ReloadType last_navigation_reload_type() {
-    return last_navigation_reload_type_;
-  }
-
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override {
-    last_navigation_reload_type_ = navigation_handle->GetReloadType();
-  }
-
- private:
-  friend class content::WebContentsUserData<TestPreviewsWebContentsObserver>;
-  content::ReloadType last_navigation_reload_type_;
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-};
-
-WEB_CONTENTS_USER_DATA_KEY_IMPL(TestPreviewsWebContentsObserver)
-
-class TestOptOutObserver : public page_load_metrics::PageLoadMetricsObserver {
- public:
-  explicit TestOptOutObserver(const base::Callback<void()>& callback)
-      : callback_(callback) {}
-  ~TestOptOutObserver() override {}
-
-  void OnEventOccurred(const void* const event_key) override {
-    if (PreviewsUITabHelper::OptOutEventKey() == event_key)
-      callback_.Run();
-  }
-
-  base::Callback<void()> callback_;
-};
-
-class TestPreviewsLogger : public previews::PreviewsLogger {
- public:
-  TestPreviewsLogger() {}
-  ~TestPreviewsLogger() override {}
-
-  // previews::PreviewsLogger:
-  void LogMessage(const std::string& event_type,
-                  const std::string& event_description,
-                  const GURL& url,
-                  base::Time time,
-                  uint64_t page_id) override {
-    event_type_ = event_type;
-    event_description_ = event_description;
-  }
-
-  // Exposed passed in params of LogMessage for testing.
-  std::string event_type() const { return event_type_; }
-  std::string event_description() const { return event_description_; }
-
- private:
-  // Passed in parameters of LogMessage.
-  std::string event_type_;
-  std::string event_description_;
-};
-
-}  // namespace
-
-class PreviewsInfoBarDelegateUnitTest
-    : public page_load_metrics::PageLoadMetricsObserverTestHarness {
- protected:
-  PreviewsInfoBarDelegateUnitTest()
-      : opt_out_called_(false),
-        field_trial_list_(new base::FieldTrialList(nullptr)),
-        tester_(new base::HistogramTester()) {}
-
-  void SetUp() override {
-    PageLoadMetricsObserverTestHarness::SetUp();
-    MockInfoBarService::CreateForWebContents(web_contents());
-    PreviewsUITabHelper::CreateForWebContents(web_contents());
-    TestPreviewsWebContentsObserver::CreateForWebContents(web_contents());
-
-    drp_test_context_ =
-        data_reduction_proxy::DataReductionProxyTestContext::Builder()
-            .WithMockConfig()
-            .SkipSettingsInitialization()
-            .Build();
-
-    auto* data_reduction_proxy_settings =
-        DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-            web_contents()->GetBrowserContext());
-
-    PrefRegistrySimple* registry =
-        drp_test_context_->pref_service()->registry();
-    registry->RegisterDictionaryPref(proxy_config::prefs::kProxy);
-    data_reduction_proxy_settings->InitDataReductionProxySettings(
-        drp_test_context_->io_data(), drp_test_context_->pref_service(),
-        drp_test_context_->request_context_getter(), profile(),
-        base::MakeRefCounted<network::TestSharedURLLoaderFactory>(),
-        base::WrapUnique(new data_reduction_proxy::DataStore()),
-        base::ThreadTaskRunnerHandle::Get(),
-        base::ThreadTaskRunnerHandle::Get());
-
-    TestingBrowserProcess::GetGlobal()->SetLocalState(
-        drp_test_context_->pref_service());
-    network_time::NetworkTimeTracker::RegisterPrefs(registry);
-
-    std::unique_ptr<TestPreviewsLogger> previews_logger =
-        std::make_unique<TestPreviewsLogger>();
-    previews_logger_ = previews_logger.get();
-    std::unique_ptr<previews::PreviewsDeciderImpl> decider =
-        std::make_unique<previews::PreviewsDeciderImpl>(
-            base::DefaultClock::GetInstance());
-    previews_decider_impl_ = decider.get();
-    test_network_quality_tracker_ =
-        std::make_unique<network::TestNetworkQualityTracker>();
-    previews_ui_service_ = std::make_unique<previews::PreviewsUIService>(
-        std::move(decider), nullptr /* previews_opt_out_store */,
-        nullptr /* previews_opt_guide */,
-        base::BindRepeating(&IsPreviewsEnabled), std::move(previews_logger),
-        blacklist::BlacklistData::AllowedTypesAndVersions(),
-        test_network_quality_tracker_.get());
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void TearDown() override {
-    previews_ui_service_.reset();
-    drp_test_context_->DestroySettings();
-    ChromeRenderViewHostTestHarness::TearDown();
-    TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
-  }
-
-  PreviewsInfoBarDelegate* CreateInfoBar(previews::PreviewsType type,
-                                         bool is_data_saver_user) {
-    PreviewsInfoBarDelegate::Create(web_contents(), type, is_data_saver_user,
-                                    previews_ui_service_.get());
-
-    EXPECT_EQ(1U, infobar_service()->infobar_count());
-
-    return static_cast<PreviewsInfoBarDelegate*>(
-        infobar_service()->infobar_at(0)->delegate());
-  }
-
-  void EnableStalePreviewsTimestamp(
-      const std::map<std::string, std::string>& variation_params) {
-    field_trial_list_.reset();
-    field_trial_list_.reset(new base::FieldTrialList(nullptr));
-    base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
-
-    scoped_feature_list_.InitAndEnableFeatureWithParameters(
-        previews::features::kStalePreviewsTimestamp, variation_params);
-  }
-
-  void TestStalePreviews(
-      int staleness_in_minutes,
-      bool is_reload,
-      base::string16 expected_timestamp,
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp expected_bucket) {
-    PreviewsUITabHelper::FromWebContents(web_contents())
-        ->SetStalePreviewsStateForTesting(
-            base::Time::Now() -
-                base::TimeDelta::FromMinutes(staleness_in_minutes),
-            is_reload);
-
-    PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-        previews::PreviewsType::LITE_PAGE, true /* is_data_saver_user */);
-    EXPECT_EQ(expected_timestamp, infobar->GetStalePreviewTimestampText());
-    tester_->ExpectBucketCount(kUMAPreviewsStalePreviewTimestamp,
-                               expected_bucket, 1);
-
-    // Dismiss the infobar.
-    infobar_service()->RemoveAllInfoBars(false);
-    PreviewsUITabHelper::FromWebContents(web_contents())
-        ->set_displayed_preview_ui(false);
-  }
-
-  InfoBarService* infobar_service() {
-    return InfoBarService::FromWebContents(web_contents());
-  }
-
-  // Expose previews_logger_ raw pointer to test results.
-  TestPreviewsLogger* previews_logger() const { return previews_logger_; }
-
-  void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
-    tracker->AddObserver(std::make_unique<TestOptOutObserver>(base::Bind(
-        &PreviewsInfoBarDelegateUnitTest::OptOut, base::Unretained(this))));
-  }
-
-  void OptOut() { opt_out_called_ = true; }
-
-  bool opt_out_called_;
-
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyTestContext>
-      drp_test_context_;
-
-  std::unique_ptr<base::FieldTrialList> field_trial_list_;
-  base::test::ScopedFeatureList scoped_feature_list_;
-  std::unique_ptr<base::HistogramTester> tester_;
-
-  TestPreviewsLogger* previews_logger_;
-  previews::PreviewsDeciderImpl* previews_decider_impl_;
-  std::unique_ptr<previews::PreviewsUIService> previews_ui_service_;
-  std::unique_ptr<network::NetworkQualityTracker> test_network_quality_tracker_;
-};
-
-// TODO(crbug/782740): Test temporarily disabled on Windows because it crashes
-// on trybots.
-#if defined(OS_WIN)
-#define DISABLE_ON_WINDOWS(x) DISABLED_##x
-#else
-#define DISABLE_ON_WINDOWS(x) x
-#endif
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestNavigationDismissal)) {
-  CreateInfoBar(previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-  // Try showing a second infobar. Another should not be shown since the page
-  // has not navigated.
-  PreviewsInfoBarDelegate::Create(web_contents(), previews::PreviewsType::LOFI,
-                                  true /* is_data_saver_user */,
-                                  previews_ui_service_.get());
-  EXPECT_EQ(1U, infobar_service()->infobar_count());
-
-  // Navigate and make sure the infobar is dismissed.
-  NavigateAndCommit(GURL(kTestUrl));
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  tester_->ExpectBucketCount(
-      kUMAPreviewsInfoBarActionLoFi,
-      PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_NAVIGATION, 1);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestReloadDismissal)) {
-  // Navigate to test URL, so we can reload later.
-  NavigateAndCommit(GURL(kTestUrl));
-
-  CreateInfoBar(previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-  // Try showing a second infobar. Another should not be shown since the page
-  // has not navigated.
-  PreviewsInfoBarDelegate::Create(web_contents(), previews::PreviewsType::LOFI,
-                                  true /* is_data_saver_user */,
-                                  previews_ui_service_.get());
-  EXPECT_EQ(1U, infobar_service()->infobar_count());
-
-  // Navigate to test URL as a reload to dismiss the infobar.
-  content::NavigationSimulator::Reload(web_contents());
-
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  tester_->ExpectBucketCount(
-      kUMAPreviewsInfoBarActionLoFi,
-      PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_RELOAD, 1);
-
-  EXPECT_FALSE(opt_out_called_);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestUserDismissal)) {
-  ConfirmInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-  // Simulate dismissing the infobar.
-  infobar->InfoBarDismissed();
-  infobar_service()->infobar_at(0)->RemoveSelf();
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  tester_->ExpectBucketCount(kUMAPreviewsInfoBarActionLoFi,
-                             PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_USER,
-                             1);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestTabClosedDismissal)) {
-  CreateInfoBar(previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-  // Delete the infobar without any other infobar actions.
-  infobar_service()->infobar_at(0)->RemoveSelf();
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  tester_->ExpectBucketCount(
-      kUMAPreviewsInfoBarActionLoFi,
-      PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_TAB_CLOSURE, 1);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestClickLinkLoFi)) {
-  NavigateAndCommit(GURL(kTestUrl));
-  const struct {
-    bool using_previews_blacklist;
-  } tests[] = {
-      {true}, {false},
-  };
-  for (const auto test : tests) {
-    opt_out_called_ = false;
-    tester_.reset(new base::HistogramTester());
-    field_trial_list_.reset();
-    field_trial_list_.reset(new base::FieldTrialList(nullptr));
-    if (test.using_previews_blacklist) {
-      base::FieldTrialList::CreateFieldTrial(
-          "DataReductionProxyPreviewsBlackListTransition", "Enabled_");
-    }
-
-    // Call Reload to force DidFinishNavigation.
-    content::NavigationSimulator::Reload(web_contents());
-    ConfirmInfoBarDelegate* infobar = CreateInfoBar(
-        previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-    // Simulate clicking the infobar link.
-    if (infobar->LinkClicked(WindowOpenDisposition::CURRENT_TAB))
-      infobar_service()->infobar_at(0)->RemoveSelf();
-    EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-    tester_->ExpectBucketCount(
-        kUMAPreviewsInfoBarActionLoFi,
-        PreviewsInfoBarDelegate::INFOBAR_LOAD_ORIGINAL_CLICKED, 1);
-
-    EXPECT_TRUE(opt_out_called_);
-  }
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestClickLinkLitePage)) {
-  NavigateAndCommit(GURL(kTestUrl));
-  ConfirmInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LITE_PAGE, true /* is_data_saver_user */);
-
-  // Simulate clicking the infobar link.
-  if (infobar->LinkClicked(WindowOpenDisposition::CURRENT_TAB))
-    infobar_service()->infobar_at(0)->RemoveSelf();
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  tester_->ExpectBucketCount(
-      kUMAPreviewsInfoBarActionLitePage,
-      PreviewsInfoBarDelegate::INFOBAR_LOAD_ORIGINAL_CLICKED, 1);
-
-  std::unique_ptr<content::NavigationSimulator> simulator =
-      content::NavigationSimulator::CreateFromPending(web_contents());
-  simulator->Commit();
-
-  EXPECT_EQ(content::ReloadType::ORIGINAL_REQUEST_URL,
-            TestPreviewsWebContentsObserver::FromWebContents(web_contents())
-                ->last_navigation_reload_type());
-
-  EXPECT_TRUE(opt_out_called_);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(InfobarTestShownOncePerNavigation)) {
-  ConfirmInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-  // Simulate dismissing the infobar.
-  infobar->InfoBarDismissed();
-  infobar_service()->infobar_at(0)->RemoveSelf();
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  PreviewsInfoBarDelegate::Create(web_contents(), previews::PreviewsType::LOFI,
-                                  true /* is_data_saver_user */,
-                                  previews_ui_service_.get());
-
-  // Infobar should not be shown again since a navigation hasn't happened.
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  // Navigate and show infobar again.
-  NavigateAndCommit(GURL(kTestUrl));
-  CreateInfoBar(previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest, DISABLE_ON_WINDOWS(LoFiInfobarTest)) {
-  ConfirmInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LOFI, true /* is_data_saver_user */);
-
-  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionLoFi,
-                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
-
-  ASSERT_TRUE(infobar);
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE),
-            infobar->GetMessageText());
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_LINK),
-            infobar->GetLinkText());
-#if defined(OS_ANDROID)
-  ASSERT_EQ(IDR_ANDROID_INFOBAR_PREVIEWS, infobar->GetIconId());
-#else
-  ASSERT_EQ(PreviewsInfoBarDelegate::kNoIconID, infobar->GetIconId());
-#endif
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTest)) {
-  PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LITE_PAGE, true /* is_data_saver_user */);
-
-  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionLitePage,
-                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
-
-  // Check the strings.
-  ASSERT_TRUE(infobar);
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE),
-            infobar->GetMessageText());
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_LINK),
-            infobar->GetLinkText());
-  ASSERT_EQ(base::string16(), infobar->GetStalePreviewTimestampText());
-#if defined(OS_ANDROID)
-  ASSERT_EQ(IDR_ANDROID_INFOBAR_PREVIEWS, infobar->GetIconId());
-#else
-  ASSERT_EQ(PreviewsInfoBarDelegate::kNoIconID, infobar->GetIconId());
-#endif
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(OfflineInfobarNonDataSaverUserTest)) {
-  PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::OFFLINE, false /* is_data_saver_user */);
-
-  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
-                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
-
-  // Check the strings.
-  ASSERT_TRUE(infobar);
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_FASTER_PAGE_TITLE),
-            infobar->GetMessageText());
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_LINK),
-            infobar->GetLinkText());
-  ASSERT_EQ(base::string16(), infobar->GetStalePreviewTimestampText());
-#if defined(OS_ANDROID)
-  ASSERT_EQ(IDR_ANDROID_INFOBAR_PREVIEWS, infobar->GetIconId());
-#else
-  ASSERT_EQ(PreviewsInfoBarDelegate::kNoIconID, infobar->GetIconId());
-#endif
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(OfflineInfobarDataSaverUserTest)) {
-  PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::OFFLINE, true /* is_data_saver_user */);
-
-  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
-                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
-
-  // Check the strings.
-  ASSERT_TRUE(infobar);
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE),
-            infobar->GetMessageText());
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_LINK),
-            infobar->GetLinkText());
-  ASSERT_EQ(base::string16(), infobar->GetStalePreviewTimestampText());
-#if defined(OS_ANDROID)
-  ASSERT_EQ(IDR_ANDROID_INFOBAR_PREVIEWS, infobar->GetIconId());
-#else
-  ASSERT_EQ(PreviewsInfoBarDelegate::kNoIconID, infobar->GetIconId());
-#endif
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(OfflineInfobarDisablesLoFi)) {
-  NavigateAndCommit(GURL(kTestUrl));
-
-  ConfirmInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::OFFLINE, true /* is_data_saver_user */);
-
-  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
-                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
-
-  // Simulate clicking the infobar link.
-  if (infobar->LinkClicked(WindowOpenDisposition::CURRENT_TAB))
-    infobar_service()->infobar_at(0)->RemoveSelf();
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-
-  std::unique_ptr<content::NavigationSimulator> simulator =
-      content::NavigationSimulator::CreateFromPending(web_contents());
-  simulator->Commit();
-
-  EXPECT_EQ(content::ReloadType::ORIGINAL_REQUEST_URL,
-            TestPreviewsWebContentsObserver::FromWebContents(web_contents())
-                ->last_navigation_reload_type());
-
-  EXPECT_TRUE(opt_out_called_);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTimestampMinutesTest)) {
-  // Use default params.
-  std::map<std::string, std::string> variation_params;
-  EnableStalePreviewsTimestamp(variation_params);
-  int staleness_in_minutes = 5;
-
-  TestStalePreviews(
-      staleness_in_minutes, false /* is_reload */,
-      l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES,
-                                 base::NumberToString16(staleness_in_minutes)),
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp::kTimestampShown);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTimestampHourTest)) {
-  // Use default variation_params.
-  std::map<std::string, std::string> variation_params;
-  EnableStalePreviewsTimestamp(variation_params);
-  int staleness_in_minutes = 65;
-
-  TestStalePreviews(
-      staleness_in_minutes, false /* is_reload */,
-      l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_ONE_HOUR),
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp::kTimestampShown);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTimestampHoursTest)) {
-  // Use default variation_params.
-  std::map<std::string, std::string> variation_params;
-  EnableStalePreviewsTimestamp(variation_params);
-  int staleness_in_hours = 2;
-
-  TestStalePreviews(
-      staleness_in_hours * 60, false /* is_reload */,
-      l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_HOURS,
-                                 base::NumberToString16(staleness_in_hours)),
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp::kTimestampShown);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTimestampFinchParamsUMA)) {
-  std::map<std::string, std::string> variation_params;
-  variation_params["min_staleness_in_minutes"] = "2";
-  variation_params["max_staleness_in_minutes"] = "5";
-  EnableStalePreviewsTimestamp(variation_params);
-
-  TestStalePreviews(
-      2, false /* is_reload */,
-      l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES,
-                                 base::NumberToString16(2)),
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp::kTimestampShown);
-
-  TestStalePreviews(6, false /* is_reload */, base::string16(),
-                    PreviewsUITabHelper::PreviewsStalePreviewTimestamp::
-                        kTimestampNotShownStalenessGreaterThanMax);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTimestampUMA)) {
-  // Use default params.
-  std::map<std::string, std::string> variation_params;
-  EnableStalePreviewsTimestamp(variation_params);
-
-  TestStalePreviews(1, false /* is_reload */, base::string16(),
-                    PreviewsUITabHelper::PreviewsStalePreviewTimestamp::
-                        kTimestampNotShownPreviewNotStale);
-  TestStalePreviews(-1, false /* is_reload */, base::string16(),
-                    PreviewsUITabHelper::PreviewsStalePreviewTimestamp::
-                        kTimestampNotShownStalenessNegative);
-  TestStalePreviews(1441, false /* is_reload */, base::string16(),
-                    PreviewsUITabHelper::PreviewsStalePreviewTimestamp::
-                        kTimestampNotShownStalenessGreaterThanMax);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(PreviewInfobarTimestampReloadTest)) {
-  // Use default params.
-  std::map<std::string, std::string> variation_params;
-  EnableStalePreviewsTimestamp(variation_params);
-  int staleness_in_minutes = 5;
-
-  TestStalePreviews(
-      staleness_in_minutes, false /* is_reload */,
-      l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES,
-                                 base::NumberToString16(staleness_in_minutes)),
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp::kTimestampShown);
-
-  staleness_in_minutes = 1;
-  TestStalePreviews(
-      staleness_in_minutes, true /* is_reload */,
-      l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_UPDATED_NOW),
-      PreviewsUITabHelper::PreviewsStalePreviewTimestamp::
-          kTimestampUpdatedNowShown);
-}
-
-TEST_F(PreviewsInfoBarDelegateUnitTest,
-       DISABLE_ON_WINDOWS(CreateInfoBarLogPreviewsInfoBarType)) {
-  const previews::PreviewsType expected_type = previews::PreviewsType::LOFI;
-  const std::string expected_event = "InfoBar";
-  const std::string expected_description =
-      previews::GetStringNameForType(expected_type) + " InfoBar shown";
-
-  CreateInfoBar(expected_type, false /* is_data_saver_user */
-                );
-  EXPECT_EQ(expected_event, previews_logger()->event_type());
-  EXPECT_EQ(expected_description, previews_logger()->event_description());
-}
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc
index ad647831..1ef3e3f 100644
--- a/chrome/browser/previews/previews_lite_page_browsertest.cc
+++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -1741,15 +1741,6 @@
   histogram_tester.ExpectBucketCount(
       "Previews.ServerLitePage.IneligibleReasons",
       PreviewsLitePageNavigationThrottle::IneligibleReason::kInfoBarNotSeen, 1);
-
-  ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess));
-  // Expect the "Saved Data" InfoBar.
-  ASSERT_EQ(1U, GetInfoBarService()->infobar_count());
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_SAVED_DATA_TITLE),
-            static_cast<ConfirmInfoBarDelegate*>(
-                GetInfoBarService()->infobar_at(0)->delegate())
-                ->GetMessageText());
-  VerifyPreviewLoaded();
 }
 
 class PreviewsLitePageNotificationDSDisabledBrowserTest
diff --git a/chrome/browser/previews/previews_offline_helper.cc b/chrome/browser/previews/previews_offline_helper.cc
index d0b16dd..833f3ac 100644
--- a/chrome/browser/previews/previews_offline_helper.cc
+++ b/chrome/browser/previews/previews_offline_helper.cc
@@ -15,10 +15,13 @@
 #include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
 #include "base/time/time.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/offline_pages/buildflags/buildflags.h"
+#include "components/offline_pages/core/page_criteria.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/previews/core/previews_experiments.h"
@@ -85,8 +88,10 @@
       continue;
     }
 
-    if (expiry < earliest_expiry)
+    if (expiry < earliest_expiry) {
       earliest_key = iter.first;
+      earliest_expiry = expiry;
+    }
   }
 
   for (const std::string& key : keys_to_delete)
@@ -99,6 +104,13 @@
   }
 }
 
+bool IsOfflinePageItemFreshForPreviews(
+    const offline_pages::OfflinePageItem& item) {
+  return base::Time::Now() <=
+         item.creation_time +
+             previews::params::OfflinePreviewFreshnessDuration();
+}
+
 void AddSingleOfflineItemEntry(
     base::DictionaryValue* available_pages,
     const offline_pages::OfflinePageItem& added_page) {
@@ -139,11 +151,19 @@
   offline_page_model_ =
       offline_pages::OfflinePageModelFactory::GetForBrowserContext(
           browser_context);
-  if (offline_page_model_) {
+
+  if (offline_page_model_ &&
+      base::FeatureList::IsEnabled(
+          previews::features::kOfflinePreviewsFalsePositivePrevention)) {
     offline_page_model_->AddObserver(this);
-    offline_page_model_->GetAllPages(
-        base::BindOnce(&PreviewsOfflineHelper::UpdateAllPrefEntries,
-                       weak_factory_.GetWeakPtr()));
+    // Schedule a low priority task with a slight delay to ensure that the
+    // expensive DB query doesn't occur during startup or during other user
+    // visible actions.
+    base::PostDelayedTaskWithTraits(
+        FROM_HERE, {base::MayBlock(), base::TaskPriority::LOWEST},
+        base::BindOnce(&PreviewsOfflineHelper::RequestDBUpdate,
+                       weak_factory_.GetWeakPtr()),
+        base::TimeDelta::FromSeconds(30));
   }
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
 }
@@ -207,6 +227,19 @@
   }
 }
 
+void PreviewsOfflineHelper::RequestDBUpdate() {
+  offline_pages::PageCriteria criteria;
+  criteria.exclude_tab_bound_pages = true;
+  criteria.maximum_matches =
+      previews::params::OfflinePreviewsHelperMaxPrefSize();
+  criteria.additional_criteria =
+      base::BindRepeating(&IsOfflinePageItemFreshForPreviews);
+
+  offline_page_model_->GetPagesWithCriteria(
+      criteria, base::BindOnce(&PreviewsOfflineHelper::UpdateAllPrefEntries,
+                               weak_factory_.GetWeakPtr()));
+}
+
 void PreviewsOfflineHelper::UpdateAllPrefEntries(
     const offline_pages::MultipleOfflinePageItemResult& pages) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -216,7 +249,6 @@
   available_pages_->Clear();
   for (const offline_pages::OfflinePageItem& page : pages)
     AddSingleOfflineItemEntry(available_pages_.get(), page);
-  RemoveStaleOfflinePageEntries(available_pages_.get());
   UpdatePref();
 
   UMA_HISTOGRAM_COUNTS_100("Previews.Offline.FalsePositivePrevention.PrefSize",
@@ -243,8 +275,6 @@
 
   // Has no effect if the url was never in the dictionary.
   available_pages_->RemoveKey(HashURL(deleted_page.url));
-
-  RemoveStaleOfflinePageEntries(available_pages_.get());
   UpdatePref();
 }
 
diff --git a/chrome/browser/previews/previews_offline_helper.h b/chrome/browser/previews/previews_offline_helper.h
index d4f21b4..38e5fda7 100644
--- a/chrome/browser/previews/previews_offline_helper.h
+++ b/chrome/browser/previews/previews_offline_helper.h
@@ -59,6 +59,12 @@
   }
 
  private:
+  // Requests all eligible pages from Offline Page Model. This is defined as a
+  // separate method so that it can be scheduled at a low priority since the
+  // Offline DB query is expensive, and only needs to be done at most once per
+  // session.
+  void RequestDBUpdate();
+
   // Helper method to update |available_pages_| in |pref_service_|.
   void UpdatePref();
 
diff --git a/chrome/browser/previews/previews_offline_helper_unittest.cc b/chrome/browser/previews/previews_offline_helper_unittest.cc
index 7723493..1c70a773 100644
--- a/chrome/browser/previews/previews_offline_helper_unittest.cc
+++ b/chrome/browser/previews/previews_offline_helper_unittest.cc
@@ -8,13 +8,24 @@
 #include <string>
 #include <vector>
 
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
+#include "chrome/browser/offline_pages/offline_page_model_factory.h"
+#include "chrome/browser/offline_pages/request_coordinator_factory.h"
+#include "chrome/browser/offline_pages/test_offline_page_model_builder.h"
+#include "chrome/browser/offline_pages/test_request_coordinator_builder.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/offline_pages/buildflags/buildflags.h"
+#include "components/offline_pages/core/offline_page_test_archiver.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/previews/core/previews_experiments.h"
 #include "components/previews/core/previews_features.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class PreviewsOfflineHelperTest : public ChromeRenderViewHostTestHarness {
@@ -269,23 +280,117 @@
 
   PreviewsOfflineHelper* helper = NewHelper(nullptr);
   base::Time now = base::Time::Now();
-  base::Time expired = now -
-                       previews::params::OfflinePreviewFreshnessDuration() -
-                       base::TimeDelta::FromHours(1);
 
   helper->OfflinePageAdded(nullptr,
                            MakeAddedPageItem("http://cleared.com", "", now));
   EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL("http://cleared.com")));
 
-  helper->UpdateAllPrefEntries(
-      {MakeAddedPageItem("http://new.com", "", now),
-       MakeAddedPageItem("http://new2.com", "", now),
-       MakeAddedPageItem("http://expired.com", "", expired)});
+  helper->UpdateAllPrefEntries({MakeAddedPageItem("http://new.com", "", now),
+                                MakeAddedPageItem("http://new2.com", "", now)});
   EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(GURL("http://cleared.com")));
   EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL("http://new.com")));
   EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL("http://new2.com")));
-  EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(GURL("http://expired.com")));
 
   histogram_tester.ExpectUniqueSample(
       "Previews.Offline.FalsePositivePrevention.PrefSize", 2, 1);
 }
+
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+
+class PreviewsOfflinePagesIntegrationTest
+    : public PreviewsOfflineHelperTest,
+      public offline_pages::OfflinePageTestArchiver::Observer {
+ public:
+  void SetUp() override {
+    PreviewsOfflineHelperTest::SetUp();
+    scoped_feature_list_.InitAndEnableFeature(
+        previews::features::kOfflinePreviewsFalsePositivePrevention);
+
+    // Sets up the factories for testing.
+    offline_pages::OfflinePageModelFactory::GetInstance()
+        ->SetTestingFactoryAndUse(
+            profile()->GetProfileKey(),
+            base::BindRepeating(&offline_pages::BuildTestOfflinePageModel));
+    base::RunLoop().RunUntilIdle();
+    offline_pages::RequestCoordinatorFactory::GetInstance()
+        ->SetTestingFactoryAndUse(
+            profile(),
+            base::BindRepeating(&offline_pages::BuildTestRequestCoordinator));
+    base::RunLoop().RunUntilIdle();
+
+    model_ = offline_pages::OfflinePageModelFactory::GetForBrowserContext(
+        browser_context());
+  }
+
+  void NavigateAndCommit(const GURL& url) {
+    content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
+                                                               url);
+  }
+
+  std::unique_ptr<offline_pages::OfflinePageArchiver> CreatePageArchiver(
+      content::WebContents* web_contents) {
+    std::unique_ptr<offline_pages::OfflinePageTestArchiver> archiver(
+        new offline_pages::OfflinePageTestArchiver(
+            this, web_contents->GetLastCommittedURL(),
+            offline_pages::OfflinePageArchiver::ArchiverResult::
+                SUCCESSFULLY_CREATED,
+            base::string16(), 1234, std::string(),
+            base::ThreadTaskRunnerHandle::Get()));
+    return std::move(archiver);
+  }
+
+  void SavePage(content::WebContents* web_contents) {
+    offline_pages::OfflinePageModel::SavePageParams save_page_params;
+    save_page_params.url = web_contents->GetLastCommittedURL();
+    save_page_params.client_id = offline_pages::ClientId("default", "id");
+    save_page_params.proposed_offline_id = 4321;
+    save_page_params.is_background = false;
+    save_page_params.original_url = web_contents->GetLastCommittedURL();
+
+    model_->SavePage(save_page_params, CreatePageArchiver(web_contents),
+                     web_contents, base::DoNothing());
+  }
+
+  // OfflinePageTestArchiver::Observer:
+  void SetLastPathCreatedByArchiver(const base::FilePath& file_path) override {}
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  offline_pages::OfflinePageModel* model_;
+};
+
+TEST_F(PreviewsOfflinePagesIntegrationTest, TestOfflinePagesDBQuery) {
+  GURL url("http://test.com/");
+  NavigateAndCommit(url);
+  SavePage(web_contents());
+  base::RunLoop().RunUntilIdle();
+
+  PreviewsOfflineHelper* helper = NewHelper(browser_context());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(url));
+  EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(GURL("http://other.com")));
+}
+
+// This test checks that expired entries are not queried and populated in the
+// pref. Since creating a stale offline page with this infrastructure is tricky,
+// we instead set the freshness duration to negative to make any newly saved
+// offline page stale.
+TEST_F(PreviewsOfflinePagesIntegrationTest, TestOfflinePagesDBQuery_Expired) {
+  base::FieldTrialList field_trial_list(nullptr);
+  ASSERT_TRUE(base::AssociateFieldTrialParams(
+      "ClientSidePreviews", "Enabled",
+      {{"offline_preview_freshness_duration_in_days", "-1"}}));
+  ASSERT_TRUE(
+      base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
+
+  GURL url("http://test.com/");
+  NavigateAndCommit(url);
+  SavePage(web_contents());
+  base::RunLoop().RunUntilIdle();
+
+  PreviewsOfflineHelper* helper = NewHelper(browser_context());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(url));
+}
+
+#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
diff --git a/chrome/browser/previews/previews_ui_tab_helper.cc b/chrome/browser/previews/previews_ui_tab_helper.cc
index 34ce735..1c5172c 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper.cc
@@ -9,13 +9,13 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_macros_local.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/previews/previews_content_util.h"
-#include "chrome/browser/previews/previews_infobar_delegate.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -85,19 +85,6 @@
       PreviewsUITabHelper::OptOutEventKey());
 }
 
-bool ShouldShowUIForPreviewsType(previews::PreviewsType type) {
-  if (type == previews::PreviewsType::NONE)
-    return false;
-
-  // Show the UI for LoFi at commit if the UI is the Android Omnibox or when
-  // network-service is enabled.
-  if (type == previews::PreviewsType::LOFI) {
-    return previews::params::IsPreviewsOmniboxUiEnabled() ||
-           base::FeatureList::IsEnabled(network::features::kNetworkService);
-  }
-  return true;
-}
-
 }  // namespace
 
 PreviewsUITabHelper::~PreviewsUITabHelper() {
@@ -115,26 +102,19 @@
 
 void PreviewsUITabHelper::ShowUIElement(
     previews::PreviewsType previews_type,
-    bool is_data_saver_user,
     OnDismissPreviewsUICallback on_dismiss_callback) {
-  // Retrieve PreviewsUIService* from |web_contents| if available.
-  PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
-  previews::PreviewsUIService* previews_ui_service =
-      previews_service ? previews_service->previews_ui_service() : nullptr;
-
   on_dismiss_callback_ = std::move(on_dismiss_callback);
-
+  displayed_preview_ui_ = true;
 #if defined(OS_ANDROID)
-  if (previews::params::IsPreviewsOmniboxUiEnabled()) {
-    displayed_preview_ui_ = true;
-    should_display_android_omnibox_badge_ = true;
-    return;
-  }
+  should_display_android_omnibox_badge_ = true;
 #endif
 
-  PreviewsInfoBarDelegate::Create(web_contents(), previews_type,
-                                  is_data_saver_user, previews_ui_service);
+  // Record a local histogram for testing.
+  base::BooleanHistogram::FactoryGet(
+      base::StringPrintf("Previews.PreviewShown.%s",
+                         GetStringNameForType(previews_type).c_str()),
+      base::HistogramBase::kNoFlags)
+      ->Add(true);
 }
 
 base::string16 PreviewsUITabHelper::GetStalePreviewTimestampText() {
@@ -360,7 +340,6 @@
                                data_use_measurement::DataUseUserData::OTHER, 0);
 
     ShowUIElement(previews::PreviewsType::OFFLINE,
-                  data_reduction_proxy_settings && data_saver_enabled,
                   base::BindOnce(&AddPreviewNavigationCallback,
                                  web_contents()->GetBrowserContext(),
                                  navigation_handle->GetRedirectChain()[0],
@@ -377,7 +356,7 @@
           previews::CoinFlipHoldbackResult::kHoldback) {
     previews::PreviewsType main_frame_preview =
         previews_user_data_->committed_previews_type();
-    if (ShouldShowUIForPreviewsType(main_frame_preview)) {
+    if (main_frame_preview != previews::PreviewsType::NONE) {
       if (main_frame_preview == previews::PreviewsType::LITE_PAGE) {
         const net::HttpResponseHeaders* headers =
             navigation_handle->GetResponseHeaders();
@@ -385,7 +364,7 @@
           headers->GetDateValue(&previews_freshness_);
       }
 
-      ShowUIElement(main_frame_preview, true /* is_data_saver_user */,
+      ShowUIElement(main_frame_preview,
                     base::BindOnce(&AddPreviewNavigationCallback,
                                    web_contents()->GetBrowserContext(),
                                    navigation_handle->GetRedirectChain()[0],
diff --git a/chrome/browser/previews/previews_ui_tab_helper.h b/chrome/browser/previews/previews_ui_tab_helper.h
index a8c69dd..ca19333 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.h
+++ b/chrome/browser/previews/previews_ui_tab_helper.h
@@ -55,7 +55,6 @@
 
   // Trigger the Previews UI to be shown to the user.
   void ShowUIElement(previews::PreviewsType previews_type,
-                     bool is_data_saver_user,
                      OnDismissPreviewsUICallback on_dismiss_callback);
 
   // Reloads the content of the page without previews.
diff --git a/chrome/browser/previews/previews_ui_tab_helper_unittest.cc b/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
index 0957c1d0..01732976 100644
--- a/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
@@ -16,7 +16,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/infobars/mock_infobar_service.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/previews/previews_lite_page_navigation_throttle.h"
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
@@ -60,7 +59,6 @@
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
     offline_pages::OfflinePageTabHelper::CreateForWebContents(web_contents());
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-    MockInfoBarService::CreateForWebContents(web_contents());
     PreviewsUITabHelper::CreateForWebContents(web_contents());
     test_handle_ = std::make_unique<content::MockNavigationHandle>(
         GURL(kTestUrl), main_rfh());
@@ -128,10 +126,6 @@
         test_handle_.get(), page_id);
   }
 
-  InfoBarService* infobar_service() {
-    return InfoBarService::FromWebContents(web_contents());
-  }
-
  protected:
   std::unique_ptr<data_reduction_proxy::DataReductionProxyTestContext>
       drp_test_context_;
@@ -150,9 +144,6 @@
   CallDidFinishNavigation();
   base::RunLoop().RunUntilIdle();
 
-#if !defined(OS_ANDROID)
-  EXPECT_EQ(1U, infobar_service()->infobar_count());
-#endif
   EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
 
   // Navigate to reset the displayed state.
@@ -164,15 +155,10 @@
 
 #if defined(OS_ANDROID)
 TEST_F(PreviewsUITabHelperUnitTest, DidFinishNavigationDisplaysOmniboxBadge) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      previews::features::kAndroidOmniboxPreviewsBadge);
-
   PreviewsUITabHelper* ui_tab_helper =
       PreviewsUITabHelper::FromWebContents(web_contents());
   EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
   EXPECT_FALSE(ui_tab_helper->should_display_android_omnibox_badge());
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
 
   SetCommittedPreviewsType(previews::PreviewsType::LITE_PAGE);
   SimulateWillProcessResponse();
@@ -181,7 +167,6 @@
 
   EXPECT_TRUE(ui_tab_helper->should_display_android_omnibox_badge());
   EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
 }
 #endif
 
@@ -196,9 +181,6 @@
   CallDidFinishNavigation();
   base::RunLoop().RunUntilIdle();
 
-#if !defined(OS_ANDROID)
-  EXPECT_EQ(1U, infobar_service()->infobar_count());
-#endif
   EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
 
   // Navigate to reset the displayed state.
@@ -209,11 +191,7 @@
 }
 
 TEST_F(PreviewsUITabHelperUnitTest,
-       DidFinishNavigationDoesCreateLoFiPreviewsInfoBar) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      previews::features::kAndroidOmniboxPreviewsBadge);
-
+       DidFinishNavigationDoesCreateLoFiPreviewsUI) {
   PreviewsUITabHelper* ui_tab_helper =
       PreviewsUITabHelper::FromWebContents(web_contents());
   EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
@@ -225,10 +203,8 @@
 
 #if defined(OS_ANDROID)
   EXPECT_TRUE(ui_tab_helper->should_display_android_omnibox_badge());
-#else
-  EXPECT_EQ(1U, infobar_service()->infobar_count());
-  EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
 #endif
+  EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
 
   // Navigate to reset the displayed state.
   content::WebContentsTester::For(web_contents())
@@ -236,32 +212,8 @@
 
 #if defined(OS_ANDROID)
   EXPECT_FALSE(ui_tab_helper->should_display_android_omnibox_badge());
-#else
-  EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
 #endif
-}
-
-TEST_F(PreviewsUITabHelperUnitTest,
-       DidFinishNavigationDoesNotCreateLoFiPreviewsInfoBar) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      previews::features::kAndroidOmniboxPreviewsBadge);
-
-  PreviewsUITabHelper* ui_tab_helper =
-      PreviewsUITabHelper::FromWebContents(web_contents());
   EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
-
-  SetCommittedPreviewsType(previews::PreviewsType::LOFI);
-  SimulateWillProcessResponse();
-  CallDidFinishNavigation();
-  base::RunLoop().RunUntilIdle();
-
-#if defined(OS_ANDROID)
-  EXPECT_FALSE(ui_tab_helper->should_display_android_omnibox_badge());
-#else
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-  EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
-#endif
 }
 
 TEST_F(PreviewsUITabHelperUnitTest, TestPreviewsIDSet) {
@@ -324,9 +276,6 @@
   CallDidFinishNavigation();
   base::RunLoop().RunUntilIdle();
 
-#if !defined(OS_ANDROID)
-  EXPECT_EQ(1U, infobar_service()->infobar_count());
-#endif
   EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
 
   // Navigate to reset the displayed state.
@@ -384,7 +333,7 @@
 
   base::Optional<bool> on_dismiss_value;
 
-  ui_tab_helper->ShowUIElement(previews::PreviewsType::OFFLINE, true,
+  ui_tab_helper->ShowUIElement(previews::PreviewsType::OFFLINE,
                                base::BindOnce(&OnDismiss, &on_dismiss_value));
 
   EXPECT_FALSE(on_dismiss_value);
@@ -405,7 +354,7 @@
 
   base::Optional<bool> on_dismiss_value;
 
-  ui_tab_helper->ShowUIElement(previews::PreviewsType::OFFLINE, true,
+  ui_tab_helper->ShowUIElement(previews::PreviewsType::OFFLINE,
                                base::BindOnce(&OnDismiss, &on_dismiss_value));
 
   EXPECT_FALSE(on_dismiss_value);
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index 303312b..948304e 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -402,7 +402,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectBucketCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0, 1);
+      "Previews.PreviewShown.ResourceLoadingHints", true, 1);
   // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
@@ -427,7 +427,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 2);
   histogram_tester.ExpectBucketCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0, 2);
+      "Previews.PreviewShown.ResourceLoadingHints", true, 2);
   // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 2);
@@ -457,7 +457,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectTotalCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0);
+      "Previews.PreviewShown.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
   EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
@@ -498,7 +498,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectBucketCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0, 1);
+      "Previews.PreviewShown.ResourceLoadingHints", true, 1);
   // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
@@ -542,7 +542,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectBucketCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0, 1);
+      "Previews.PreviewShown.ResourceLoadingHints", true, 1);
   // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
@@ -583,7 +583,7 @@
   // Infobar would still be shown since there were at least one resource
   // loading hints available, even though none of them matched.
   RetryForHistogramUntilCountReached(
-      &histogram_tester, "Previews.InfoBarAction.ResourceLoadingHints", 1);
+      &histogram_tester, "Previews.PreviewShown.ResourceLoadingHints", 1);
   EXPECT_TRUE(resource_loading_hint_intervention_header_seen());
 }
 
@@ -616,7 +616,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 2);
   RetryForHistogramUntilCountReached(
-      &histogram_tester, "Previews.InfoBarAction.ResourceLoadingHints", 1);
+      &histogram_tester, "Previews.PreviewShown.ResourceLoadingHints", 1);
   // SetDefaultOnlyResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
@@ -645,7 +645,7 @@
           previews::PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
       1);
   histogram_tester.ExpectTotalCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0);
+      "Previews.PreviewShown.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
   EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
@@ -671,7 +671,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectTotalCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0);
+      "Previews.PreviewShown.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
   EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
@@ -698,7 +698,7 @@
       "Previews.EligibilityReason.ResourceLoadingHints",
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectTotalCount(
-      "Previews.InfoBarAction.ResourceLoadingHints", 0);
+      "Previews.PreviewShown.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
   EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc
index d21e737..9008f3e 100644
--- a/chrome/browser/renderer_preferences_util.cc
+++ b/chrome/browser/renderer_preferences_util.cc
@@ -118,8 +118,6 @@
   prefs->inactive_selection_bg_color = SkColorSetRGB(0xEA, 0xEA, 0xEA);
   prefs->inactive_selection_fg_color = SK_ColorBLACK;
 #endif
-#else
-  prefs->use_custom_colors = false;
 #endif
 
 #if defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/resources/downloads/BUILD.gn b/chrome/browser/resources/downloads/BUILD.gn
index ff97df9..85620b2 100644
--- a/chrome/browser/resources/downloads/BUILD.gn
+++ b/chrome/browser/resources/downloads/BUILD.gn
@@ -20,8 +20,8 @@
     js_out_files = [ "crisper.js" ]
     excludes = [
       "chrome://resources/js/mojo_bindings_lite.js",
-      "chrome://downloads/downloads.mojom-lite.js",
-      "chrome://downloads/downloads.mojom-lite.html",
+      "downloads.mojom-lite.js",
+      "downloads.mojom-lite.html",
     ]
     replace_for_html_imports_polyfill = "crisper.js"
 
diff --git a/chrome/browser/resources/downloads/browser_proxy.html b/chrome/browser/resources/downloads/browser_proxy.html
index 610c6459..b11be958 100644
--- a/chrome/browser/resources/downloads/browser_proxy.html
+++ b/chrome/browser/resources/downloads/browser_proxy.html
@@ -1,4 +1,4 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
-<link rel="import" href="chrome://downloads/downloads.mojom-lite.html">
+<link rel="import" href="downloads.mojom-lite.html">
 <script src="browser_proxy.js"></script>
diff --git a/chrome/browser/resources/downloads/constants.html b/chrome/browser/resources/downloads/constants.html
index 0ac6c26b..f6c8603 100644
--- a/chrome/browser/resources/downloads/constants.html
+++ b/chrome/browser/resources/downloads/constants.html
@@ -1,2 +1,2 @@
 <link rel="import" href="chrome://resources/html/cr.html">
-<script src="chrome://downloads/constants.js"></script>
+<script src="constants.js"></script>
diff --git a/chrome/browser/resources/downloads/downloads.html b/chrome/browser/resources/downloads/downloads.html
index a177651..05a625d 100644
--- a/chrome/browser/resources/downloads/downloads.html
+++ b/chrome/browser/resources/downloads/downloads.html
@@ -3,6 +3,9 @@
     $i18n{dark}>
 <head>
   <meta charset="utf-8">
+<if expr="not optimize_webui">
+  <base href="chrome://downloads">
+</if>
   <title>$i18n{title}</title>
   <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   <style>
@@ -47,9 +50,9 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="import" href="chrome://resources/html/cr.html">
   <link rel="import" href="chrome://resources/html/polymer.html">
-  <link rel="import" href="chrome://downloads/i18n_setup.html">
-  <link rel="import" href="chrome://downloads/manager.html">
-  <script src="chrome://downloads/downloads.js"></script>
+  <link rel="import" href="i18n_setup.html">
+  <link rel="import" href="manager.html">
+  <script src="downloads.js"></script>
   <link rel="import" href="chrome://resources/html/dark_mode.html">
 </body>
 </html>
diff --git a/chrome/browser/resources/downloads/i18n_setup.html b/chrome/browser/resources/downloads/i18n_setup.html
index 92fb6da4..b1bc3de 100644
--- a/chrome/browser/resources/downloads/i18n_setup.html
+++ b/chrome/browser/resources/downloads/i18n_setup.html
@@ -1,3 +1,3 @@
 <link rel="import" href="chrome://resources/html/load_time_data.html">
 
-<script src="chrome://downloads/strings.js"></script>
+<script src="strings.js"></script>
diff --git a/chrome/browser/resources/downloads/icon_loader.html b/chrome/browser/resources/downloads/icon_loader.html
index d489d71..db64c8d 100644
--- a/chrome/browser/resources/downloads/icon_loader.html
+++ b/chrome/browser/resources/downloads/icon_loader.html
@@ -1,4 +1,4 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/icon.html">
-<script src="chrome://downloads/icon_loader.js"></script>
+<script src="icon_loader.js"></script>
diff --git a/chrome/browser/resources/downloads/item.html b/chrome/browser/resources/downloads/item.html
index 136e77ec..8c9e616e 100644
--- a/chrome/browser/resources/downloads/item.html
+++ b/chrome/browser/resources/downloads/item.html
@@ -1,10 +1,10 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://downloads/browser_proxy.html">
-<link rel="import" href="chrome://downloads/constants.html">
-<link rel="import" href="chrome://downloads/i18n_setup.html">
-<link rel="import" href="chrome://downloads/icon_loader.html">
-<link rel="import" href="chrome://downloads/icons.html">
+<link rel="import" href="browser_proxy.html">
+<link rel="import" href="constants.html">
+<link rel="import" href="i18n_setup.html">
+<link rel="import" href="icon_loader.html">
+<link rel="import" href="icons.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
@@ -252,7 +252,7 @@
       }
 
       #incognito {
-        -webkit-mask-image: url(chrome://downloads/images/incognito_marker.svg);
+        -webkit-mask-image: url(images/incognito_marker.svg);
         background-color: var(--cr-secondary-text-color);
         bottom: 20px;
         height: 16px;
@@ -376,5 +376,5 @@
     </div>
 
   </template>
-  <script src="chrome://downloads/item.js"></script>
+  <script src="item.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/downloads/manager.html b/chrome/browser/resources/downloads/manager.html
index 52ab5c96..015710b 100644
--- a/chrome/browser/resources/downloads/manager.html
+++ b/chrome/browser/resources/downloads/manager.html
@@ -1,11 +1,11 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://downloads/browser_proxy.html">
-<link rel="import" href="chrome://downloads/constants.html">
-<link rel="import" href="chrome://downloads/i18n_setup.html">
-<link rel="import" href="chrome://downloads/item.html">
-<link rel="import" href="chrome://downloads/search_service.html">
-<link rel="import" href="chrome://downloads/toolbar.html">
+<link rel="import" href="browser_proxy.html">
+<link rel="import" href="constants.html">
+<link rel="import" href="i18n_setup.html">
+<link rel="import" href="item.html">
+<link rel="import" href="search_service.html">
+<link rel="import" href="toolbar.html">
 <link rel="import" href="chrome://resources/cr_components/managed_footnote/managed_footnote.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
 <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
@@ -86,7 +86,7 @@
       }
 
       #no-downloads .illustration {
-        background: url(chrome://downloads/images/no_downloads.svg) no-repeat
+        background: url(images/no_downloads.svg) no-repeat
             center center;
         background-size: contain;
         height: 144px;
@@ -145,5 +145,5 @@
         undo-description="$i18n{undoDescription}" duration="10000">
     </cr-toast-manager>
   </template>
-  <script src="chrome://downloads/manager.js"></script>
+  <script src="manager.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/downloads/manager.js b/chrome/browser/resources/downloads/manager.js
index a8d6788..d808927 100644
--- a/chrome/browser/resources/downloads/manager.js
+++ b/chrome/browser/resources/downloads/manager.js
@@ -88,6 +88,14 @@
       this.mojoEventTarget_ = browserProxy.callbackRouter;
       this.mojoHandler_ = browserProxy.handler;
       this.searchService_ = downloads.SearchService.getInstance();
+
+      // Regular expression that captures the leading slash, the content and the
+      // trailing slash in three different groups.
+      const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
+      const path = location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2');
+      if (path !== '/') {  // There are no subpages in chrome://downloads.
+        window.history.replaceState(undefined /* stateObject */, '', '/');
+      }
     },
 
     /** @override */
diff --git a/chrome/browser/resources/downloads/search_service.html b/chrome/browser/resources/downloads/search_service.html
index f37b195..e309b0a 100644
--- a/chrome/browser/resources/downloads/search_service.html
+++ b/chrome/browser/resources/downloads/search_service.html
@@ -1,4 +1,4 @@
 <link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://downloads/i18n_setup.html">
-<link rel="import" href="chrome://downloads/browser_proxy.html">
-<script src="chrome://downloads/search_service.js"></script>
+<link rel="import" href="i18n_setup.html">
+<link rel="import" href="browser_proxy.html">
+<script src="search_service.js"></script>
diff --git a/chrome/browser/resources/downloads/toolbar.html b/chrome/browser/resources/downloads/toolbar.html
index acbdae2..f90470d 100644
--- a/chrome/browser/resources/downloads/toolbar.html
+++ b/chrome/browser/resources/downloads/toolbar.html
@@ -1,7 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://downloads/search_service.html">
-<link rel="import" href="chrome://downloads/browser_proxy.html">
+<link rel="import" href="search_service.html">
+<link rel="import" href="browser_proxy.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
@@ -53,5 +53,5 @@
       </button>
     </cr-action-menu>
   </template>
-  <script src="chrome://downloads/toolbar.js"></script>
+  <script src="toolbar.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/feedback/js/event_handler.js b/chrome/browser/resources/feedback/js/event_handler.js
index 653cc0ae..5f9b2397 100644
--- a/chrome/browser/resources/feedback/js/event_handler.js
+++ b/chrome/browser/resources/feedback/js/event_handler.js
@@ -185,7 +185,9 @@
         this.feedbackInfo_, function(result, landingPageType) {
           if (result == chrome.feedbackPrivate.Status.SUCCESS) {
             console.log('Feedback: Report sent for request with ID ' + ID);
-            if (FLOW != chrome.feedbackPrivate.FeedbackFlow.LOGIN) {
+            if (FLOW != chrome.feedbackPrivate.FeedbackFlow.LOGIN &&
+                landingPageType !=
+                    chrome.feedbackPrivate.LandingPageType.NO_LANDING_PAGE) {
               const landingPage = landingPageType ==
                       chrome.feedbackPrivate.LandingPageType.NORMAL ?
                   FEEDBACK_LANDING_PAGE :
diff --git a/chrome/browser/resources/media/media_engagement.js b/chrome/browser/resources/media/media_engagement.js
index 5491928..e1df7c58 100644
--- a/chrome/browser/resources/media/media_engagement.js
+++ b/chrome/browser/resources/media/media_engagement.js
@@ -136,8 +136,6 @@
   configTableBody.appendChild(createConfigRow(
       'Preload MEI data', formatFeatureFlag(config.featurePreloadData)));
   configTableBody.appendChild(createConfigRow(
-      'MEI for HTTPS only', formatFeatureFlag(config.featureHttpsOnly)));
-  configTableBody.appendChild(createConfigRow(
       'Autoplay disable settings',
       formatFeatureFlag(config.featureAutoplayDisableSettings)));
   configTableBody.appendChild(createConfigRow(
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index 84a82ce..376f481 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -160,6 +160,12 @@
   return ProfileAllowsSigninCookies(profile_);
 }
 
+bool ChromeSigninClient::AreSigninCookiesDeletedOnExit() {
+  content_settings::CookieSettings* cookie_settings =
+      CookieSettingsFactory::GetForProfile(profile_).get();
+  return signin::SettingsDeleteSigninCookiesOnExit(cookie_settings);
+}
+
 void ChromeSigninClient::AddContentSettingsObserver(
     content_settings::Observer* observer) {
   HostContentSettingsMapFactory::GetForProfile(profile_)
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index bf666eb..f225d5403 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -54,6 +54,7 @@
   bool IsFirstRun() const override;
   base::Time GetInstallDate() override;
   bool AreSigninCookiesAllowed() override;
+  bool AreSigninCookiesDeletedOnExit() override;
   void AddContentSettingsObserver(
       content_settings::Observer* observer) override;
   void RemoveContentSettingsObserver(
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index d18147a..810e98a 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -681,6 +681,37 @@
   ASSERT_TRUE(SetupSync()) <<  "SetupSync() failed.";
 }
 
+IN_PROC_BROWSER_TEST_P(
+    SingleClientBookmarksSyncTest,
+    RemoveRightAfterAddShouldNotSendCommitRequestsOrTombstones) {
+  base::HistogramTester histogram_tester;
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+
+  // Add a folder and directly remove it.
+  ASSERT_NE(nullptr,
+            AddFolder(kSingleProfileIndex,
+                      /*parent=*/GetBookmarkBarNode(kSingleProfileIndex),
+                      /*index=*/0, "folder name"));
+  Remove(kSingleProfileIndex,
+         /*parent=*/GetBookmarkBarNode(kSingleProfileIndex), 0);
+
+  // Add another bookmark to make sure a full sync cycle completion.
+  ASSERT_NE(nullptr, AddURL(kSingleProfileIndex,
+                            /*parent=*/GetOtherNode(kSingleProfileIndex),
+                            /*index=*/0, "title", GURL("http://www.url.com")));
+  ASSERT_TRUE(
+      UpdatedProgressMarkerChecker(GetSyncService(kSingleProfileIndex)).Wait());
+  EXPECT_TRUE(ModelMatchesVerifier(kSingleProfileIndex));
+
+  // There should have been one creation and no deletions.
+  EXPECT_EQ(
+      1, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.BOOKMARK",
+                                         /*LOCAL_CREATION=*/1));
+  EXPECT_EQ(
+      0, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.BOOKMARK",
+                                         /*LOCAL_DELETION=*/0));
+}
+
 IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTest,
                        PRE_PersistProgressMarkerOnRestart) {
   const std::string title = "Seattle Sounders FC";
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index bf9797c..04eaa25 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -661,8 +661,6 @@
       "android/infobars/near_oom_reduction_infobar.h",
       "android/infobars/permission_infobar.cc",
       "android/infobars/permission_infobar.h",
-      "android/infobars/previews_infobar.cc",
-      "android/infobars/previews_infobar.h",
       "android/infobars/previews_lite_page_infobar.cc",
       "android/infobars/previews_lite_page_infobar.h",
       "android/infobars/reader_mode_infobar.cc",
diff --git a/chrome/browser/ui/android/infobars/previews_infobar.cc b/chrome/browser/ui/android/infobars/previews_infobar.cc
deleted file mode 100644
index b0cbd1b..0000000
--- a/chrome/browser/ui/android/infobars/previews_infobar.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/android/infobars/previews_infobar.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "jni/PreviewsInfoBar_jni.h"
-
-PreviewsInfoBar::PreviewsInfoBar(
-    std::unique_ptr<PreviewsInfoBarDelegate> delegate)
-    : ConfirmInfoBar(std::move(delegate)) {}
-
-PreviewsInfoBar::~PreviewsInfoBar() {}
-
-base::android::ScopedJavaLocalRef<jobject> PreviewsInfoBar::CreateRenderInfoBar(
-    JNIEnv* env) {
-  PreviewsInfoBarDelegate* delegate =
-      static_cast<PreviewsInfoBarDelegate*>(GetDelegate());
-  base::android::ScopedJavaLocalRef<jstring> message_text =
-      base::android::ConvertUTF16ToJavaString(env, delegate->GetMessageText());
-  base::android::ScopedJavaLocalRef<jstring> link_text =
-      base::android::ConvertUTF16ToJavaString(env, delegate->GetLinkText());
-  base::android::ScopedJavaLocalRef<jstring> timestamp_text =
-      base::android::ConvertUTF16ToJavaString(
-          env, delegate->GetStalePreviewTimestampText());
-  return Java_PreviewsInfoBar_show(env, GetEnumeratedIconId(), message_text,
-                                   link_text, timestamp_text);
-}
-
-// static
-std::unique_ptr<infobars::InfoBar> PreviewsInfoBar::CreateInfoBar(
-    infobars::InfoBarManager* infobar_manager,
-    std::unique_ptr<PreviewsInfoBarDelegate> delegate) {
-  return std::make_unique<PreviewsInfoBar>(std::move(delegate));
-}
diff --git a/chrome/browser/ui/android/infobars/previews_infobar.h b/chrome/browser/ui/android/infobars/previews_infobar.h
deleted file mode 100644
index 8c71ca83..0000000
--- a/chrome/browser/ui/android/infobars/previews_infobar.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_PREVIEWS_INFOBAR_H_
-#define CHROME_BROWSER_UI_ANDROID_INFOBARS_PREVIEWS_INFOBAR_H_
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "chrome/browser/previews/previews_infobar_delegate.h"
-#include "chrome/browser/ui/android/infobars/confirm_infobar.h"
-
-class PreviewsInfoBar : public ConfirmInfoBar {
- public:
-  explicit PreviewsInfoBar(std::unique_ptr<PreviewsInfoBarDelegate> delegate);
-
-  ~PreviewsInfoBar() override;
-
-  // Returns a Previews infobar that owns |delegate|.
-  static std::unique_ptr<infobars::InfoBar> CreateInfoBar(
-      infobars::InfoBarManager* infobar_manager,
-      std::unique_ptr<PreviewsInfoBarDelegate> delegate);
-
- private:
-  // ConfirmInfoBar:
-  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
-      JNIEnv* env) override;
-
-  DISALLOW_COPY_AND_ASSIGN(PreviewsInfoBar);
-};
-
-#endif  // CHROME_BROWSER_UI_ANDROID_INFOBARS_PREVIEWS_INFOBAR_H_
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index ed2e5978..031a43d3 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -64,8 +64,6 @@
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ws/public/mojom/user_activity_monitor.mojom.h"
-#include "ui/aura/mus/property_converter.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/ui_base_features.h"
 
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index db7a79d..f7a163b 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
@@ -61,6 +62,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/content_restriction.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
@@ -96,6 +98,7 @@
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "url/gurl.h"
+#include "url/url_constants.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/api/commands/command_service.h"
@@ -533,6 +536,11 @@
     extensions::MaybeShowExtensionControlledHomeNotification(browser);
 #endif
 
+  bool is_chrome_internal = url.SchemeIs(url::kAboutScheme) ||
+                            url.SchemeIs(content::kChromeUIScheme) ||
+                            url.SchemeIs(chrome::kChromeNativeScheme);
+  base::UmaHistogramBoolean("Navigation.Home.IsChromeInternal",
+                            is_chrome_internal);
   OpenURLParams params(
       url, Referrer(), disposition,
       ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_BOOKMARK |
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
index fbb7e5c..22fa67eb 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -563,29 +563,9 @@
 }
 
 void RecentTabsSubMenuModel::AddTabFavicon(int command_id, const GURL& url) {
-  bool is_local_tab = command_id < kFirstOtherDevicesTabCommandId;
   int index_in_menu = GetIndexOfCommandId(command_id);
 
-  if (!is_local_tab) {
-    // If tab has synced favicon, use it.
-    // Note that currently, other devices' tabs only have favicons if
-    // --sync-tab-favicons switch is on; according to zea@, this flag is now
-    // automatically enabled for iOS and android, and they're looking into
-    // enabling it for other platforms.
-    sync_sessions::OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate();
-    scoped_refptr<base::RefCountedMemory> favicon_png;
-    if (open_tabs &&
-        open_tabs->GetSyncedFaviconForPageURL(url.spec(), &favicon_png)) {
-      favicon::RecordFaviconRequestMetric(
-          favicon::FaviconRequestOrigin::RECENTLY_CLOSED_TABS,
-          favicon::FaviconAvailability::kSync);
-      gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(favicon_png);
-      SetIcon(index_in_menu, image);
-      return;
-    }
-  }
-
-  // Otherwise, start to fetch the favicon from local history asynchronously.
+  // Start to fetch the favicon from local history asynchronously.
   // Set default icon first.
   SetIcon(index_in_menu, favicon::GetDefaultFavicon());
   // Start request to fetch actual icon if possible.
@@ -595,34 +575,52 @@
   if (!favicon_service)
     return;
 
+  bool is_local_tab = command_id < kFirstOtherDevicesTabCommandId;
   favicon_service->GetFaviconImageForPageURL(
       url,
       base::Bind(&RecentTabsSubMenuModel::OnFaviconDataAvailable,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 command_id),
+                 weak_ptr_factory_.GetWeakPtr(), url, command_id),
       is_local_tab ? &local_tab_cancelable_task_tracker_
                    : &other_devices_tab_cancelable_task_tracker_);
 }
 
 void RecentTabsSubMenuModel::OnFaviconDataAvailable(
+    const GURL& page_url,
     int command_id,
     const favicon_base::FaviconImageResult& image_result) {
-  if (image_result.image.IsEmpty()) {
+  int index_in_menu = GetIndexOfCommandId(command_id);
+  if (!image_result.image.IsEmpty()) {
     favicon::RecordFaviconRequestMetric(
         favicon::FaviconRequestOrigin::RECENTLY_CLOSED_TABS,
-        favicon::FaviconAvailability::kNotAvailable);
+        favicon::FaviconAvailability::kLocal);
+    DCHECK_GT(index_in_menu, -1);
+    SetIcon(index_in_menu, image_result.image);
+    ui::MenuModelDelegate* delegate = menu_model_delegate();
+    if (delegate)
+      delegate->OnIconChanged(index_in_menu);
+    return;
+  }
+
+  // If tab has synced favicon, use it.
+  // Note that currently, other devices' tabs only have favicons if
+  // --sync-tab-favicons switch is on; according to zea@, this flag is now
+  // automatically enabled for iOS and android, and they're looking into
+  // enabling it for other platforms.
+  sync_sessions::OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate();
+  scoped_refptr<base::RefCountedMemory> favicon_png;
+  if (open_tabs &&
+      open_tabs->GetSyncedFaviconForPageURL(page_url.spec(), &favicon_png)) {
+    favicon::RecordFaviconRequestMetric(
+        favicon::FaviconRequestOrigin::RECENTLY_CLOSED_TABS,
+        favicon::FaviconAvailability::kSync);
+    gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(favicon_png);
+    SetIcon(index_in_menu, image);
     return;
   }
 
   favicon::RecordFaviconRequestMetric(
       favicon::FaviconRequestOrigin::RECENTLY_CLOSED_TABS,
-      favicon::FaviconAvailability::kLocal);
-  int index_in_menu = GetIndexOfCommandId(command_id);
-  DCHECK_GT(index_in_menu, -1);
-  SetIcon(index_in_menu, image_result.image);
-  ui::MenuModelDelegate* delegate = menu_model_delegate();
-  if (delegate)
-    delegate->OnIconChanged(index_in_menu);
+      favicon::FaviconAvailability::kNotAvailable);
 }
 
 int RecentTabsSubMenuModel::CommandIdToTabVectorIndex(
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
index 515952c..bb359723 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
@@ -119,6 +119,7 @@
   // OnFaviconDataAvailable() will be invoked when the favicon is ready.
   void AddTabFavicon(int command_id, const GURL& url);
   void OnFaviconDataAvailable(
+      const GURL& page_url,
       int command_id,
       const favicon_base::FaviconImageResult& image_result);
 
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 6d9b1cb..64368f8 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -70,7 +70,7 @@
 
   std::vector<ToolbarActionView*> GetVisibleToolbarActionViews() const {
     auto views = GetToolbarActionViews();
-    base::EraseIf(views, [](views::View* view) { return !view->visible(); });
+    base::EraseIf(views, [](views::View* view) { return !view->GetVisible(); });
     return views;
   }
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index ff296a52a..a1f0bcdf 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -49,8 +49,6 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
-#include "ui/aura/mus/window_mus.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/layout.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index 2a35daa..c6cb007 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -20,10 +20,6 @@
 #include "services/ws/public/cpp/property_type_converters.h"
 #include "services/ws/public/mojom/window_manager.mojom.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/mus/mus_types.h"
-#include "ui/aura/mus/property_converter.h"
-#include "ui/aura/mus/window_port_mus.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_targeter.h"
 #include "ui/compositor/layer.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
index 9fee25dd..94034539 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -71,7 +71,7 @@
     // which triggers an animation.
     ash::ImmersiveFullscreenControllerTestApi(
         static_cast<ImmersiveModeControllerAsh*>(controller_)->controller())
-        .SetupForTest(/*wait_for_mouse_event=*/wait);
+        .SetupForTest();
 
     browser_->window()->Show();
   }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index 03019696..9f9020141 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -444,10 +444,11 @@
                  kImageButton) {
     DCHECK_EQ(std::string(views::ImageButton::kViewClassName),
               button->GetClassName());
-    static_cast<views::ImageButton*>(button)->SetImageAlignment(
+    auto* const image_button = static_cast<views::ImageButton*>(button);
+    image_button->SetImageHorizontalAlignment(
         (alignment == ALIGN_LEADING) ? views::ImageButton::ALIGN_RIGHT
-                                     : views::ImageButton::ALIGN_LEFT,
-        views::ImageButton::ALIGN_BOTTOM);
+                                     : views::ImageButton::ALIGN_LEFT);
+    image_button->SetImageVerticalAlignment(views::ImageButton::ALIGN_BOTTOM);
   }
 
   TopAreaPadding top_area_padding = GetTopAreaPadding();
diff --git a/chrome/browser/ui/views/ime/ime_window_frame_view.cc b/chrome/browser/ui/views/ime/ime_window_frame_view.cc
index c689b59..8779bd6 100644
--- a/chrome/browser/ui/views/ime/ime_window_frame_view.cc
+++ b/chrome/browser/ui/views/ime/ime_window_frame_view.cc
@@ -41,8 +41,8 @@
                           rb.GetImageSkiaNamed(IDR_IME_WINDOW_CLOSE_H));
   close_button_->SetImage(views::Button::STATE_PRESSED,
                           rb.GetImageSkiaNamed(IDR_IME_WINDOW_CLOSE_C));
-  close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                                   views::ImageButton::ALIGN_MIDDLE);
+  close_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  close_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   close_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
   AddChildView(close_button_);
diff --git a/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc b/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc
index 17d664e..8e4deaf 100644
--- a/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc
+++ b/chrome/browser/ui/views/overlay/back_to_tab_image_button.cc
@@ -23,8 +23,8 @@
 
 BackToTabImageButton::BackToTabImageButton(ButtonListener* listener)
     : ImageButton(listener) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   SetImage(views::Button::STATE_NORMAL,
            gfx::CreateVectorIcon(views::kLaunchIcon, kBackToTabImageSize,
                                  kBackToTabIconColor));
diff --git a/chrome/browser/ui/views/overlay/close_image_button.cc b/chrome/browser/ui/views/overlay/close_image_button.cc
index b68170b..0aca251 100644
--- a/chrome/browser/ui/views/overlay/close_image_button.cc
+++ b/chrome/browser/ui/views/overlay/close_image_button.cc
@@ -24,8 +24,8 @@
 
 CloseImageButton::CloseImageButton(ButtonListener* listener)
     : ImageButton(listener) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   SetSize(gfx::Size(kCloseButtonSize, kCloseButtonSize));
   SetImage(views::Button::STATE_NORMAL,
            gfx::CreateVectorIcon(views::kIcCloseIcon, kCloseButtonSize,
diff --git a/chrome/browser/ui/views/overlay/mute_image_button.cc b/chrome/browser/ui/views/overlay/mute_image_button.cc
index c2bab8a..8c88ef08 100644
--- a/chrome/browser/ui/views/overlay/mute_image_button.cc
+++ b/chrome/browser/ui/views/overlay/mute_image_button.cc
@@ -30,8 +30,8 @@
       unmute_image_(gfx::CreateVectorIcon(kTabAudioMutingIcon,
                                           kMuteImageSize,
                                           kMuteIconColor)) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
 
   // Accessibility.
   SetFocusForPlatform();
diff --git a/chrome/browser/ui/views/overlay/playback_image_button.cc b/chrome/browser/ui/views/overlay/playback_image_button.cc
index 5940480..d9e5174e 100644
--- a/chrome/browser/ui/views/overlay/playback_image_button.cc
+++ b/chrome/browser/ui/views/overlay/playback_image_button.cc
@@ -22,8 +22,8 @@
 
 PlaybackImageButton::PlaybackImageButton(ButtonListener* listener)
     : ImageButton(listener) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
 
   // Accessibility.
   SetFocusForPlatform();
diff --git a/chrome/browser/ui/views/overlay/resize_handle_button.cc b/chrome/browser/ui/views/overlay/resize_handle_button.cc
index 72cc587..ee6b361 100644
--- a/chrome/browser/ui/views/overlay/resize_handle_button.cc
+++ b/chrome/browser/ui/views/overlay/resize_handle_button.cc
@@ -28,8 +28,6 @@
 
 ResizeHandleButton::ResizeHandleButton(ButtonListener* listener)
     : ImageButton(listener) {
-  SetImageAlignment(views::ImageButton::ALIGN_LEFT,
-                    views::ImageButton::ALIGN_TOP);
   SetSize(gfx::Size(kResizeHandleButtonSize, kResizeHandleButtonSize));
   SetImageForQuadrant(OverlayWindowViews::WindowQuadrant::kBottomRight);
 
@@ -101,24 +99,24 @@
       kResizeHandleIcon, kResizeHandleButtonSize, kResizeHandleIconColor);
   switch (quadrant) {
     case OverlayWindowViews::WindowQuadrant::kBottomLeft:
-      SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
-                        views::ImageButton::ALIGN_TOP);
+      SetImageHorizontalAlignment(views::ImageButton::ALIGN_RIGHT);
+      SetImageVerticalAlignment(views::ImageButton::ALIGN_TOP);
       break;
     case OverlayWindowViews::WindowQuadrant::kBottomRight:
-      SetImageAlignment(views::ImageButton::ALIGN_LEFT,
-                        views::ImageButton::ALIGN_TOP);
+      SetImageHorizontalAlignment(views::ImageButton::ALIGN_LEFT);
+      SetImageVerticalAlignment(views::ImageButton::ALIGN_TOP);
       icon = gfx::ImageSkiaOperations::CreateRotatedImage(
           icon, SkBitmapOperations::ROTATION_270_CW);
       break;
     case OverlayWindowViews::WindowQuadrant::kTopLeft:
-      SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
-                        views::ImageButton::ALIGN_BOTTOM);
+      SetImageHorizontalAlignment(views::ImageButton::ALIGN_RIGHT);
+      SetImageVerticalAlignment(views::ImageButton::ALIGN_BOTTOM);
       icon = gfx::ImageSkiaOperations::CreateRotatedImage(
           icon, SkBitmapOperations::ROTATION_90_CW);
       break;
     case OverlayWindowViews::WindowQuadrant::kTopRight:
-      SetImageAlignment(views::ImageButton::ALIGN_LEFT,
-                        views::ImageButton::ALIGN_BOTTOM);
+      SetImageHorizontalAlignment(views::ImageButton::ALIGN_LEFT);
+      SetImageVerticalAlignment(views::ImageButton::ALIGN_BOTTOM);
       icon = gfx::ImageSkiaOperations::CreateRotatedImage(
           icon, SkBitmapOperations::ROTATION_180_CW);
       break;
diff --git a/chrome/browser/ui/views/overlay/track_image_button.cc b/chrome/browser/ui/views/overlay/track_image_button.cc
index 83814c9..8f42277 100644
--- a/chrome/browser/ui/views/overlay/track_image_button.cc
+++ b/chrome/browser/ui/views/overlay/track_image_button.cc
@@ -27,8 +27,8 @@
                                    base::string16 label)
     : ImageButton(listener),
       image_(gfx::CreateVectorIcon(icon, kTrackImageSize, kTrackIconColor)) {
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   SetImage(views::Button::STATE_NORMAL, image_);
 
   // Accessibility.
diff --git a/chrome/browser/ui/views/passwords/password_bubble_view_base.cc b/chrome/browser/ui/views/passwords/password_bubble_view_base.cc
index 739cdef..463b433 100644
--- a/chrome/browser/ui/views/passwords/password_bubble_view_base.cc
+++ b/chrome/browser/ui/views/passwords/password_bubble_view_base.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
+#include "ui/views/controls/button/button.h"
 
 // static
 PasswordBubbleViewBase* PasswordBubbleViewBase::g_manage_passwords_bubble_ =
@@ -48,10 +49,19 @@
   DCHECK(bubble == g_manage_passwords_bubble_);
 
   if (anchor_view) {
-    g_manage_passwords_bubble_->SetHighlightedButton(
-        browser_view->toolbar_button_provider()
-            ->GetOmniboxPageActionIconContainerView()
-            ->GetPageActionIconView(PageActionIconType::kManagePasswords));
+    views::Button* highlighted_button;
+    if (base::FeatureList::IsEnabled(
+            autofill::features::kAutofillEnableToolbarStatusChip)) {
+      highlighted_button =
+          browser_view->toolbar()->toolbar_page_action_container()->GetIconView(
+              PageActionIconType::kManagePasswords);
+    } else {
+      highlighted_button =
+          browser_view->toolbar_button_provider()
+              ->GetOmniboxPageActionIconContainerView()
+              ->GetPageActionIconView(PageActionIconType::kManagePasswords);
+    }
+    g_manage_passwords_bubble_->SetHighlightedButton(highlighted_button);
   } else {
     g_manage_passwords_bubble_->set_parent_window(
         web_contents->GetNativeView());
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.cc b/chrome/browser/ui/views/passwords/password_pending_view.cc
index ba46281b..131846cf 100644
--- a/chrome/browser/ui/views/passwords/password_pending_view.cc
+++ b/chrome/browser/ui/views/passwords/password_pending_view.cc
@@ -165,8 +165,8 @@
       views::ImageButton::STATE_NORMAL,
       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
           IDR_HIDE_PASSWORD_HOVER));
-  button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                            views::ImageButton::ALIGN_MIDDLE);
+  button->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  button->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   button->SetToggled(are_passwords_revealed);
   return button;
 }
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 07febed6..82ca994 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -155,6 +155,7 @@
       this, base::BindRepeating(&TabController::OnMouseEventInTab,
                                 base::Unretained(controller_)));
   AddChildView(close_button_);
+  close_button_->AddObserver(this);
 
   set_context_menu_controller(this);
 
@@ -165,7 +166,9 @@
   focus_ring_ = views::FocusRing::Install(this);
 }
 
-Tab::~Tab() = default;
+Tab::~Tab() {
+  close_button_->RemoveObserver(this);
+}
 
 void Tab::AnimationEnded(const gfx::Animation* animation) {
   DCHECK_EQ(animation, &title_animation_);
@@ -592,10 +595,18 @@
   UpdateForegroundColors();
 }
 
+void Tab::OnFocus() {
+  controller_->UpdateHoverCard(this, true);
+}
+
 void Tab::OnThemeChanged() {
   UpdateForegroundColors();
 }
 
+void Tab::OnViewFocused(views::View* observed_view) {
+  controller_->UpdateHoverCard(this, true);
+}
+
 void Tab::SetClosing(bool closing) {
   closing_ = closing;
   ActiveStateChanged();
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index a05900b3..d646db8 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -47,7 +47,8 @@
             public views::ButtonListener,
             public views::ContextMenuController,
             public views::MaskedTargeterDelegate,
-            public views::View {
+            public views::View,
+            public views::ViewObserver {
  public:
   // The Tab's class name.
   static const char kViewClassName[];
@@ -95,8 +96,12 @@
   void PaintChildren(const views::PaintInfo& info) override;
   void OnPaint(gfx::Canvas* canvas) override;
   void AddedToWidget() override;
+  void OnFocus() override;
   void OnThemeChanged() override;
 
+  // views::ViewObserver:
+  void OnViewFocused(views::View* observed_view) override;
+
   TabController* controller() const { return controller_; }
 
   // Used to set/check whether this Tab is being animated closed.
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index ea986bc..40c8f34 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -84,7 +84,6 @@
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/mus/window_mus.h"
 #include "ui/aura/test/mus/change_completion_waiter.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/ui_base_features.h"
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 1a444c2..63701b40 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -354,7 +354,8 @@
   fade_animation_delegate_->CancelFadeOut();
 
   if (!widget_->IsVisible()) {
-    if (disable_animations_for_testing_ || show_immediately) {
+    if (disable_animations_for_testing_ || show_immediately ||
+        tab->HasFocus()) {
       widget_->Show();
     } else {
       // Note that this will restart the timer if it is already running. If the
@@ -367,6 +368,8 @@
 }
 
 void TabHoverCardBubbleView::FadeOutToHide() {
+  if (!widget_->IsVisible())
+    return;
   delayed_show_timer_.Stop();
   last_visible_timestamp_ = base::TimeTicks::Now();
   if (disable_animations_for_testing_) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 56e0157..36444ce4 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -119,8 +119,10 @@
 class TabHoverCardEventSniffer : public ui::EventHandler {
  public:
   TabHoverCardEventSniffer(TabHoverCardBubbleView* hover_card,
-                           views::Widget* widget)
-      : hover_card_(hover_card), widget_(widget) {
+                           TabStrip* tab_strip)
+      : hover_card_(hover_card),
+        tab_strip_(tab_strip),
+        widget_(tab_strip->GetWidget()) {
 #if defined(OS_MACOSX)
     if (widget_->GetRootView())
       widget_->GetRootView()->AddPreTargetHandler(this);
@@ -141,11 +143,22 @@
  protected:
   // ui::EventTarget:
   void OnKeyEvent(ui::KeyEvent* event) override {
-    hover_card_->FadeOutToHide();
+    if (!TabStripIsKeyboardFocused())
+      hover_card_->FadeOutToHide();
+  }
+
+  void OnMouseEvent(ui::MouseEvent* event) override {
+    if (event->IsAnyButton())
+      hover_card_->FadeOutToHide();
   }
 
  private:
+  bool TabStripIsKeyboardFocused() {
+    return tab_strip_->GetPaneFocusTraversable() != nullptr;
+  }
+
   TabHoverCardBubbleView* const hover_card_;
+  TabStrip* tab_strip_;
   views::Widget* widget_;
 };
 
@@ -1558,7 +1571,7 @@
     hover_card_->views::View::AddObserver(this);
     if (GetWidget()) {
       hover_card_event_sniffer_ =
-          std::make_unique<TabHoverCardEventSniffer>(hover_card_, GetWidget());
+          std::make_unique<TabHoverCardEventSniffer>(hover_card_, this);
     }
   }
   if (should_show)
@@ -2017,8 +2030,7 @@
       l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB));
   new_tab_button_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB));
-  new_tab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
-                                     views::ImageButton::ALIGN_BOTTOM);
+  new_tab_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_BOTTOM);
   new_tab_button_->SetEventTargeter(
       std::make_unique<views::ViewTargeter>(new_tab_button_));
   AddChildView(new_tab_button_);
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 7ec5b4e1..bcec2ab 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -522,8 +522,8 @@
     // focusable regardless of the platform.
     fullscreen_button_->SetFocusBehavior(FocusBehavior::ALWAYS);
     fullscreen_button_->set_tag(fullscreen_index);
-    fullscreen_button_->SetImageAlignment(
-        ImageButton::ALIGN_CENTER, ImageButton::ALIGN_MIDDLE);
+    fullscreen_button_->SetImageHorizontalAlignment(ImageButton::ALIGN_CENTER);
+    fullscreen_button_->SetImageVerticalAlignment(ImageButton::ALIGN_MIDDLE);
     fullscreen_button_->SetBackground(std::make_unique<InMenuButtonBackground>(
         InMenuButtonBackground::LEADING_BORDER));
     fullscreen_button_->SetAccessibleName(GetAccessibleNameForAppMenuItem(
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
index 879f9e7..578e9024 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/feature_switch.h"
@@ -101,9 +102,8 @@
   // Click on the toolbar action to activate it.
   gfx::Point action_view_loc =
       ui_test_utils::GetCenterInScreenCoordinates(action_view);
-  EXPECT_TRUE(
-      ui_controls::SendMouseMove(action_view_loc.x(), action_view_loc.y()));
-  EXPECT_TRUE(ui_controls::SendMouseClick(button));
+  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(action_view_loc));
+  ASSERT_TRUE(ui_controls::SendMouseClick(button));
   base::RunLoop().RunUntilIdle();
 
   if (toolbar_action_view)
@@ -216,13 +216,13 @@
   // Click on the app button.
   gfx::Point app_button_loc =
       ui_test_utils::GetCenterInScreenCoordinates(app_menu_button);
-  EXPECT_TRUE(
-      ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y()));
-  EXPECT_TRUE(ui_controls::SendMouseClick(ui_controls::LEFT));
+  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(app_button_loc));
+  ASSERT_TRUE(ui_controls::SendMouseClick(ui_controls::LEFT));
   AppMenuShowingWaiter waiter(app_menu_button);
   waiter.Wait();
 
-  TestOverflowedToolbarAction(browser(), ui_controls::LEFT, nullptr);
+  ASSERT_NO_FATAL_FAILURE(
+      TestOverflowedToolbarAction(browser(), ui_controls::LEFT, nullptr));
 
   // The app menu should no longer be showing.
   EXPECT_FALSE(app_menu_button->IsMenuShowing());
@@ -281,7 +281,8 @@
 
   // Right click on the action view. This should trigger the context menu.
   ToolbarActionView* action_view = nullptr;
-  TestOverflowedToolbarAction(browser(), ui_controls::RIGHT, &action_view);
+  ASSERT_NO_FATAL_FAILURE(
+      TestOverflowedToolbarAction(browser(), ui_controls::RIGHT, &action_view));
 
   // Ensure that the menu actually opened.
   EXPECT_TRUE(action_view->IsMenuRunningForTesting());
@@ -375,9 +376,8 @@
   auto* app_menu_button = GetAppMenuButtonFromBrowser(browser());
   gfx::Point app_button_loc =
       ui_test_utils::GetCenterInScreenCoordinates(app_menu_button);
-  EXPECT_TRUE(
-      ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y()));
-  EXPECT_TRUE(ui_controls::SendMouseClick(ui_controls::LEFT));
+  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(app_button_loc));
+  ASSERT_TRUE(ui_controls::SendMouseClick(ui_controls::LEFT));
   AppMenuShowingWaiter waiter(app_menu_button);
   waiter.Wait();
 
@@ -386,11 +386,11 @@
       views::MenuController::GetActiveInstance()->owner()->GetNativeWindow();
   // Send a key down event followed by the return key.
   // The key down event targets the toolbar action in the app menu.
-  EXPECT_TRUE(ui_controls::SendKeyPress(native_window, ui::VKEY_DOWN, false,
+  ASSERT_TRUE(ui_controls::SendKeyPress(native_window, ui::VKEY_DOWN, false,
                                         false, false, false));
   // The triggering of the action and subsequent widget destruction occurs on
   // the message loop. Wait for this all to complete.
-  EXPECT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+  ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
       native_window, ui::VKEY_RETURN, false, false, false, false));
 
   // The menu should be closed.
diff --git a/chrome/browser/ui/webui/media/media_engagement_ui.cc b/chrome/browser/ui/webui/media/media_engagement_ui.cc
index e69a536..1e293ad3 100644
--- a/chrome/browser/ui/webui/media/media_engagement_ui.cc
+++ b/chrome/browser/ui/webui/media/media_engagement_ui.cc
@@ -78,7 +78,6 @@
         base::FeatureList::IsEnabled(
             media::kMediaEngagementBypassAutoplayPolicies),
         base::FeatureList::IsEnabled(media::kPreloadMediaEngagementData),
-        base::FeatureList::IsEnabled(media::kMediaEngagementHTTPSOnly),
         base::FeatureList::IsEnabled(media::kAutoplayDisableSettings),
         base::FeatureList::IsEnabled(media::kAutoplayWhitelistSettings),
         GetBlockAutoplayPref(),
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 2c54fe7..d133f58d 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -669,6 +669,8 @@
     sources = [
       "test/conditional_skipping.cc",
       "test/conditional_skipping.h",
+      "test/fake_xr_session_request_consent_manager.cc",
+      "test/fake_xr_session_request_consent_manager.h",
       "test/mock_xr_device_hook_base.cc",
       "test/mock_xr_device_hook_base.h",
       "test/mock_xr_session_request_consent_manager.cc",
@@ -728,6 +730,7 @@
 
       # Tests.
       sources += [
+        "webxr_vr_consent_dialog_browser_test.cc",
         "webxr_vr_frame_pose_browser_test.cc",
         "webxr_vr_indicators_browser_test.cc",
         "webxr_vr_input_browser_test.cc",
diff --git a/chrome/browser/vr/service/xr_session_request_consent_manager.h b/chrome/browser/vr/service/xr_session_request_consent_manager.h
index bc38195..37d763e 100644
--- a/chrome/browser/vr/service/xr_session_request_consent_manager.h
+++ b/chrome/browser/vr/service/xr_session_request_consent_manager.h
@@ -12,6 +12,8 @@
 class WebContents;
 }
 
+class TabModalConfirmDialog;
+
 namespace vr {
 
 // Abstract class to break a dependency loop between the "vr_common" component
@@ -42,7 +44,7 @@
   // |response_callback| is guaranteed to be called with 'true' as arg if
   // the user presses the 'accept' button, or with 'false' if the user
   // either closes the dialog by any means or clicks on 'cancel' button.
-  virtual void ShowDialogAndGetConsent(
+  virtual TabModalConfirmDialog* ShowDialogAndGetConsent(
       content::WebContents* web_contents,
       base::OnceCallback<void(bool)> response_callback) = 0;
 };
diff --git a/chrome/browser/vr/service/xr_session_request_consent_manager_impl.cc b/chrome/browser/vr/service/xr_session_request_consent_manager_impl.cc
index 2818381..71680f6 100644
--- a/chrome/browser/vr/service/xr_session_request_consent_manager_impl.cc
+++ b/chrome/browser/vr/service/xr_session_request_consent_manager_impl.cc
@@ -18,12 +18,14 @@
 XRSessionRequestConsentManagerImpl::~XRSessionRequestConsentManagerImpl() =
     default;
 
-void XRSessionRequestConsentManagerImpl::ShowDialogAndGetConsent(
+TabModalConfirmDialog*
+XRSessionRequestConsentManagerImpl::ShowDialogAndGetConsent(
     content::WebContents* web_contents,
     base::OnceCallback<void(bool)> response_callback) {
-  TabModalConfirmDialog::Create(new XrSessionRequestConsentDialogDelegate(
-                                    web_contents, std::move(response_callback)),
-                                web_contents);
+  return TabModalConfirmDialog::Create(
+      new XrSessionRequestConsentDialogDelegate(web_contents,
+                                                std::move(response_callback)),
+      web_contents);
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/service/xr_session_request_consent_manager_impl.h b/chrome/browser/vr/service/xr_session_request_consent_manager_impl.h
index b1f3eea6..d2e2b027 100644
--- a/chrome/browser/vr/service/xr_session_request_consent_manager_impl.h
+++ b/chrome/browser/vr/service/xr_session_request_consent_manager_impl.h
@@ -19,7 +19,7 @@
   ~XRSessionRequestConsentManagerImpl() override;
 
   // XRSessionRequestConsentManager:
-  void ShowDialogAndGetConsent(
+  TabModalConfirmDialog* ShowDialogAndGetConsent(
       content::WebContents* web_contents,
       base::OnceCallback<void(bool)> response_callback) override;
 
diff --git a/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc b/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc
new file mode 100644
index 0000000..6eac1495
--- /dev/null
+++ b/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc
@@ -0,0 +1,55 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/vr/test/fake_xr_session_request_consent_manager.h"
+
+#include <utility>
+
+#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
+#include "content/public/test/test_utils.h"
+
+namespace vr {
+
+namespace {
+static constexpr base::TimeDelta kConsentDialogDisplayingTime =
+    base::TimeDelta::FromMilliseconds(250);
+}  // namespace
+
+FakeXRSessionRequestConsentManager::FakeXRSessionRequestConsentManager(
+    XRSessionRequestConsentManager* consent_manager,
+    UserResponse user_response)
+    : consent_manager_(consent_manager), user_response_(user_response) {}
+
+FakeXRSessionRequestConsentManager::~FakeXRSessionRequestConsentManager() =
+    default;
+
+TabModalConfirmDialog*
+FakeXRSessionRequestConsentManager::ShowDialogAndGetConsent(
+    content::WebContents* web_contents,
+    base::OnceCallback<void(bool)> response_callback) {
+  auto* confirm_dialog = consent_manager_->ShowDialogAndGetConsent(
+      web_contents, std::move(response_callback));
+
+  // Allow the dialog to show at least for a little while before simulating
+  // the action.
+  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitWhenIdleClosure(), kConsentDialogDisplayingTime);
+  run_loop.Run();
+
+  switch (user_response_) {
+    case UserResponse::kClickAllowButton:
+      confirm_dialog->AcceptTabModalDialog();
+      break;
+    case UserResponse::kClickCancelButton:
+      confirm_dialog->CancelTabModalDialog();
+      break;
+    case UserResponse::kCloseDialog:
+      confirm_dialog->CloseDialog();
+      break;
+  }
+  return confirm_dialog;
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/test/fake_xr_session_request_consent_manager.h b/chrome/browser/vr/test/fake_xr_session_request_consent_manager.h
new file mode 100644
index 0000000..e86f235
--- /dev/null
+++ b/chrome/browser/vr/test/fake_xr_session_request_consent_manager.h
@@ -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.
+
+#ifndef CHROME_BROWSER_VR_TEST_FAKE_XR_SESSION_REQUEST_CONSENT_MANAGER_H_
+#define CHROME_BROWSER_VR_TEST_FAKE_XR_SESSION_REQUEST_CONSENT_MANAGER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/vr/service/xr_session_request_consent_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace vr {
+
+class FakeXRSessionRequestConsentManager
+    : public XRSessionRequestConsentManager {
+ public:
+  enum class UserResponse {
+    kClickAllowButton,
+    kClickCancelButton,
+    kCloseDialog,
+  };
+
+  FakeXRSessionRequestConsentManager(
+      XRSessionRequestConsentManager* consent_manager,
+      UserResponse user_response);
+  ~FakeXRSessionRequestConsentManager() override;
+
+  TabModalConfirmDialog* ShowDialogAndGetConsent(
+      content::WebContents* web_contents,
+      base::OnceCallback<void(bool)> response_callback) override;
+
+ private:
+  XRSessionRequestConsentManager* consent_manager_;
+  UserResponse user_response_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeXRSessionRequestConsentManager);
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_TEST_FAKE_XR_SESSION_REQUEST_CONSENT_MANAGER_H_
diff --git a/chrome/browser/vr/test/mock_xr_session_request_consent_manager.h b/chrome/browser/vr/test/mock_xr_session_request_consent_manager.h
index 5df1a301..7b766d8a 100644
--- a/chrome/browser/vr/test/mock_xr_session_request_consent_manager.h
+++ b/chrome/browser/vr/test/mock_xr_session_request_consent_manager.h
@@ -17,9 +17,10 @@
   MockXRSessionRequestConsentManager();
   ~MockXRSessionRequestConsentManager() override;
 
-  MOCK_METHOD2(ShowDialogAndGetConsent,
-               void(content::WebContents* web_contents,
-                    base::OnceCallback<void(bool)> response_callback));
+  MOCK_METHOD2(
+      ShowDialogAndGetConsent,
+      TabModalConfirmDialog*(content::WebContents* web_contents,
+                             base::OnceCallback<void(bool)> response_callback));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockXRSessionRequestConsentManager);
diff --git a/chrome/browser/vr/test/webvr_browser_test.cc b/chrome/browser/vr/test/webvr_browser_test.cc
index 2eb13f8..db445a9 100644
--- a/chrome/browser/vr/test/webvr_browser_test.cc
+++ b/chrome/browser/vr/test/webvr_browser_test.cc
@@ -26,6 +26,7 @@
       .WillByDefault(Invoke(
           [](content::WebContents*, base::OnceCallback<void(bool)> callback) {
             std::move(callback).Run(true);
+            return nullptr;
           }));
 #endif
   // ExecuteScript runs with a user gesture, so we can just directly call
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.cc b/chrome/browser/vr/test/webxr_vr_browser_test.cc
index d4a7278..59e4756 100644
--- a/chrome/browser/vr/test/webxr_vr_browser_test.cc
+++ b/chrome/browser/vr/test/webxr_vr_browser_test.cc
@@ -22,6 +22,7 @@
       .WillByDefault(Invoke(
           [](content::WebContents*, base::OnceCallback<void(bool)> callback) {
             std::move(callback).Run(true);
+            return nullptr;
           }));
 #endif
   // ExecuteScript runs with a user gesture, so we can just directly call
diff --git a/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc b/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc
new file mode 100644
index 0000000..91cf129
--- /dev/null
+++ b/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc
@@ -0,0 +1,93 @@
+// 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 "build/build_config.h"
+#include "chrome/browser/vr/test/fake_xr_session_request_consent_manager.h"
+#include "chrome/browser/vr/test/webxr_vr_browser_test.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+
+namespace vr {
+
+#if defined(OS_WIN)
+
+// Browser test class exclusively to test the consent dialog that's shown when
+// attempting to enter VR.
+class WebXrVrConsentDialogBrowserTest : public WebXrVrBrowserTestBase {
+ public:
+  WebXrVrConsentDialogBrowserTest();
+
+  // Must be called first thing in the test. This cannot be part of SetUp()
+  // because the XRSessionRequestConsentManager::SetInstance() is not called
+  // in ChromeBrowserMain code by that time.
+  void SetupFakeConsentManager(
+      FakeXRSessionRequestConsentManager::UserResponse user_response);
+
+ private:
+  std::unique_ptr<FakeXRSessionRequestConsentManager> fake_consent_manager_;
+};
+
+WebXrVrConsentDialogBrowserTest::WebXrVrConsentDialogBrowserTest() {
+  enable_features_.push_back(features::kOpenVR);
+  enable_features_.push_back(features::kWebXr);
+}
+
+void WebXrVrConsentDialogBrowserTest::SetupFakeConsentManager(
+    FakeXRSessionRequestConsentManager::UserResponse user_response) {
+  fake_consent_manager_.reset(new FakeXRSessionRequestConsentManager(
+      XRSessionRequestConsentManager::Instance(), user_response));
+  XRSessionRequestConsentManager::SetInstanceForTesting(
+      fake_consent_manager_.get());
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebXrVrConsentDialogBrowserTest,
+    TestWebXrVrSucceedsWhenUserClicksConsentDialogAllowButton) {
+  SetupFakeConsentManager(
+      FakeXRSessionRequestConsentManager::UserResponse::kClickAllowButton);
+
+  LoadUrlAndAwaitInitialization(
+      GetFileUrlForHtmlTestFile("generic_webxr_page"));
+
+  // These two functions below are exactly the same as
+  // WebXrVrBrowserTestBase::EnterSessionWithUserGesture, except that the base
+  // class' implementation replaces the FakeXRSessionRequestConsentManager
+  // set in the SetupFakeConsentManager call above, which should be avoided.
+  RunJavaScriptOrFail("onRequestSession()", GetCurrentWebContents());
+  PollJavaScriptBooleanOrFail(
+      "sessionInfos[sessionTypes.IMMERSIVE].currentSession != null",
+      kPollTimeoutLong, GetCurrentWebContents());
+
+  RunJavaScriptOrFail(
+      "sessionInfos[sessionTypes.IMMERSIVE].currentSession.end()",
+      GetCurrentWebContents());
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebXrVrConsentDialogBrowserTest,
+    TestWebXrVrFailsWhenUserClicksConsentDialogCancelButton) {
+  SetupFakeConsentManager(
+      FakeXRSessionRequestConsentManager::UserResponse::kClickCancelButton);
+
+  LoadUrlAndAwaitInitialization(GetFileUrlForHtmlTestFile(
+      "webxr_test_presentation_promise_rejected_if_don_canceled"));
+  ExecuteStepAndWait("onImmersiveRequestWithDon()");
+  EndTest();
+}
+
+IN_PROC_BROWSER_TEST_F(WebXrVrConsentDialogBrowserTest,
+                       TestWebXrVrFailsWhenUserClosesConsentDialog) {
+  SetupFakeConsentManager(
+      FakeXRSessionRequestConsentManager::UserResponse::kCloseDialog);
+
+  LoadUrlAndAwaitInitialization(GetFileUrlForHtmlTestFile(
+      "webxr_test_presentation_promise_rejected_if_don_canceled"));
+  ExecuteStepAndWait("onImmersiveRequestWithDon()");
+  EndTest();
+}
+
+#endif
+
+}  // namespace vr
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc
index 6b9e39e..b7767767 100644
--- a/chrome/browser/vr/webxr_vr_input_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -148,30 +148,7 @@
     return ConnectController(controller);
   }
 
-  void UpdateControllerSupport(
-      unsigned int controller_index,
-      const std::map<vr::EVRButtonId, unsigned int>& axis_types,
-      uint64_t supported_buttons) {
-    auto controller_data = GetCurrentControllerData(controller_index);
-
-    for (unsigned int i = 0; i < device::kMaxNumAxes; i++) {
-      auto button_id = GetAxisId(i);
-      auto it = axis_types.find(button_id);
-      unsigned int new_axis_type = k_eControllerAxis_None;
-      if (it != axis_types.end())
-        new_axis_type = it->second;
-      controller_data.axis_data[i].axis_type = new_axis_type;
-    }
-
-    controller_data.supported_buttons = supported_buttons;
-
-    UpdateControllerAndWait(controller_index, controller_data);
-  }
-
  private:
-  vr::EVRButtonId GetAxisId(unsigned int offset) {
-    return static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + offset);
-  }
   unsigned int GetAxisOffset(vr::EVRButtonId button_id) {
     DCHECK(vr::k_EButton_Axis0 <= button_id &&
            button_id < (vr::k_EButton_Axis0 + device::kMaxNumAxes));
@@ -200,78 +177,6 @@
   std::move(callback).Run();
 }
 
-// Ensure that changes to a gamepad object respect that it is the same object
-// and that if whether or not an input source has a gamepad changes that the
-// input source change event is fired and a new input source is created.
-IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestInputGamepadSameObject) {
-  WebXrControllerInputMock my_mock;
-
-  // Create a set of buttons and axes that don't have enough data to be made
-  // into an xr-standard gamepad (which we expect the runtimes to not report).
-  // Note that we need to set the trigger axis because of how OpenVR handles
-  // selects.
-  uint64_t insufficient_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger);
-  std::map<vr::EVRButtonId, unsigned int> insufficient_axis_types = {
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
-  };
-
-  // Create a set of buttons and axes that we expect to have enough data to be
-  // made into an xr-standard gamepad (which we expect the runtimes to report).
-  uint64_t sufficient_buttons =
-      vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger) |
-      vr::ButtonMaskFromId(vr::k_EButton_Axis0);
-  std::map<vr::EVRButtonId, unsigned int> sufficient_axis_types = {
-      {vr::k_EButton_Axis0, vr::k_eControllerAxis_TrackPad},
-      {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger},
-  };
-
-  // Start off without a gamepad.
-  unsigned int controller_index = my_mock.CreateAndConnectController(
-      device::ControllerRole::kControllerRoleRight, insufficient_axis_types,
-      insufficient_buttons);
-
-  LoadUrlAndAwaitInitialization(
-      GetFileUrlForHtmlTestFile("test_webxr_input_same_object"));
-  EnterSessionWithUserGestureOrFail();
-
-  // We should only have seen the first change indicating we have input sources.
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 1", kPollTimeoutShort);
-
-  // We only expect one input source, cache it.
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("updateCachedInputSource(0)");
-
-  // Toggle a button and confirm that the controller is still the same.
-  my_mock.PressReleasePrimaryTrigger(controller_index);
-  RunJavaScriptOrFail("validateCachedSourcePresence(true)");
-  RunJavaScriptOrFail("validateCurrentAndCachedGamepadMatch()");
-
-  // Update the controller to now support a gamepad and verify that we get a
-  // change event and that the old controller isn't present.  Then cache the new
-  // one.
-  my_mock.UpdateControllerSupport(controller_index, sufficient_axis_types,
-                                  sufficient_buttons);
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 2", kPollTimeoutShort);
-  RunJavaScriptOrFail("validateCachedSourcePresence(false)");
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("updateCachedInputSource(0)");
-
-  // Toggle a button and confirm that the controller is still the same.
-  my_mock.PressReleasePrimaryTrigger(controller_index);
-  RunJavaScriptOrFail("validateCachedSourcePresence(true)");
-  RunJavaScriptOrFail("validateCurrentAndCachedGamepadMatch()");
-
-  // Switch back to the insufficient gamepad and confirm that we get the change.
-  my_mock.UpdateControllerSupport(controller_index, insufficient_axis_types,
-                                  insufficient_buttons);
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 3", kPollTimeoutShort);
-  RunJavaScriptOrFail("validateCachedSourcePresence(false)");
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
 // Ensure that if the controller lacks enough data to be considered a Gamepad
 // that the input source that it is associated with does not have a Gamepad.
 IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestGamepadIncompleteData) {
@@ -284,12 +189,12 @@
   my_mock.CreateAndConnectController(
       device::ControllerRole::kControllerRoleRight, {}, supported_buttons);
 
-  LoadUrlAndAwaitInitialization(
-      GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
-  EnterSessionWithUserGestureOrFail();
-  ExecuteStepAndWait("validateInputSourceHasNoGamepad()");
-  RunJavaScriptOrFail("done()");
-  EndTest();
+  this->LoadUrlAndAwaitInitialization(
+      this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
+  this->EnterSessionWithUserGestureOrFail();
+  this->ExecuteStepAndWait("validateInputSourceHasNoGamepad()");
+  this->RunJavaScriptOrFail("done()");
+  this->EndTest();
 }
 
 // Ensure that if a Gamepad has the minimum required number of axes/buttons to
@@ -299,9 +204,9 @@
   WebXrControllerInputMock my_mock;
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
 
-  LoadUrlAndAwaitInitialization(
-      GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
-  EnterSessionWithUserGestureOrFail();
+  this->LoadUrlAndAwaitInitialization(
+      this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
+  this->EnterSessionWithUserGestureOrFail();
 
   // Press the trigger and set the axis to a non-zero amount, so we can ensure
   // we aren't getting just default gamepad data.
@@ -341,9 +246,9 @@
       device::ControllerRole::kControllerRoleRight, axis_types,
       supported_buttons);
 
-  LoadUrlAndAwaitInitialization(
-      GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
-  EnterSessionWithUserGestureOrFail();
+  this->LoadUrlAndAwaitInitialization(
+      this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
+  this->EnterSessionWithUserGestureOrFail();
 
   // Setup some state on the optional buttons (as TestGamepadMinimumData should
   // ensure proper state on the required buttons).
@@ -362,18 +267,18 @@
   ExecuteStepAndWait("validateMapping('xr-standard')");
 
   // The secondary set of axes should be set appropriately.
-  ExecuteStepAndWait("validateAxesValues(1, 0.25, -0.25)");
+  this->ExecuteStepAndWait("validateAxesValues(1, 0.25, -0.25)");
 
   // Button 2 is reserved for the Grip, and should be pressed.
-  ExecuteStepAndWait("validateButtonPressed(2)");
+  this->ExecuteStepAndWait("validateButtonPressed(2)");
 
   // Button 3 is reserved for the secondary trackpad/joystick and should be
   // touched but not pressed.
-  ExecuteStepAndWait("validateButtonNotPressed(3)");
-  ExecuteStepAndWait("validateButtonTouched(3)");
+  this->ExecuteStepAndWait("validateButtonNotPressed(3)");
+  this->ExecuteStepAndWait("validateButtonTouched(3)");
 
-  RunJavaScriptOrFail("done()");
-  EndTest();
+  this->RunJavaScriptOrFail("done()");
+  this->EndTest();
 }
 
 // Ensure that if a Gamepad has all required buttons, an extra button not
@@ -399,9 +304,9 @@
       device::ControllerRole::kControllerRoleRight, axis_types,
       supported_buttons);
 
-  LoadUrlAndAwaitInitialization(
-      GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
-  EnterSessionWithUserGestureOrFail();
+  this->LoadUrlAndAwaitInitialization(
+      this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support"));
+  this->EnterSessionWithUserGestureOrFail();
 
   // Claim that all buttons are pressed, note that any non-supported buttons
   // should be ignored.
@@ -431,12 +336,13 @@
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
 
   // Load the test page and enter presentation.
-  LoadUrlAndAwaitInitialization(GetFileUrlForHtmlTestFile("test_webxr_input"));
-  EnterSessionWithUserGestureOrFail();
+  this->LoadUrlAndAwaitInitialization(
+      this->GetFileUrlForHtmlTestFile("test_webxr_input"));
+  this->EnterSessionWithUserGestureOrFail();
 
   unsigned int num_iterations = 10;
-  RunJavaScriptOrFail("stepSetupListeners(" +
-                      base::NumberToString(num_iterations) + ")");
+  this->RunJavaScriptOrFail("stepSetupListeners(" +
+                            std::to_string(num_iterations) + ")");
 
   // Press and unpress the controller's trigger a bunch of times and make sure
   // they're all registered.
@@ -444,9 +350,9 @@
     my_mock.PressReleasePrimaryTrigger(controller_index);
     // After each trigger release, wait for the JavaScript to receive the
     // "select" event.
-    WaitOnJavaScriptStep();
+    this->WaitOnJavaScriptStep();
   }
-  EndTest();
+  this->EndTest();
 }
 
 // Test that OpenVR controller input is registered via the Gamepad API.
@@ -469,9 +375,9 @@
   unsigned int controller_index = my_mock.ConnectController(controller_data);
 
   // Load the test page and enter presentation.
-  LoadUrlAndAwaitInitialization(
-      GetFileUrlForHtmlTestFile("test_gamepad_button"));
-  EnterSessionWithUserGestureOrFail();
+  this->LoadUrlAndAwaitInitialization(
+      this->GetFileUrlForHtmlTestFile("test_gamepad_button"));
+  this->EnterSessionWithUserGestureOrFail();
 
   // We need to have this, otherwise the JavaScript side of the Gamepad API
   // doesn't seem to pick up the correct button state? I.e. if we don't have
@@ -484,13 +390,13 @@
   // flakiness workaround. Coincidentally, it's also helpful for the different
   // issue solved by the above PressReleasePrimaryTrigger, so make sure to set
   // it here so that the above press/release isn't caught by the test code.
-  RunJavaScriptOrFail("canStartTest = true");
+  this->RunJavaScriptOrFail("canStartTest = true");
   // Press and release the trigger, ensuring the Gamepad API detects both.
   my_mock.TogglePrimaryTrigger(controller_index);
-  WaitOnJavaScriptStep();
+  this->WaitOnJavaScriptStep();
   my_mock.TogglePrimaryTrigger(controller_index);
-  WaitOnJavaScriptStep();
-  EndTest();
+  this->WaitOnJavaScriptStep();
+  this->EndTest();
 }
 
 class WebXrHeadPoseMock : public MockXRDeviceHookBase {
diff --git a/chrome/common/safe_browsing/zip_analyzer.cc b/chrome/common/safe_browsing/zip_analyzer.cc
index b02218ed..9353cca 100644
--- a/chrome/common/safe_browsing/zip_analyzer.cc
+++ b/chrome/common/safe_browsing/zip_analyzer.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/ranges.h"
 #include "base/rand_util.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
@@ -25,9 +26,17 @@
 namespace safe_browsing {
 namespace zip_analyzer {
 
+namespace {
+
+// The maximum duration of ZIP analysis, in milliseconds.
+const int kZipAnalysisTimeoutMs = 10000;
+
+}  // namespace
+
 void AnalyzeZipFile(base::File zip_file,
                     base::File temp_file,
                     ArchiveAnalyzerResults* results) {
+  base::Time start_time = base::Time::Now();
   zip::ZipReader reader;
   if (!reader.OpenFromPlatformFile(zip_file.GetPlatformFile())) {
     DVLOG(1) << "Failed to open zip file";
@@ -44,9 +53,8 @@
     return;
   }
 
-  bool contains_zip = false;
+  bool timeout = false;
   bool advanced = true;
-  int zip_entry_count = 0;
   results->file_count = 0;
   results->directory_count = 0;
   for (; reader.HasMore(); advanced = reader.AdvanceToNextEntry()) {
@@ -58,6 +66,11 @@
       DVLOG(1) << "Failed to open current entry in zip file";
       continue;
     }
+    if (base::Time::Now() - start_time >
+        base::TimeDelta::FromMilliseconds(kZipAnalysisTimeoutMs)) {
+      timeout = true;
+      break;
+    }
 
     // Clear the |temp_file| between extractions.
     temp_file.Seek(base::File::Whence::FROM_BEGIN, 0);
@@ -69,19 +82,13 @@
         writer.file_length(), reader.current_entry_info()->is_encrypted(),
         results);
 
-    if (FileTypePolicies::GetFileExtension(
-            reader.current_entry_info()->file_path()) ==
-        FILE_PATH_LITERAL(".zip"))
-      contains_zip = true;
-    zip_entry_count++;
-
     if (reader.current_entry_info()->is_directory())
       results->directory_count++;
     else
       results->file_count++;
   }
 
-  results->success = true;
+  results->success = !timeout;
 }
 
 }  // namespace zip_analyzer
diff --git a/chrome/common/secure_origin_whitelist.cc b/chrome/common/secure_origin_whitelist.cc
index 9f0054d4..e6a2a3ba 100644
--- a/chrome/common/secure_origin_whitelist.cc
+++ b/chrome/common/secure_origin_whitelist.cc
@@ -19,9 +19,9 @@
   return schemes;
 }
 
-void RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(prefs::kUnsafelyTreatInsecureOriginAsSecure,
-                               /* default_value */ "");
+void RegisterPrefs(PrefRegistrySimple* local_state) {
+  local_state->RegisterStringPref(prefs::kUnsafelyTreatInsecureOriginAsSecure,
+                                  /* default_value */ "");
 }
 
 }  // namespace secure_origin_whitelist
diff --git a/chrome/common/secure_origin_whitelist.h b/chrome/common/secure_origin_whitelist.h
index e0af2ce..e55ca47 100644
--- a/chrome/common/secure_origin_whitelist.h
+++ b/chrome/common/secure_origin_whitelist.h
@@ -17,11 +17,7 @@
 std::set<std::string> GetSchemesBypassingSecureContextCheck();
 
 // Register preferences for Secure Origin Whitelists.
-//
-// Note: the preferences need to be registered both for LocalState and for
-// ProfilePrefs - this way LocalState will reflect the correct value (from the
-// primary profile) that can be picked up by SecureOriginPrefsObserver.
-void RegisterPrefs(PrefRegistrySimple*);
+void RegisterPrefs(PrefRegistrySimple* local_state);
 
 }  // namespace secure_origin_whitelist
 
diff --git a/chrome/credential_provider/test/BUILD.gn b/chrome/credential_provider/test/BUILD.gn
index 7aae9892..5455dccc 100644
--- a/chrome/credential_provider/test/BUILD.gn
+++ b/chrome/credential_provider/test/BUILD.gn
@@ -47,7 +47,6 @@
 
   data = [
     "//net/tools/testserver/",
-    "//third_party/pyftpdlib/",
     "//third_party/pywebsocket/src/mod_pywebsocket/",
     "//third_party/tlslite/",
   ]
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b483fe4e..bcd6462 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1240,7 +1240,6 @@
       "//third_party/chaijs/chai.js",
       "//third_party/mocha/mocha.js",
       "//third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js",
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/simplejson/",
       "//third_party/tlslite/",
@@ -2888,7 +2887,6 @@
     "../browser/prerender/prerender_unittest.cc",
     "../browser/prerender/prerender_util_unittest.cc",
     "../browser/previews/previews_content_util_unittest.cc",
-    "../browser/previews/previews_infobar_delegate_unittest.cc",
     "../browser/previews/previews_lite_page_decider_unittest.cc",
     "../browser/previews/previews_lite_page_infobar_delegate_unittest.cc",
     "../browser/previews/previews_lite_page_navigation_throttle_unittest.cc",
@@ -3120,7 +3118,6 @@
     "//net/tools/testserver/",
     "//third_party/accessibility-audit/axs_testing.js",
     "//third_party/chaijs/chai.js",
-    "//third_party/pyftpdlib/",
     "//third_party/pywebsocket/src/mod_pywebsocket/",
     "//third_party/tlslite/",
     "//third_party/zlib/google/test/data/",
@@ -5097,7 +5094,6 @@
       "//third_party/chaijs/chai.js",
       "//third_party/mocha/mocha.js",
       "//third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js",
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
       "//third_party/zlib/google/test/data/",
@@ -5650,7 +5646,6 @@
     data = [
       "//chrome/test/data/sync/",
       "//net/tools/testserver/",
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
       "//testing/xvfb.py",
diff --git a/chrome/test/base/default_ash_event_generator_delegate.cc b/chrome/test/base/default_ash_event_generator_delegate.cc
index 94c924ff..646300f8 100644
--- a/chrome/test/base/default_ash_event_generator_delegate.cc
+++ b/chrome/test/base/default_ash_event_generator_delegate.cc
@@ -6,7 +6,6 @@
 
 #include "ash/shell.h"
 #include "base/macros.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/test/default_event_generator_delegate.h"
 #include "ui/base/ui_base_features.h"
 
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 8dee445..310caf49 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -45,14 +45,16 @@
   "OverrideSecurityRestrictionsOnInsecureOrigin": {
     "os": ["win", "linux", "mac", "android", "chromeos"],
     "test_policy": { "OverrideSecurityRestrictionsOnInsecureOrigin": ["http://example.com/","*.example.com"] },
-    "pref_mappings": [ { "pref": "unsafely_treat_insecure_origin_as_secure" } ]
+    "pref_mappings": [ { "pref": "unsafely_treat_insecure_origin_as_secure",
+                         "local_state": true } ]
   },
 
   "UnsafelyTreatInsecureOriginAsSecure": {
     "note": "This policy is deprecated.",
     "os": ["win", "linux", "mac"],
     "test_policy": { "UnsafelyTreatInsecureOriginAsSecure": ["http://example.com/","*.example.com"] },
-    "pref_mappings": [ { "pref": "unsafely_treat_insecure_origin_as_secure" } ]
+    "pref_mappings": [ { "pref": "unsafely_treat_insecure_origin_as_secure",
+                         "local_state": true } ]
   },
 
   "HomepageLocation": {
diff --git a/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js b/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js
index c5acc58..1aa4eb1 100644
--- a/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js
+++ b/chrome/test/data/webui/bookmarks/bookmarks_focus_test.js
@@ -27,13 +27,7 @@
   ],
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('BookmarksFocusTest', 'MAYBE_All', function() {
+TEST_F('BookmarksFocusTest', 'All', function() {
   suite('<bookmarks-folder-node>', function() {
     let rootNode;
     let store;
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
index 7e87149..770765f 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -28,13 +28,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsActionMenuTest', 'MAYBE_All', function() {
+TEST_F('CrElementsActionMenuTest', 'All', function() {
   mocha.run();
 });
 
@@ -52,13 +46,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsProfileAvatarSelectorFocusTest', 'MAYBE_All', function() {
+TEST_F('CrElementsProfileAvatarSelectorFocusTest', 'All', function() {
   cr_profile_avatar_selector.registerTests();
   mocha.grep(cr_profile_avatar_selector.TestNames.Focus).run();
 });
@@ -82,13 +70,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsToggleTest', 'MAYBE_All', function() {
+TEST_F('CrElementsToggleTest', 'All', function() {
   mocha.run();
 });
 
@@ -112,13 +94,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsCheckboxTest', 'MAYBE_All', function() {
+TEST_F('CrElementsCheckboxTest', 'All', function() {
   mocha.run();
 });
 
@@ -141,13 +117,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsInputTest', 'MAYBE_All', function() {
+TEST_F('CrElementsInputTest', 'All', function() {
   mocha.run();
 });
 
@@ -170,13 +140,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsIconButtonFocusTest', 'MAYBE_All', function() {
+TEST_F('CrElementsIconButtonFocusTest', 'All', function() {
   mocha.run();
 });
 
@@ -202,12 +166,6 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsExpandButtonTest', 'MAYBE_All', function() {
+TEST_F('CrElementsExpandButtonTest', 'All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js b/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js
index 1c2e9c3..a31e1980 100644
--- a/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js
+++ b/chrome/test/data/webui/cr_focus_row_behavior_interactive_test.js
@@ -34,12 +34,6 @@
   },
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_FocusTest DISABLED_FocusTest');
-GEN('#else');
-GEN('#define MAYBE_FocusTest FocusTest');
-GEN('#endif');
-TEST_F('CrFocusRowBehaviorTest', 'MAYBE_FocusTest', function() {
+TEST_F('CrFocusRowBehaviorTest', 'FocusTest', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/downloads/downloads_browsertest.js b/chrome/test/data/webui/downloads/downloads_browsertest.js
index 5c082e7..74ce4547 100644
--- a/chrome/test/data/webui/downloads/downloads_browsertest.js
+++ b/chrome/test/data/webui/downloads/downloads_browsertest.js
@@ -137,8 +137,10 @@
 
 TEST_F('DownloadsUrlTest', 'All', function() {
   suite('loading a nonexistent URL of /a/b/', function() {
-    test('should yield no console errors', function() {
-      assertEquals(location.href, DownloadsUrlTest.prototype.browsePreload);
+    test('should load main page with no console errors', function() {
+      return customElements.whenDefined('downloads-manager').then(() => {
+        assertEquals('chrome://downloads/', location.href);
+      });
     });
   });
   mocha.run();
diff --git a/chrome/test/data/webui/history/history_focus_test.js b/chrome/test/data/webui/history/history_focus_test.js
index 2e7dc2d..8b23dd1a 100644
--- a/chrome/test/data/webui/history/history_focus_test.js
+++ b/chrome/test/data/webui/history/history_focus_test.js
@@ -35,13 +35,7 @@
   },
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('HistoryFocusTest', 'MAYBE_All', function() {
+TEST_F('HistoryFocusTest', 'All', function() {
   suite('<history-toolbar>', function() {
     let app;
     let toolbar;
diff --git a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
index 01251b9..bacc14745 100644
--- a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
@@ -66,15 +66,8 @@
   }
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_FocusPrintOnReady DISABLED_FocusPrintOnReady');
-GEN('#else');
-GEN('#define MAYBE_FocusPrintOnReady FocusPrintOnReady');
-GEN('#endif');
 TEST_F(
-    'PrintPreviewPrintHeaderInteractiveTest', 'MAYBE_FocusPrintOnReady',
-    function() {
+    'PrintPreviewPrintHeaderInteractiveTest', 'FocusPrintOnReady', function() {
       this.runMochaTest(
           print_header_interactive_test.TestNames.FocusPrintOnReady);
     });
@@ -138,27 +131,15 @@
   }
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_FocusSearchBox DISABLED_FocusSearchBox');
-GEN('#else');
-GEN('#define MAYBE_FocusSearchBox FocusSearchBox');
-GEN('#endif');
 TEST_F(
-    'PrintPreviewDestinationDialogInteractiveTest', 'MAYBE_FocusSearchBox',
+    'PrintPreviewDestinationDialogInteractiveTest', 'FocusSearchBox',
     function() {
       this.runMochaTest(
           destination_dialog_interactive_test.TestNames.FocusSearchBox);
     });
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_EscapeSearchBox DISABLED_EscapeSearchBox');
-GEN('#else');
-GEN('#define MAYBE_EscapeSearchBox EscapeSearchBox');
-GEN('#endif');
 TEST_F(
-    'PrintPreviewDestinationDialogInteractiveTest', 'MAYBE_EscapeSearchBox',
+    'PrintPreviewDestinationDialogInteractiveTest', 'EscapeSearchBox',
     function() {
       this.runMochaTest(
           destination_dialog_interactive_test.TestNames.EscapeSearchBox);
@@ -185,38 +166,19 @@
   }
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_ClearInput DISABLED_ClearInput');
-GEN('#else');
-GEN('#define MAYBE_ClearInput ClearInput');
-GEN('#endif');
-TEST_F('PrintPreviewPagesSettingsTest', 'MAYBE_ClearInput', function() {
+TEST_F('PrintPreviewPagesSettingsTest', 'ClearInput', function() {
   this.runMochaTest(pages_settings_test.TestNames.ClearInput);
 });
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_InputNotDisabledOnValidityChange DISABLED_InputNotDisabledOnValidityChange');
-GEN('#else');
-GEN('#define MAYBE_InputNotDisabledOnValidityChange InputNotDisabledOnValidityChange');
-GEN('#endif');
 TEST_F(
-    'PrintPreviewPagesSettingsTest', 'MAYBE_InputNotDisabledOnValidityChange',
+    'PrintPreviewPagesSettingsTest', 'InputNotDisabledOnValidityChange',
     function() {
       this.runMochaTest(
           pages_settings_test.TestNames.InputNotDisabledOnValidityChange);
     });
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_EnterOnInputTriggersPrint DISABLED_EnterOnInputTriggersPrint');
-GEN('#else');
-GEN('#define MAYBE_EnterOnInputTriggersPrint EnterOnInputTriggersPrint');
-GEN('#endif');
 TEST_F(
-    'PrintPreviewPagesSettingsTest', 'MAYBE_EnterOnInputTriggersPrint',
-    function() {
+    'PrintPreviewPagesSettingsTest', 'EnterOnInputTriggersPrint', function() {
       this.runMochaTest(
           pages_settings_test.TestNames.EnterOnInputTriggersPrint);
     });
@@ -243,15 +205,9 @@
   }
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_BlurResetsEmptyInput DISABLED_BlurResetsEmptyInput');
-GEN('#else');
-GEN('#define MAYBE_BlurResetsEmptyInput BlurResetsEmptyInput');
-GEN('#endif');
 TEST_F(
-    'PrintPreviewNumberSettingsSectionInteractiveTest',
-    'MAYBE_BlurResetsEmptyInput', function() {
+    'PrintPreviewNumberSettingsSectionInteractiveTest', 'BlurResetsEmptyInput',
+    function() {
       this.runMochaTest(number_settings_section_interactive_test.TestNames
                             .BlurResetsEmptyInput);
     });
diff --git a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
index 36a5fde7..e345ee4 100644
--- a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
+++ b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
@@ -50,13 +50,7 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrSettingsSyncPageTest', 'MAYBE_All', function() {
+TEST_F('CrSettingsSyncPageTest', 'All', function() {
   mocha.run();
 });
 
@@ -78,12 +72,6 @@
   ]),
 };
 
-// Web UI interactive tests are flaky on Win10, see https://crbug.com/711256
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrSettingsAnimatedPagesTest', 'MAYBE_All', function() {
+TEST_F('CrSettingsAnimatedPagesTest', 'All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_input_same_object.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_input_same_object.html
deleted file mode 100644
index 218d149..0000000
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_input_same_object.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!doctype html>
-<!--
-A collection of helper functions and listeners to confirm the state of input
-sources for the same object tests.
--->
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
-  </head>
-  <body>
-    <canvas id="webgl-canvas"></canvas>
-    <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
-    <script src="../resources/webxr_e2e.js"></script>
-    <script src="../resources/webxr_boilerplate.js"></script>
-    <script>
-      let inputChangeEvents = 0;
-      function onInputSourcesChange() {
-        inputChangeEvents++;
-      }
-
-      onSessionStartedCallback = function(session) {
-        if (session.mode === "immersive-vr") {
-          session.addEventListener('inputsourceschange', onInputSourcesChange, false);
-        }
-      }
-
-      function getCurrentInputSources() {
-        let currentSession = sessionInfos[sessionTypes.IMMERSIVE].currentSession;
-        return currentSession.getInputSources();
-      }
-
-      let cached_input_source = null;
-      function updateCachedInputSource(id) {
-        let input_sources = getCurrentInputSources();
-        assert_less_than(id, input_sources.length);
-        cached_input_source = input_sources[id];
-      }
-
-      function validateCachedSourcePresence(present) {
-        assert_not_equals(cached_input_source, null);
-        assert_not_equals(present, undefined);
-        let current_sources = getCurrentInputSources();
-        assert_equals(current_sources.includes(cached_input_source), present);
-      }
-
-      function validateInputSourceLength(length) {
-        assert_equals(getCurrentInputSources().length, length);
-      }
-
-      function validateCurrentAndCachedGamepadMatch() {
-        assert_not_equals(cached_input_source, null);
-        let current_sources = getCurrentInputSources();
-        let index = current_sources.indexOf(cached_input_source);
-        assert_not_equals(index, -1);
-        assert_equals(cached_input_source.gamepad, current_sources[index].gamepad);
-      }
-    </script>
-  </body>
-</html>
diff --git a/chromecast/graphics/cast_views_test.cc b/chromecast/graphics/cast_views_test.cc
index 794ac03..b9f785d 100644
--- a/chromecast/graphics/cast_views_test.cc
+++ b/chromecast/graphics/cast_views_test.cc
@@ -40,8 +40,8 @@
 
   EXPECT_TRUE(progress_bar->GetWidget());
   EXPECT_TRUE(progress_bar->GetWidget()->IsVisible());
-  EXPECT_TRUE(progress_bar->visible());
-  EXPECT_TRUE(progress_bar->enabled());
+  EXPECT_TRUE(progress_bar->GetVisible());
+  EXPECT_TRUE(progress_bar->GetEnabled());
 
   widget.reset();
   window_manager.reset();
diff --git a/components/autofill/core/browser/form_parsing/address_field.cc b/components/autofill/core/browser/form_parsing/address_field.cc
index 1bb9b23..cc0a747 100644
--- a/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/components/autofill/core/browser/form_parsing/address_field.cc
@@ -38,9 +38,11 @@
     MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER;
 
 // Select fields are allowed here.  This occurs on top-100 site rediff.com.
-const int AddressField::kCityMatchType = MATCH_DEFAULT | MATCH_SELECT;
+const int AddressField::kCityMatchType =
+    MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
 
-const int AddressField::kStateMatchType = MATCH_DEFAULT | MATCH_SELECT;
+const int AddressField::kStateMatchType =
+    MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
 
 std::unique_ptr<FormField> AddressField::Parse(AutofillScanner* scanner) {
   if (scanner->IsEnd())
@@ -227,16 +229,17 @@
 
   scanner->SaveCursor();
   if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kCountryRe),
-                          MATCH_DEFAULT | MATCH_SELECT, &country_)) {
+                          MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
+                          &country_)) {
     return true;
   }
 
   // The occasional page (e.g. google account registration page) calls this a
   // "location". However, this only makes sense for select tags.
   scanner->Rewind();
-  return ParseFieldSpecifics(scanner, UTF8ToUTF16(kCountryLocationRe),
-                             MATCH_LABEL | MATCH_NAME | MATCH_SELECT,
-                             &country_);
+  return ParseFieldSpecifics(
+      scanner, UTF8ToUTF16(kCountryLocationRe),
+      MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, &country_);
 }
 
 bool AddressField::ParseZipCode(AutofillScanner* scanner) {
diff --git a/components/autofill/core/browser/form_parsing/credit_card_field.cc b/components/autofill/core/browser/form_parsing/credit_card_field.cc
index 00399ed..a022adb 100644
--- a/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -269,7 +269,8 @@
     return false;
 
   AutofillField* field = scanner->Cursor();
-  if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
+  if (!MatchesFormControlType(field->form_control_type,
+                              MATCH_SELECT | MATCH_SEARCH))
     return false;
 
   if (field->option_values.size() < 12 || field->option_values.size() > 13)
@@ -306,7 +307,8 @@
     return false;
 
   AutofillField* field = scanner->Cursor();
-  if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
+  if (!MatchesFormControlType(field->form_control_type,
+                              MATCH_SELECT | MATCH_SEARCH))
     return false;
 
   const base::Time time_now = AutofillClock::Now();
@@ -330,7 +332,8 @@
 
   AutofillField* field = scanner->Cursor();
 
-  if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
+  if (!MatchesFormControlType(field->form_control_type,
+                              MATCH_SELECT | MATCH_SEARCH))
     return false;
 
   // We set |ignore_whitespace| to true on these calls because this is actually
@@ -444,21 +447,21 @@
 
   // If that fails, do a general regex search.
   scanner->RewindTo(month_year_saved_cursor);
-  const int kMatchNumAndTelAndSelect =
-      MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_SELECT;
+  const int kMatchCCType = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE |
+                           MATCH_SELECT | MATCH_SEARCH;
   if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationMonthRe),
-                          kMatchNumAndTelAndSelect, &expiration_month_) &&
+                          kMatchCCType, &expiration_month_) &&
       ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationYearRe),
-                          kMatchNumAndTelAndSelect, &expiration_year_)) {
+                          kMatchCCType, &expiration_year_)) {
     return true;
   }
 
   // If that fails, look for just MM and/or YY(YY).
   scanner->RewindTo(month_year_saved_cursor);
-  if (ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^mm$"),
-                          kMatchNumAndTelAndSelect, &expiration_month_) &&
+  if (ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^mm$"), kMatchCCType,
+                          &expiration_month_) &&
       ParseFieldSpecifics(scanner, base::ASCIIToUTF16("^(yy|yyyy)$"),
-                          kMatchNumAndTelAndSelect, &expiration_year_)) {
+                          kMatchCCType, &expiration_year_)) {
     return true;
   }
 
@@ -475,7 +478,7 @@
   // Try to look for a 2-digit year expiration date.
   if (ParseFieldSpecifics(scanner,
                           base::UTF8ToUTF16(kExpirationDate2DigitYearRe),
-                          kMatchNumAndTelAndSelect, &expiration_date_)) {
+                          kMatchCCType, &expiration_date_)) {
     exp_year_type_ = CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
     expiration_month_ = nullptr;
     return true;
@@ -483,7 +486,7 @@
 
   // Try to look for a generic expiration date field. (2 or 4 digit year)
   if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kExpirationDateRe),
-                          kMatchNumAndTelAndSelect, &expiration_date_)) {
+                          kMatchCCType, &expiration_date_)) {
     // If such a field exists, but it cannot fit a 4-digit year expiration
     // date, then the likely possibility is that it is a 2-digit year expiration
     // date.
@@ -500,7 +503,7 @@
                                   CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR) &&
       ParseFieldSpecifics(scanner,
                           base::UTF8ToUTF16(kExpirationDate4DigitYearRe),
-                          kMatchNumAndTelAndSelect, &expiration_date_)) {
+                          kMatchCCType, &expiration_date_)) {
     expiration_month_ = nullptr;
     return true;
   }
diff --git a/components/autofill/core/browser/form_parsing/form_field.cc b/components/autofill/core/browser/form_parsing/form_field.cc
index 9229b1ed..b83384e1 100644
--- a/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/components/autofill/core/browser/form_parsing/form_field.cc
@@ -223,6 +223,9 @@
   if ((match_type & MATCH_NUMBER) && type == "number")
     return true;
 
+  if ((match_type & MATCH_SEARCH) && type == "search")
+    return true;
+
   return false;
 }
 
diff --git a/components/autofill/core/browser/form_parsing/form_field.h b/components/autofill/core/browser/form_parsing/form_field.h
index 2579d98e..9ea02ccd 100644
--- a/components/autofill/core/browser/form_parsing/form_field.h
+++ b/components/autofill/core/browser/form_parsing/form_field.h
@@ -51,7 +51,7 @@
     MATCH_SEARCH = 1 << 9,
     MATCH_ALL_INPUTS = MATCH_TEXT | MATCH_EMAIL | MATCH_TELEPHONE |
                        MATCH_SELECT | MATCH_TEXT_AREA | MATCH_PASSWORD |
-                       MATCH_NUMBER,
+                       MATCH_NUMBER | MATCH_SEARCH,
 
     // By default match label and name for input/text types.
     MATCH_DEFAULT = MATCH_LABEL | MATCH_NAME | MATCH_TEXT,
diff --git a/components/autofill/core/browser/form_parsing/name_field.cc b/components/autofill/core/browser/form_parsing/name_field.cc
index d35f73c..d542d9b 100644
--- a/components/autofill/core/browser/form_parsing/name_field.cc
+++ b/components/autofill/core/browser/form_parsing/name_field.cc
@@ -147,7 +147,8 @@
   while (!scanner->IsEnd()) {
     // Skip over any unrelated fields, e.g. "username" or "nickname".
     if (ParseFieldSpecifics(scanner, UTF8ToUTF16(kNameIgnoredRe),
-                            MATCH_DEFAULT | MATCH_SELECT, nullptr)) {
+                            MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
+                            nullptr)) {
       continue;
     }
 
diff --git a/components/autofill/core/browser/form_parsing/price_field.cc b/components/autofill/core/browser/form_parsing/price_field.cc
index 63e81ab..51de7a2 100644
--- a/components/autofill/core/browser/form_parsing/price_field.cc
+++ b/components/autofill/core/browser/form_parsing/price_field.cc
@@ -14,10 +14,10 @@
 // static
 std::unique_ptr<FormField> PriceField::Parse(AutofillScanner* scanner) {
   AutofillField* field;
-  if (ParseFieldSpecifics(
-          scanner, base::UTF8ToUTF16(kPriceRe),
-          MATCH_DEFAULT | MATCH_NUMBER | MATCH_SELECT | MATCH_TEXT_AREA,
-          &field)) {
+  if (ParseFieldSpecifics(scanner, base::UTF8ToUTF16(kPriceRe),
+                          MATCH_DEFAULT | MATCH_NUMBER | MATCH_SELECT |
+                              MATCH_TEXT_AREA | MATCH_SEARCH,
+                          &field)) {
     return std::make_unique<PriceField>(field);
   }
 
diff --git a/components/component_updater/component_installer.h b/components/component_updater/component_installer.h
index 3404ec7d..1588693 100644
--- a/components/component_updater/component_installer.h
+++ b/components/component_updater/component_installer.h
@@ -65,6 +65,7 @@
   // OnCustomUninstall is called during the unregister (uninstall) process.
   // Components that require custom uninstallation operations should implement
   // them here.
+  // Called only from a thread belonging to a blocking thread pool.
   virtual void OnCustomUninstall() = 0;
 
   // ComponentReady is called in two cases:
diff --git a/components/data_reduction_proxy/content/browser/BUILD.gn b/components/data_reduction_proxy/content/browser/BUILD.gn
index 8984e3d..30adbd5 100644
--- a/components/data_reduction_proxy/content/browser/BUILD.gn
+++ b/components/data_reduction_proxy/content/browser/BUILD.gn
@@ -6,8 +6,6 @@
   sources = [
     "content_lofi_decider.cc",
     "content_lofi_decider.h",
-    "content_lofi_ui_service.cc",
-    "content_lofi_ui_service.h",
     "content_resource_type_provider.cc",
     "content_resource_type_provider.h",
     "data_reduction_proxy_page_load_timing.cc",
@@ -36,7 +34,6 @@
   testonly = true
   sources = [
     "content_lofi_decider_unittest.cc",
-    "content_lofi_ui_service_unittest.cc",
     "content_resource_type_provider_unittest.cc",
     "data_reduction_proxy_pingback_client_impl_unittest.cc",
   ]
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc b/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc
deleted file mode 100644
index b19ac89..0000000
--- a/components/data_reduction_proxy/content/browser/content_lofi_ui_service.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/data_reduction_proxy/content/browser/content_lofi_ui_service.h"
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "build/build_config.h"
-#include "components/previews/core/previews_experiments.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/web_contents.h"
-#include "net/url_request/url_request.h"
-
-namespace data_reduction_proxy {
-
-ContentLoFiUIService::ContentLoFiUIService(
-    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
-    const OnLoFiResponseReceivedCallback&
-        notify_lofi_response_received_callback)
-    : ui_task_runner_(ui_task_runner),
-      on_lofi_response_received_callback_(
-          notify_lofi_response_received_callback) {
-  DCHECK(!on_lofi_response_received_callback_.is_null());
-}
-
-ContentLoFiUIService::~ContentLoFiUIService() {}
-
-void ContentLoFiUIService::OnLoFiReponseReceived(
-    const net::URLRequest& request) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  // If the UI is in the Android Omnibox, it has already been shown at commit
-  // time.
-#if defined(OS_ANDROID)
-  if (previews::params::IsPreviewsOmniboxUiEnabled())
-    return;
-#endif
-
-  int render_process_id = -1;
-  int render_frame_id = -1;
-  if (content::ResourceRequestInfo::GetRenderFrameForRequest(
-          &request, &render_process_id, &render_frame_id)) {
-    ui_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&ContentLoFiUIService::OnLoFiResponseReceivedOnUIThread,
-                       base::Unretained(this), render_process_id,
-                       render_frame_id));
-  }
-}
-
-void ContentLoFiUIService::OnLoFiResponseReceivedOnUIThread(
-    int render_process_id,
-    int render_frame_id) {
-  DCHECK(ui_task_runner_->BelongsToCurrentThread());
-#if defined(OS_ANDROID)
-  // If the UI is in the Android Omnibox, it has already been shown at commit
-  // time.
-  DCHECK(!previews::params::IsPreviewsOmniboxUiEnabled());
-#endif
-
-  content::RenderFrameHost* frame =
-      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
-  if (frame) {
-    DCHECK(!on_lofi_response_received_callback_.is_null());
-    content::WebContents* web_contents =
-        content::WebContents::FromRenderFrameHost(frame);
-    on_lofi_response_received_callback_.Run(web_contents);
-  }
-}
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h b/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h
deleted file mode 100644
index 9c0c3f1..0000000
--- a/components/data_reduction_proxy/content/browser/content_lofi_ui_service.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_CONTENT_LOFI_UI_SERVICE_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_CONTENT_LOFI_UI_SERVICE_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "components/data_reduction_proxy/core/common/lofi_ui_service.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace content {
-class WebContents;
-}
-
-namespace net {
-class URLRequest;
-}
-
-namespace data_reduction_proxy {
-
-using OnLoFiResponseReceivedCallback =
-    base::Callback<void(content::WebContents* web_contents)>;
-
-// Passes notifications to the UI thread that a Lo-Fi response has been
-// received. These notifications may be used to show Lo-Fi UI. This object lives
-// on the IO thread and OnLoFiReponseReceived should be called from there.
-class ContentLoFiUIService : public LoFiUIService {
- public:
-  ContentLoFiUIService(
-      const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
-      const OnLoFiResponseReceivedCallback& on_lofi_response_received_callback);
-  ~ContentLoFiUIService() override;
-
-  // LoFiUIService implementation:
-  void OnLoFiReponseReceived(const net::URLRequest& request) override;
-
- private:
-  // Using the |render_process_id| and |render_frame_id|, gets the associated
-  // WebContents if it exists and runs the
-  // |notify_lofi_response_received_callback_|.
-  void OnLoFiResponseReceivedOnUIThread(int render_process_id,
-                                        int render_frame_id);
-
-  // A task runner to post calls to OnLoFiReponseReceivedOnUI on the UI
-  // thread.
-  const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
-  const OnLoFiResponseReceivedCallback on_lofi_response_received_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContentLoFiUIService);
-};
-
-}  // namespace data_reduction_proxy
-
-#endif  // COMPONENTS_DATA_REDUCTION_PROXY_CONTENT_BROWSER_CONTENT_LOFI_UI_SERVICE_H_
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc b/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
deleted file mode 100644
index 7854b9c..0000000
--- a/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/data_reduction_proxy/content/browser/content_lofi_ui_service.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/task/post_task.h"
-#include "build/build_config.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/previews_state.h"
-#include "content/public/test/test_renderer_host.h"
-#include "net/socket/socket_test_util.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-
-class ContentLoFiUIServiceTest : public content::RenderViewHostTestHarness {
- public:
-  ContentLoFiUIServiceTest() : callback_called_(false) {}
-
-  void RunTestOnIOThread(base::RunLoop* ui_run_loop) {
-    ASSERT_TRUE(ui_run_loop);
-    EXPECT_TRUE(
-        content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
-    net::TestURLRequestContext context(true);
-    net::MockClientSocketFactory mock_socket_factory;
-    net::TestDelegate delegate;
-    context.set_client_socket_factory(&mock_socket_factory);
-    context.Init();
-
-    content_lofi_ui_service_.reset(new ContentLoFiUIService(
-        base::CreateSingleThreadTaskRunnerWithTraits(
-            {content::BrowserThread::UI}),
-        base::Bind(&ContentLoFiUIServiceTest::OnLoFiResponseReceivedCallback,
-                   base::Unretained(this))));
-
-    std::unique_ptr<net::URLRequest> request =
-        CreateRequest(context, &delegate);
-
-    content_lofi_ui_service_->OnLoFiReponseReceived(*request);
-
-    base::PostTaskWithTraits(
-        FROM_HERE, {content::BrowserThread::UI},
-        base::BindOnce(&base::RunLoop::Quit, base::Unretained(ui_run_loop)));
-  }
-
-  std::unique_ptr<net::URLRequest> CreateRequest(
-      const net::TestURLRequestContext& context,
-      net::TestDelegate* delegate) {
-    EXPECT_TRUE(
-        content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
-    std::unique_ptr<net::URLRequest> request =
-        context.CreateRequest(GURL("http://www.google.com/"), net::IDLE,
-                              delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
-
-    content::ResourceRequestInfo::AllocateForTesting(
-        request.get(), content::ResourceType::kSubFrame, nullptr,
-        web_contents()->GetMainFrame()->GetProcess()->GetID(), -1,
-        web_contents()->GetMainFrame()->GetRoutingID(),
-        /*is_main_frame=*/false, content::ResourceInterceptPolicy::kAllowNone,
-        /*is_async=*/false, content::SERVER_LOFI_ON,
-        /*navigation_ui_data*/ nullptr);
-
-    return request;
-  }
-
-  void OnLoFiResponseReceivedCallback(content::WebContents* web_contents) {
-    EXPECT_TRUE(
-        content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-    callback_called_ = true;
-  }
-
-  void VerifyOnLoFiResponseReceivedCallback() {
-    EXPECT_TRUE(
-        content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-    EXPECT_TRUE(callback_called_);
-  }
-
- private:
-  std::unique_ptr<ContentLoFiUIService> content_lofi_ui_service_;
-  bool callback_called_;
-};
-
-#if !defined(OS_ANDROID)
-TEST_F(ContentLoFiUIServiceTest, OnLoFiResponseReceived) {
-  base::RunLoop ui_run_loop;
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&ContentLoFiUIServiceTest::RunTestOnIOThread,
-                     base::Unretained(this), &ui_run_loop));
-  ui_run_loop.Run();
-  base::RunLoop().RunUntilIdle();
-  VerifyOnLoFiResponseReceivedCallback();
-}
-#endif
-
-}  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 0bd465032..14cb0a3 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -80,7 +80,8 @@
 #endif
 
 // This is the default backoff policy used to communicate with the Data
-// Reduction Proxy configuration service.
+// Reduction Proxy configuration service. The policy gets overwritten based on
+// kDataReductionProxyAggressiveConfigFetch.
 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
     0,                // num_errors_to_ignore
     10 * 1000,        // initial_delay_ms
@@ -134,8 +135,16 @@
 
 }  // namespace
 
-const net::BackoffEntry::Policy& GetBackoffPolicy() {
-  return kDefaultBackoffPolicy;
+net::BackoffEntry::Policy GetBackoffPolicy() {
+  net::BackoffEntry::Policy policy = kDefaultBackoffPolicy;
+  if (base::FeatureList::IsEnabled(
+          features::kDataReductionProxyAggressiveConfigFetch)) {
+    // Disabling always_use_initial_delay allows no backoffs until
+    // num_errors_to_ignore failures have occurred.
+    policy.num_errors_to_ignore = 2;
+    policy.always_use_initial_delay = false;
+  }
+  return policy;
 }
 
 DataReductionProxyConfigServiceClient::DataReductionProxyConfigServiceClient(
@@ -152,7 +161,8 @@
       io_data_(io_data),
       network_connection_tracker_(network_connection_tracker),
       config_storer_(config_storer),
-      backoff_entry_(&backoff_policy),
+      backoff_policy_(backoff_policy),
+      backoff_entry_(&backoff_policy_),
       config_service_url_(util::AddApiKeyToUrl(params::GetConfigServiceURL())),
       enabled_(false),
       remote_config_applied_(false),
@@ -192,7 +202,10 @@
 
 #if defined(OS_ANDROID)
   foreground_fetch_pending_ = false;
-  if (!fetch_succeeded && IsApplicationStateBackground()) {
+  if (!fetch_succeeded &&
+      !base::FeatureList::IsEnabled(
+          features::kDataReductionProxyAggressiveConfigFetch) &&
+      IsApplicationStateBackground()) {
     // If Chromium is in background, then fetch the config when Chromium comes
     // to foreground or after max of |kMaxBackgroundFetchIntervalSeconds| and
     // |backoff_delay|.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
index 92dd6ca..8e211ba9 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
@@ -48,7 +48,7 @@
 
 // Retrieves the default net::BackoffEntry::Policy for the Data Reduction Proxy
 // configuration service client.
-const net::BackoffEntry::Policy& GetBackoffPolicy();
+net::BackoffEntry::Policy GetBackoffPolicy();
 
 // Retrieves the Data Reduction Proxy configuration from a remote service. This
 // object lives on the IO thread.
@@ -210,6 +210,7 @@
   ConfigStorer config_storer_;
 
   // Used to calculate the backoff time on request failures.
+  net::BackoffEntry::Policy backoff_policy_;
   net::BackoffEntry backoff_entry_;
 
   // The URL for retrieving the Data Reduction Proxy configuration.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index 477a489..f0a0b92 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
@@ -28,6 +29,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
@@ -83,10 +85,18 @@
 
 class DataReductionProxyConfigServiceClientTest : public testing::Test {
  protected:
-  DataReductionProxyConfigServiceClientTest()
+  DataReductionProxyConfigServiceClientTest(
+      bool enable_aggressive_config_fetch_feature = false)
       : test_shared_url_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)) {
+    if (enable_aggressive_config_fetch_feature) {
+      scoped_feature_list_.InitAndEnableFeature(
+          features::kDataReductionProxyAggressiveConfigFetch);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(
+          features::kDataReductionProxyAggressiveConfigFetch);
+    }
     // TODO(tonikitoo): Do a clean up pass to remove unneeded class members
     // once the URLFetcher->SimpleURLLoader switch stabalizes.
     // This includes |context_|, |context_storage_|, |mock_socket_factory_|,
@@ -424,6 +434,7 @@
   }
 
  private:
+  base::test::ScopedFeatureList scoped_feature_list_;
   base::test::ScopedTaskEnvironment task_environment_{
       base::test::ScopedTaskEnvironment::MainThreadType::IO};
   std::unique_ptr<net::TestURLRequestContext> context_;
@@ -508,7 +519,7 @@
   config_client()->RetrieveConfig();
   RunUntilIdle();
   EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
-  EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay());
+  EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
 
 #if defined(OS_ANDROID)
   EXPECT_FALSE(config_client()->foreground_fetch_pending());
@@ -518,7 +529,7 @@
   config_client()->RetrieveConfig();
   RunUntilIdle();
   EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
-  EXPECT_EQ(base::TimeDelta::FromSeconds(40), config_client()->GetDelay());
+  EXPECT_EQ(base::TimeDelta::FromSeconds(90), config_client()->GetDelay());
   EXPECT_TRUE(persisted_config().empty());
   EXPECT_TRUE(persisted_config_retrieval_time().is_null());
 
@@ -617,7 +628,7 @@
   config_client()->RetrieveConfig();
   RunUntilIdle();
   EXPECT_EQ(1, config_client()->failed_attempts_before_success());
-  EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay());
+  EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
   EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
   EXPECT_TRUE(request_options()->GetSecureSession().empty());
 
@@ -662,8 +673,8 @@
     }
 
     // Verify that the backoff increased exponentially.
-    EXPECT_EQ(base::TimeDelta::FromSeconds(320),
-              config_client()->GetDelay());  // 320 = 20 * 2^(5-1)
+    EXPECT_EQ(base::TimeDelta::FromSeconds(2430),
+              config_client()->GetDelay());  // 2430 = 30 * 3^(5-1)
     EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount());
 
     // IP address change should reset.
@@ -705,8 +716,8 @@
   }
 
   // Verify that the backoff increased exponentially.
-  EXPECT_EQ(base::TimeDelta::FromSeconds(320),
-            config_client()->GetDelay());  // 320 = 20 * 2^(5-1)
+  EXPECT_EQ(base::TimeDelta::FromSeconds(2430),
+            config_client()->GetDelay());  // 2430 = 30 * 3^(5-1)
   EXPECT_EQ(kFailureCount, config_client()->GetBackoffErrorCount());
 
   // IP address change should reset.
@@ -1437,12 +1448,12 @@
     EXPECT_FALSE(config_client()->foreground_fetch_pending());
     histogram_tester.ExpectTotalCount(
         "DataReductionProxy.ConfigService.FetchLatency", 0);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay());
+    EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
     config_client()->TriggerApplicationStatusToForeground();
     RunUntilIdle();
     histogram_tester.ExpectTotalCount(
         "DataReductionProxy.ConfigService.FetchLatency", 0);
-    EXPECT_EQ(base::TimeDelta::FromSeconds(20), config_client()->GetDelay());
+    EXPECT_EQ(base::TimeDelta::FromSeconds(30), config_client()->GetDelay());
   }
 
   {
@@ -1470,6 +1481,55 @@
     VerifyRemoteSuccess(true);
   }
 }
+
+class DataReductionProxyAggressiveConfigServiceClientTest
+    : public DataReductionProxyConfigServiceClientTest {
+ public:
+  DataReductionProxyAggressiveConfigServiceClientTest()
+      : DataReductionProxyConfigServiceClientTest(true) {}
+};
+
+TEST_F(DataReductionProxyAggressiveConfigServiceClientTest,
+       AggressiveFetchConfigOnBackground) {
+  Init(true);
+  SetDataReductionProxyEnabled(true, true);
+
+  // Tests that config fetch failures while Chromium is in background, trigger
+  // refetches while still in background, and no refetch happens Chromium
+  // comes to foreground, when the aggressive client config fetch feature is
+  // enabled.
+  base::HistogramTester histogram_tester;
+  AddMockFailure();
+  AddMockFailure();
+  AddMockSuccess();
+  config_client()->set_application_state_background(true);
+  config_client()->RetrieveConfig();
+  RunUntilIdle();
+  // Three fetches are triggered in background without any backoff. First two
+  // fail, while the third succeeds.
+  EXPECT_EQ(base::TimeDelta::FromSeconds(0),
+            config_client()->GetBackoffTimeUntilRelease());
+  EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
+            config_client()->GetDelay());
+  EXPECT_FALSE(config_client()->foreground_fetch_pending());
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigService.FetchLatency", 1);
+  histogram_tester.ExpectBucketCount(
+      "DataReductionProxy.ConfigService.FetchFailedAttemptsBeforeSuccess", 2,
+      1);
+
+  // No new fetch should happen when Chromium comes to foreground.
+  config_client()->set_application_state_background(false);
+  config_client()->TriggerApplicationStatusToForeground();
+  RunUntilIdle();
+  EXPECT_FALSE(config_client()->foreground_fetch_pending());
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.ConfigService.FetchLatency", 1);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(kConfigRefreshDurationSeconds),
+            config_client()->GetDelay());
+  VerifyRemoteSuccess(true);
+}
+
 #endif
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
index 5aa2e50..eefb6e8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -148,14 +148,6 @@
 const Client kClient = Client::UNKNOWN;
 #endif
 
-class TestLoFiUIService : public LoFiUIService {
- public:
-  TestLoFiUIService() {}
-  ~TestLoFiUIService() override {}
-
-  void OnLoFiReponseReceived(const net::URLRequest& request) override {}
-};
-
 class DataReductionProxyDelegateTest : public testing::Test {
  public:
   DataReductionProxyDelegateTest()
@@ -169,10 +161,6 @@
     context_.set_client_socket_factory(&mock_socket_factory_);
     test_context_->AttachToURLRequestContext(&context_storage_);
 
-    std::unique_ptr<TestLoFiUIService> lofi_ui_service(new TestLoFiUIService());
-    lofi_ui_service_ = lofi_ui_service.get();
-    test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service));
-
     proxy_delegate_ = test_context_->io_data()->CreateProxyDelegate();
     context_.Init();
     context_.proxy_resolution_service()->SetProxyDelegate(
@@ -253,8 +241,6 @@
   net::TestURLRequestContext context_;
   net::URLRequestContextStorage context_storage_;
 
-  TestLoFiUIService* lofi_ui_service_;
-
   std::unique_ptr<DataReductionProxyTestContext> test_context_;
   std::unique_ptr<DataReductionProxyDelegate> proxy_delegate_;
 };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
index 05a8cfa..336f5c3 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -24,7 +24,6 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy.mojom.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_throttle_manager.h"
 #include "components/data_reduction_proxy/core/common/lofi_decider.h"
-#include "components/data_reduction_proxy/core/common/lofi_ui_service.h"
 #include "components/data_reduction_proxy/core/common/resource_type_provider.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -193,13 +192,6 @@
     lofi_decider_ = std::move(lofi_decider);
   }
 
-  LoFiUIService* lofi_ui_service() const { return lofi_ui_service_.get(); }
-
-  // Takes ownership of |lofi_ui_service|.
-  void set_lofi_ui_service(std::unique_ptr<LoFiUIService> lofi_ui_service) {
-    lofi_ui_service_ = std::move(lofi_ui_service);
-  }
-
   ResourceTypeProvider* resource_type_provider() const {
     DCHECK(io_task_runner_->BelongsToCurrentThread());
     return resource_type_provider_.get();
@@ -280,9 +272,6 @@
   // Handles getting if a request is in Lo-Fi mode.
   std::unique_ptr<LoFiDecider> lofi_decider_;
 
-  // Handles showing Lo-Fi UI when a Lo-Fi response is received.
-  std::unique_ptr<LoFiUIService> lofi_ui_service_;
-
   // Handles getting the content type of a request.
   std::unique_ptr<ResourceTypeProvider> resource_type_provider_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 6fb8ad2..6938e41 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -468,11 +468,8 @@
       // infobar.
       !IsEntireResource(request->response_headers());
 
-  if ((server_lofi || will_show_client_lofi_placeholder) &&
-      data_reduction_proxy_io_data_ &&
-      data_reduction_proxy_io_data_->lofi_ui_service()) {
-    data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived(
-        *request);
+  if (server_lofi || will_show_client_lofi_placeholder) {
+    // TODO(robertogden): Remove this code.
   } else if (data_reduction_proxy_io_data_ && request->response_headers() &&
              IsLitePagePreview(*(request->response_headers()))) {
     RecordLitePageTransformationType(LITE_PAGE);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 2d65f55..7d43b29 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -245,23 +245,6 @@
   bool ignore_is_using_data_reduction_proxy_check_;
 };
 
-class TestLoFiUIService : public LoFiUIService {
- public:
-  TestLoFiUIService() : on_lofi_response_(false) {}
-  ~TestLoFiUIService() override {}
-
-  bool DidNotifyLoFiResponse() const { return on_lofi_response_; }
-
-  void OnLoFiReponseReceived(const net::URLRequest& request) override {
-    on_lofi_response_ = true;
-  }
-
-  void ClearResponse() { on_lofi_response_ = false; }
-
- private:
-  bool on_lofi_response_;
-};
-
 class TestResourceTypeProvider : public ResourceTypeProvider {
  public:
   void SetContentType(const net::URLRequest& request) override {}
@@ -290,7 +273,6 @@
  public:
   DataReductionProxyNetworkDelegateTest()
       : lofi_decider_(nullptr),
-        lofi_ui_service_(nullptr),
         ssl_socket_data_provider_(net::ASYNC, net::OK) {
     ssl_socket_data_provider_.next_proto = net::kProtoHTTP11;
     ssl_socket_data_provider_.ssl_info.cert = net::ImportCertFromFile(
@@ -339,10 +321,6 @@
     lofi_decider_ = lofi_decider.get();
     test_context_->io_data()->set_lofi_decider(std::move(lofi_decider));
 
-    std::unique_ptr<TestLoFiUIService> lofi_ui_service(new TestLoFiUIService());
-    lofi_ui_service_ = lofi_ui_service.get();
-    test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service));
-
     context_->Init();
 
     test_context_->DisableWarmupURLFetch();
@@ -432,12 +410,6 @@
               header_value.find("empty-image") != std::string::npos);
   }
 
-  void VerifyDidNotifyLoFiResponse(bool lofi_response) const {
-    EXPECT_EQ(lofi_response, lofi_ui_service_->DidNotifyLoFiResponse());
-  }
-
-  void ClearLoFiUIService() { lofi_ui_service_->ClearResponse(); }
-
   void VerifyDataReductionProxyData(const net::URLRequest& request,
                                     bool data_reduction_proxy_used,
                                     bool lofi_used) {
@@ -690,7 +662,6 @@
   std::unique_ptr<net::URLRequestContextStorage> context_storage_;
 
   TestLoFiDecider* lofi_decider_;
-  TestLoFiUIService* lofi_ui_service_;
   std::unique_ptr<DataReductionProxyTestContext> test_context_;
 
   net::SSLSocketDataProvider ssl_socket_data_provider_;
@@ -1321,7 +1292,6 @@
        NonServerLoFiResponseDoesNotTriggerInfobar) {
   Init(USE_INSECURE_PROXY);
 
-  ClearLoFiUIService();
   lofi_decider()->SetIsUsingClientLoFi(false);
   std::string response_headers =
       "HTTP/1.1 200 OK\r\n"
@@ -1334,14 +1304,12 @@
       FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
 
   EXPECT_FALSE(DataReductionProxyData::GetData(*request)->lofi_received());
-  VerifyDidNotifyLoFiResponse(false);
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        ServerLoFiResponseDoesTriggerInfobar) {
   Init(USE_INSECURE_PROXY);
 
-  ClearLoFiUIService();
   lofi_decider()->SetIsUsingClientLoFi(false);
   std::string response_headers =
       "HTTP/1.1 200 OK\r\n"
@@ -1355,86 +1323,6 @@
       FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0);
 
   EXPECT_TRUE(DataReductionProxyData::GetData(*request)->lofi_received());
-  VerifyDidNotifyLoFiResponse(true);
-}
-
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       NonClientLoFiResponseDoesNotTriggerInfobar) {
-  Init(USE_INSECURE_PROXY);
-
-  ClearLoFiUIService();
-  lofi_decider()->SetIsUsingClientLoFi(false);
-
-  FetchURLRequest(GURL(kTestURL), nullptr,
-                  "HTTP/1.1 206 Partial Content\r\n"
-                  "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-                  "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-                  "Via: 1.1 Chrome-Compression-Proxy\r\n"
-                  "Content-Range: bytes 0-139/2048\r\n\r\n",
-                  140, 0);
-
-  VerifyDidNotifyLoFiResponse(false);
-}
-
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       ClientLoFiCompleteResponseDoesNotTriggerInfobar) {
-  Init(USE_INSECURE_PROXY);
-
-  const char* const test_response_headers[] = {
-      "HTTP/1.1 200 OK\r\n"
-      "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-      "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
-
-      "HTTP/1.1 204 No Content\r\n"
-      "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-      "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
-
-      "HTTP/1.1 404 Not Found\r\n"
-      "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-      "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
-
-      "HTTP/1.1 206 Partial Content\r\n"
-      "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-      "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Content-Range: bytes 0-139/140\r\n\r\n",
-  };
-
-  for (const char* headers : test_response_headers) {
-    ClearLoFiUIService();
-    lofi_decider()->SetIsUsingClientLoFi(true);
-    FetchURLRequest(GURL(kTestURL), nullptr, headers, 140, 0);
-    VerifyDidNotifyLoFiResponse(false);
-  }
-}
-
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       ClientLoFiPartialRangeDoesTriggerInfobar) {
-  Init(USE_INSECURE_PROXY);
-
-  const char* const test_response_headers[] = {
-      "HTTP/1.1 206 Partial Content\r\n"
-      "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-      "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Content-Range: bytes 0-139/2048\r\n\r\n",
-
-      "HTTP/1.1 206 Partial Content\r\n"
-      "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n"
-      "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Content-Range: bytes 5-144/145\r\n\r\n",
-  };
-
-  for (const char* headers : test_response_headers) {
-    ClearLoFiUIService();
-    lofi_decider()->SetIsUsingClientLoFi(true);
-    FetchURLRequest(GURL(kTestURL), nullptr, headers, 140, 0);
-    VerifyDidNotifyLoFiResponse(true);
-  }
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index 3225086..c7c45da 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -68,15 +68,14 @@
 
 const char kTestKey[] = "test-key";
 
-const net::BackoffEntry::Policy kTestBackoffPolicy = {
-    0,               // num_errors_to_ignore
-    10 * 1000,       // initial_delay_ms
-    2,               // multiply_factor
-    0,               // jitter_factor
-    30 * 60 * 1000,  // maximum_backoff_ms
-    -1,              // entry_lifetime_ms
-    true,            // always_use_initial_delay
-};
+net::BackoffEntry::Policy kTestBackoffPolicy;
+
+const net::BackoffEntry::Policy& GetTestBackoffPolicy() {
+  kTestBackoffPolicy = data_reduction_proxy::GetBackoffPolicy();
+  // Remove jitter to bring certainty in the tests.
+  kTestBackoffPolicy.jitter_factor = 0;
+  return kTestBackoffPolicy;
+}
 
 }  // namespace
 
@@ -109,8 +108,9 @@
         DataReductionProxyConfig* config,
         DataReductionProxyIOData* io_data,
         network::NetworkConnectionTracker* network_connection_tracker,
-        ConfigStorer config_storer)
-    : DataReductionProxyConfigServiceClient(kTestBackoffPolicy,
+        ConfigStorer config_storer,
+        const net::BackoffEntry::Policy& backoff_policy)
+    : DataReductionProxyConfigServiceClient(backoff_policy,
                                             request_options,
                                             config_values,
                                             config,
@@ -121,7 +121,7 @@
       is_application_state_background_(false),
 #endif
       tick_clock_(base::Time::UnixEpoch()),
-      test_backoff_entry_(&kTestBackoffPolicy, &tick_clock_) {
+      test_backoff_entry_(&backoff_policy, &tick_clock_) {
 }
 
 TestDataReductionProxyConfigServiceClient::
@@ -141,6 +141,11 @@
   return config_refresh_timer_.GetCurrentDelay();
 }
 
+base::TimeDelta
+TestDataReductionProxyConfigServiceClient::GetBackoffTimeUntilRelease() const {
+  return test_backoff_entry_.GetTimeUntilRelease();
+}
+
 int TestDataReductionProxyConfigServiceClient::GetBackoffErrorCount() {
   return test_backoff_entry_.failure_count();
 }
@@ -515,7 +520,8 @@
         std::move(params), io_data->request_options(), raw_mutable_config,
         io_data->config(), io_data.get(), test_network_connection_tracker,
         base::BindRepeating(&TestConfigStorer::StoreSerializedConfig,
-                            base::Unretained(config_storer.get()))));
+                            base::Unretained(config_storer.get())),
+        GetTestBackoffPolicy()));
   } else if (use_config_client_) {
     config_client.reset(new DataReductionProxyConfigServiceClient(
         GetBackoffPolicy(), io_data->request_options(), raw_mutable_config,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index e999f03b..f8531cf 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -98,7 +98,8 @@
       DataReductionProxyConfig* config,
       DataReductionProxyIOData* io_data,
       network::NetworkConnectionTracker* network_connection_tracker,
-      ConfigStorer config_storer);
+      ConfigStorer config_storer,
+      const net::BackoffEntry::Policy& backoff_policy);
 
   ~TestDataReductionProxyConfigServiceClient() override;
 
@@ -112,6 +113,8 @@
 
   int GetBackoffErrorCount();
 
+  base::TimeDelta GetBackoffTimeUntilRelease() const;
+
   void SetConfigServiceURL(const GURL& service_url);
 
   int32_t failed_attempts_before_success() const;
diff --git a/components/data_reduction_proxy/core/common/BUILD.gn b/components/data_reduction_proxy/core/common/BUILD.gn
index 6c121fa6..7a6dd3d 100644
--- a/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/components/data_reduction_proxy/core/common/BUILD.gn
@@ -30,7 +30,6 @@
       "data_reduction_proxy_throttle_manager.h",
       "data_reduction_proxy_type_info.h",
       "lofi_decider.h",
-      "lofi_ui_service.h",
       "resource_type_provider.h",
       "uma_util.cc",
       "uma_util.h",
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 97bf9fc..ebc21359 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -67,5 +67,11 @@
 const base::Feature kDataReductionProxyServerExperiments{
     "DataReductionProxyServerExperiments", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables fetching the client config aggressively by tuning the backoff params
+// and by not deferring fetches while Chrome is in background.
+const base::Feature kDataReductionProxyAggressiveConfigFetch{
+    "DataReductionProxyAggressiveConfigFetch",
+    base::FEATURE_ENABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index 9fc873b..81b4514 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -20,6 +20,7 @@
 extern const base::Feature kDataReductionProxyPopulatePreviewsPageIDToPingback;
 extern const base::Feature kDataReductionProxyDisableProxyFailedWarmup;
 extern const base::Feature kDataReductionProxyServerExperiments;
+extern const base::Feature kDataReductionProxyAggressiveConfigFetch;
 
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/lofi_ui_service.h b/components/data_reduction_proxy/core/common/lofi_ui_service.h
deleted file mode 100644
index 656dab4d..0000000
--- a/components/data_reduction_proxy/core/common/lofi_ui_service.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_LOFI_UI_SERVICE_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_LOFI_UI_SERVICE_H_
-
-#include "base/macros.h"
-
-namespace net {
-class URLRequest;
-}
-
-namespace data_reduction_proxy {
-
-// Passes notifications to the UI thread that a Lo-Fi response has been
-// received. These notifications may be used to show Lo-Fi UI.
-class LoFiUIService {
- public:
-  virtual ~LoFiUIService() {}
-
-  // Notifies the UI thread that |request| has a Lo-Fi response.
-  virtual void OnLoFiReponseReceived(const net::URLRequest& request) = 0;
-};
-
-}  // namespace data_reduction_proxy
-
-#endif  // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_LOFI_UI_SERVICE_H_
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index f10d190..afc0be21 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -502,7 +502,7 @@
           widget->non_client_view()->frame_view());
 
   // Normal state.
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_EQ(normal_window_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(normal_window_bounds));
@@ -512,7 +512,7 @@
   shell_surface->SetGeometry(fullscreen_bounds);
   surface->Commit();
 
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(
       gfx::Size(800, 468),
@@ -521,7 +521,7 @@
   // AutoHide
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
   surface->Commit();
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(fullscreen_bounds,
             frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds));
@@ -529,7 +529,7 @@
   // Fullscreen state.
   shell_surface->SetFullscreen(true);
   surface->Commit();
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(fullscreen_bounds,
             frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds));
@@ -539,7 +539,7 @@
   shell_surface->SetGeometry(client_bounds);
   surface->SetFrame(SurfaceFrameType::NORMAL);
   surface->Commit();
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_EQ(normal_window_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(normal_window_bounds));
@@ -549,7 +549,7 @@
   shell_surface->SetGeometry(client_bounds);
   surface->SetFrame(SurfaceFrameType::NONE);
   surface->Commit();
-  EXPECT_FALSE(frame_view->visible());
+  EXPECT_FALSE(frame_view->GetVisible());
   EXPECT_EQ(client_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(client_bounds));
@@ -559,11 +559,11 @@
   shell_surface->SetGeometry(fullscreen_bounds);
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
   surface->Commit();
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode());
   surface->SetFrame(SurfaceFrameType::NONE);
   surface->Commit();
-  EXPECT_FALSE(frame_view->visible());
+  EXPECT_FALSE(frame_view->GetVisible());
   EXPECT_FALSE(frame_view->GetHeaderView()->in_immersive_mode());
 }
 
@@ -1854,7 +1854,7 @@
           shell_surface->GetWidget()->non_client_view()->frame_view());
   // Snapped window can also use auto hide.
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
-  EXPECT_TRUE(frame_view->visible());
+  EXPECT_TRUE(frame_view->GetVisible());
   EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode());
 }
 
diff --git a/components/exo/fullscreen_shell_surface.cc b/components/exo/fullscreen_shell_surface.cc
index b0262de..236da687 100644
--- a/components/exo/fullscreen_shell_surface.cc
+++ b/components/exo/fullscreen_shell_surface.cc
@@ -197,7 +197,7 @@
 
 void FullscreenShellSurface::CreateFullscreenShellSurfaceWidget(
     ui::WindowShowState show_state) {
-  DCHECK(enabled());
+  DCHECK(GetEnabled());
   DCHECK(!widget_);
 
   views::Widget::InitParams params;
@@ -237,7 +237,7 @@
 }
 
 bool FullscreenShellSurface::OnPreWidgetCommit() {
-  if (!widget_ && enabled() && host_window()->bounds().IsEmpty())
+  if (!widget_ && GetEnabled() && host_window()->bounds().IsEmpty())
     return false;
 
   return true;
diff --git a/components/feedback/feedback_common.cc b/components/feedback/feedback_common.cc
index 41f4149..65cff4b 100644
--- a/components/feedback/feedback_common.cc
+++ b/components/feedback/feedback_common.cc
@@ -42,8 +42,6 @@
 constexpr char kPngMimeType[] = "image/png";
 constexpr char kArbitraryMimeType[] = "application/octet-stream";
 
-constexpr char kGoogleDotCom[] = "@google.com";
-
 // Determine if the given feedback value is small enough to not need to
 // be compressed.
 bool BelowCompressionThreshold(const std::string& content) {
@@ -249,8 +247,7 @@
       // @google.com email. We do this also in feedback_private_api, but not all
       // code paths go through that so we need to check again here.
       if (iter.first == feedback::FeedbackReport::kAllCrashReportIdsKey &&
-          !base::EndsWith(user_email(), kGoogleDotCom,
-                          base::CompareCase::INSENSITIVE_ASCII)) {
+          !feedback_util::IsGoogleEmail(user_email())) {
         continue;
       }
 
diff --git a/components/feedback/feedback_util.cc b/components/feedback/feedback_util.cc
index 1572c9d..c879e17df 100644
--- a/components/feedback/feedback_util.cc
+++ b/components/feedback/feedback_util.cc
@@ -9,9 +9,15 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_util.h"
 #include "third_party/zlib/google/zip.h"
 
 namespace feedback_util {
+namespace {
+
+constexpr char kAtGoogleDotCom[] = "@google.com";
+
+}  // namespace
 
 bool ZipString(const base::FilePath& filename,
                const std::string& data, std::string* compressed_logs) {
@@ -36,4 +42,9 @@
   return succeed;
 }
 
+bool IsGoogleEmail(const std::string& email) {
+  return base::EndsWith(email, kAtGoogleDotCom,
+                        base::CompareCase::INSENSITIVE_ASCII);
+}
+
 }  // namespace feedback_util
diff --git a/components/feedback/feedback_util.h b/components/feedback/feedback_util.h
index 8cb4012..31d0bf2 100644
--- a/components/feedback/feedback_util.h
+++ b/components/feedback/feedback_util.h
@@ -15,6 +15,9 @@
                const std::string& data,
                std::string* compressed_data);
 
+// Returns true for google.com email addresses.
+bool IsGoogleEmail(const std::string& email);
+
 }  // namespace feedback_util
 
 #endif  // COMPONENTS_FEEDBACK_FEEDBACK_UTIL_H_
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 34e0e0bc..4977559 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -136,7 +136,7 @@
     AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_ANDROID = 65,
     ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID = 66,
     INSTANT_APPS_INFOBAR_DELEGATE_ANDROID = 67,
-    DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE = 68,
+    // Removed: DATA_REDUCTION_PROXY_PREVIEW_INFOBAR_DELEGATE = 68,
     SCREEN_CAPTURE_INFOBAR_DELEGATE_ANDROID = 69,
     GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID = 70,
     OFFLINE_PAGE_INFOBAR_DELEGATE_ANDROID = 71,
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index c2b1aa3..cb17685 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -160,7 +160,8 @@
   // empty string if there is no explanation.
   base::string16 GetWhyThisSuggestionText() const;
 
-  // Comparison function for determining when one match is better than another.
+  // Comparison function for determining whether the first match is better than
+  // the second.
   static bool MoreRelevant(const AutocompleteMatch& elem1,
                            const AutocompleteMatch& elem2);
 
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index 8bcf1a10..f962f72 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -31,6 +31,8 @@
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using metrics::OmniboxEventProto;
+
 typedef AutocompleteMatchType ACMatchType;
 
 struct MatchGURLHash {
@@ -174,7 +176,7 @@
   std::sort(matches_.begin(), matches_.end(), comparing_object);
   // Top match is not allowed to be the default match.  Find the most
   // relevant legal match and shift it to the front.
-  auto it = FindTopMatch(&matches_);
+  auto it = FindTopMatch(input.current_page_classification(), &matches_);
   if (it != matches_.end())
     std::rotate(matches_.begin(), it, it + 1);
   // In the process of trimming, drop all matches with a demoted relevance
@@ -361,19 +363,32 @@
 
 // static
 ACMatches::const_iterator AutocompleteResult::FindTopMatch(
+    OmniboxEventProto::PageClassification page_classification,
     const ACMatches& matches) {
-  auto it = matches.begin();
-  while ((it != matches.end()) && !it->allowed_to_be_default_match)
-    ++it;
-  return it;
+  return FindTopMatch(page_classification, const_cast<ACMatches*>(&matches));
 }
 
 // static
-ACMatches::iterator AutocompleteResult::FindTopMatch(ACMatches* matches) {
-  auto it = matches->begin();
-  while ((it != matches->end()) && !it->allowed_to_be_default_match)
-    ++it;
-  return it;
+ACMatches::iterator AutocompleteResult::FindTopMatch(
+    OmniboxEventProto::PageClassification page_classification,
+    ACMatches* matches) {
+  if (page_classification !=
+          OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS &&
+      OmniboxFieldTrial::IsPreserveDefaultMatchScoreEnabled()) {
+    auto best = matches->end();
+    for (auto it = matches->begin(); it != matches->end(); ++it) {
+      if (it->allowed_to_be_default_match &&
+          (best == matches->end() ||
+           AutocompleteMatch::MoreRelevant(*it, *best))) {
+        best = it;
+      }
+    }
+    return best;
+  } else {
+    return std::find_if(matches->begin(), matches->end(), [](const auto& m) {
+      return m.allowed_to_be_default_match;
+    });
+  }
 }
 
 void AutocompleteResult::Reset() {
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h
index 533715f..ed334bd 100644
--- a/components/omnibox/browser/autocomplete_result.h
+++ b/components/omnibox/browser/autocomplete_result.h
@@ -94,8 +94,14 @@
   bool TopMatchIsStandaloneVerbatimMatch() const;
 
   // Returns the first match in |matches| which might be chosen as default.
-  static ACMatches::const_iterator FindTopMatch(const ACMatches& matches);
-  static ACMatches::iterator FindTopMatch(ACMatches* matches);
+  // If |kOmniboxPreserveDefaultMatchScore| is enabled and the page is not
+  // the fake box, the scores are not demoted by type.
+  static ACMatches::const_iterator FindTopMatch(
+      metrics::OmniboxEventProto::PageClassification page_classification,
+      const ACMatches& matches);
+  static ACMatches::iterator FindTopMatch(
+      metrics::OmniboxEventProto::PageClassification page_classification,
+      ACMatches* matches);
 
   const GURL& alternate_nav_url() const { return alternate_nav_url_; }
 
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index e1588a3..cc39838 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -549,6 +549,11 @@
   return static_cast<EmphasizeTitlesCondition>(value);
 }
 
+bool OmniboxFieldTrial::IsPreserveDefaultMatchScoreEnabled() {
+  return base::FeatureList::IsEnabled(
+      omnibox::kOmniboxPreserveDefaultMatchScore);
+}
+
 bool OmniboxFieldTrial::IsReverseAnswersEnabled() {
   return base::FeatureList::IsEnabled(omnibox::kOmniboxReverseAnswers);
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index d63dac93..64d48ec 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -380,6 +380,9 @@
 // ---------------------------------------------------------
 // For UI experiments.
 
+// Returns whether preserve default match score is enabled.
+bool IsPreserveDefaultMatchScoreEnabled();
+
 // Returns true if the reverse answers flag is enabled.
 bool IsReverseAnswersEnabled();
 
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc
index ad8eb714..fa608b8d 100644
--- a/components/omnibox/browser/search_provider.cc
+++ b/components/omnibox/browser/search_provider.cc
@@ -549,7 +549,8 @@
         (keyword_url != nullptr) &&
         (keyword_url->type() == TemplateURL::OMNIBOX_API_EXTENSION);
     if ((keyword_url != nullptr) && !is_extension_keyword &&
-        (AutocompleteResult::FindTopMatch(&matches_) == matches_.end())) {
+        (AutocompleteResult::FindTopMatch(input_.current_page_classification(),
+                                          matches_) == matches_.end())) {
       // In non-extension keyword mode, disregard the keyword verbatim suggested
       // relevance if necessary, so at least one match is allowed to be default.
       // (In extension keyword mode this is not necessary because the extension
@@ -571,7 +572,8 @@
       ConvertResultsToAutocompleteMatches();
     }
     if (!is_extension_keyword &&
-        (AutocompleteResult::FindTopMatch(&matches_) == matches_.end())) {
+        (AutocompleteResult::FindTopMatch(input_.current_page_classification(),
+                                          matches_) == matches_.end())) {
       // Guarantee that SearchProvider returns a legal default match (except
       // when in extension-based keyword mode).  The omnibox always needs at
       // least one legal default match, and it relies on SearchProvider in
@@ -586,15 +588,17 @@
       ConvertResultsToAutocompleteMatches();
     }
     DCHECK(!IsTopMatchSearchWithURLInput());
-    DCHECK(is_extension_keyword ||
-           (AutocompleteResult::FindTopMatch(&matches_) != matches_.end()));
+    DCHECK(is_extension_keyword || (AutocompleteResult::FindTopMatch(
+                                        input_.current_page_classification(),
+                                        matches_) != matches_.end()));
   }
 }
 
 void SearchProvider::RecordTopSuggestion() {
   top_query_suggestion_fill_into_edit_ = base::string16();
   top_navigation_suggestion_ = GURL();
-  auto first_match = AutocompleteResult::FindTopMatch(matches_);
+  auto first_match = AutocompleteResult::FindTopMatch(
+      input_.current_page_classification(), matches_);
   if (first_match != matches_.end()) {
     // Identify if this match came from a query suggestion or a navsuggestion.
     // In either case, extracts the identifying feature of the suggestion
@@ -1082,7 +1086,8 @@
   // Guarantee that if there's a legal default match anywhere in the result
   // set that it'll get returned.  The rotate() call does this by moving the
   // default match to the front of the list.
-  auto default_match = AutocompleteResult::FindTopMatch(&matches);
+  auto default_match = AutocompleteResult::FindTopMatch(
+      input_.current_page_classification(), &matches);
   if (default_match != matches.end())
     std::rotate(matches.begin(), default_match, default_match + 1);
 
@@ -1134,7 +1139,8 @@
 }
 
 bool SearchProvider::IsTopMatchSearchWithURLInput() const {
-  auto first_match = AutocompleteResult::FindTopMatch(matches_);
+  auto first_match = AutocompleteResult::FindTopMatch(
+      input_.current_page_classification(), matches_);
   return (input_.type() == metrics::OmniboxInputType::URL) &&
          (first_match != matches_.end()) &&
          (first_match->relevance > CalculateRelevanceForVerbatim()) &&
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 1243c0e..f18ec04 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -90,6 +90,9 @@
 const base::Feature kOmniboxNewAnswerLayout{"OmniboxNewAnswerLayout",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kOmniboxPreserveDefaultMatchScore{
+    "OmniboxPreserveDefaultMatchScore", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature used to enable swapping the rows on answers.
 const base::Feature kOmniboxReverseAnswers{"OmniboxReverseAnswers",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 9711a32..699398a 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -29,6 +29,7 @@
 extern const base::Feature kOmniboxSuggestionTransparencyOptions;
 extern const base::Feature kOmniboxUICuesForSearchHistoryMatches;
 extern const base::Feature kOmniboxAlternateMatchDescriptionSeparator;
+extern const base::Feature kOmniboxPreserveDefaultMatchScore;
 extern const base::Feature kEnableClipboardProviderTextSuggestions;
 extern const base::Feature kEnableClipboardProviderImageSuggestions;
 extern const base::Feature kSearchProviderWarmUpOnFocus;
diff --git a/components/previews/core/previews_experiments.cc b/components/previews/core/previews_experiments.cc
index 30ff9af..47d321790 100644
--- a/components/previews/core/previews_experiments.cc
+++ b/components/previews/core/previews_experiments.cc
@@ -296,10 +296,6 @@
   return base::FeatureList::IsEnabled(features::kPreviews);
 }
 
-bool IsPreviewsOmniboxUiEnabled() {
-  return base::FeatureList::IsEnabled(features::kAndroidOmniboxPreviewsBadge);
-}
-
 bool IsOfflinePreviewsEnabled() {
   return base::FeatureList::IsEnabled(features::kOfflinePreviews);
 }
diff --git a/components/previews/core/previews_experiments.h b/components/previews/core/previews_experiments.h
index 85b70f4..0706ff6 100644
--- a/components/previews/core/previews_experiments.h
+++ b/components/previews/core/previews_experiments.h
@@ -161,9 +161,6 @@
 // Whether any previews are allowed. Acts as a kill-switch or holdback check.
 bool ArePreviewsAllowed();
 
-// Whether the Previews UI is in the omnibox instead of an infobar.
-bool IsPreviewsOmniboxUiEnabled();
-
 // Whether the preview type is enabled.
 bool IsOfflinePreviewsEnabled();
 bool IsClientLoFiEnabled();
diff --git a/components/previews/core/previews_features.cc b/components/previews/core/previews_features.cc
index 027c1db..5c02eff8 100644
--- a/components/previews/core/previews_features.cc
+++ b/components/previews/core/previews_features.cc
@@ -81,11 +81,6 @@
 const base::Feature kLitePageServerPreviews{"LitePageServerPreviews",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Shows a Previews icon and string in the Android Omnibox instead of an Infobar
-// when enabled. Only works and is honored on Android..
-const base::Feature kAndroidOmniboxPreviewsBadge{
-    "AndroidOmniboxPreviewsBadge", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Provides slow page triggering parameters.
 const base::Feature kSlowPageTriggering{"PreviewsSlowPageTriggering",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/previews/core/previews_features.h b/components/previews/core/previews_features.h
index 1f889bb..c2c8f34d 100644
--- a/components/previews/core/previews_features.h
+++ b/components/previews/core/previews_features.h
@@ -20,7 +20,6 @@
 constexpr char kOptimizationHintsExperimentNameParam[] = "experiment_name";
 extern const base::Feature kResourceLoadingHints;
 extern const base::Feature kLitePageServerPreviews;
-extern const base::Feature kAndroidOmniboxPreviewsBadge;
 extern const base::Feature kSlowPageTriggering;
 extern const base::Feature kHTTPSServerPreviewsUsingURLLoader;
 extern const base::Feature kPreviewsReloadsAreSoftOptOuts;
diff --git a/components/safe_browsing/BUILD.gn b/components/safe_browsing/BUILD.gn
index a435efc..7d8a539 100644
--- a/components/safe_browsing/BUILD.gn
+++ b/components/safe_browsing/BUILD.gn
@@ -16,6 +16,16 @@
   ]
 }
 
+proto_library("realtimeapi_proto") {
+  sources = [
+    "proto/realtimeapi.proto",
+  ]
+
+  deps = [
+    ":csd_proto",
+  ]
+}
+
 source_set("safe_browsing") {
   sources = [
     "base_blocking_page.cc",
diff --git a/components/safe_browsing/db/safebrowsing.proto b/components/safe_browsing/db/safebrowsing.proto
index a111415c..eff947dd 100644
--- a/components/safe_browsing/db/safebrowsing.proto
+++ b/components/safe_browsing/db/safebrowsing.proto
@@ -292,6 +292,9 @@
 
   // Billing threat list. The internal proto's enum name is different
   BILLING = 15;
+
+  // Safe list to ship hashes of known safe URL expressions.
+  HIGH_CONFIDENCE_ALLOWLIST = 16;
 }
 
 // Types of platforms.
diff --git a/components/safe_browsing/proto/realtimeapi.proto b/components/safe_browsing/proto/realtimeapi.proto
new file mode 100644
index 0000000..3f1598df
--- /dev/null
+++ b/components/safe_browsing/proto/realtimeapi.proto
@@ -0,0 +1,73 @@
+// 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.
+//
+// This proto file includes the protocol buffers for communicating with the Safe
+// Browsing Real Time API.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package safe_browsing;
+
+import "csd.proto";
+
+message RTLookupRequest {
+  // If applicable, URL submitted from Chrome.
+  optional string url = 1;
+  // Type of Lookup submitted by Chrome.
+  enum LookupType {
+    // Lookup type is not specified in request.
+    LOOKUP_TYPE_UNSPECIFIED = 0;
+    // Lookup type is navigation.
+    NAVIGATION = 1;
+    // Lookup type is download.
+    DOWNLOAD = 2;
+  }
+  optional LookupType lookup_type = 2;
+  // Mechanism to have different detection methods for different user
+  // population later.
+  optional ChromeUserPopulation population = 3;
+}
+
+message RTLookupResponse {
+  // Contains threat information including threat type, verdict type, cache
+  // duration and cache expression on a matching url.
+  message ThreatInfo {
+    // Type of threat detected.
+    enum ThreatType {
+      // Unknown.
+      THREAT_TYPE_UNSPECIFIED = 0;
+      // url leads to the 'unintentional' download of malware
+      DRIVE_BY_DOWNLOAD = 1;
+      // Malware download threat type.
+      MALWARE_DOWNLOAD = 2;
+      // Social engineering threat type for internal use.
+      SOCIAL_ENGINEERING = 3;
+      // Unwanted software threat type.
+      UNWANTED_SOFTWARE = 4;
+      // Unclear Billing threat type
+      UNCLEAR_BILLING = 5;
+    }
+    optional ThreatType threat_type = 1;
+    // TTL of the verdict in seconds.
+    optional int64 cache_duration_sec = 2;
+    // A host-suffix/path-prefix expression for caching the verdict
+    optional string cache_expression = 3;
+    // Type of verdicts issued by the server. Different levels of verdicts from
+    // 1 to 100 can be added in future based on the confidence of the verdict.
+    // 1 being confidently safe to 100 being confidently dangerous.
+    enum VerdictType {
+      VERDICT_TYPE_UNSPECIFIED = 0;
+      SAFE = 1;
+      DANGEROUS = 100;
+    }
+    optional VerdictType verdict_type = 4;
+  }
+  // Each matching url can have multiple threats detected, if the response
+  // contains multiple threat_info messages, then they are in decreasing order
+  // of severity so that the client could choose first applicable threat_info
+  // as the most severe one.
+  repeated ThreatInfo threat_info = 1;
+}
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc
index f29d0de..b3e4d98 100644
--- a/components/signin/core/browser/about_signin_internals.cc
+++ b/components/signin/core/browser/about_signin_internals.cc
@@ -33,6 +33,35 @@
 // |kMaxRefreshTokenListSize| events are kept in memory.
 const size_t kMaxRefreshTokenListSize = 50;
 
+enum class GaiaCookiesState {
+  kAllowed,
+  kClearOnExit,
+  kBlocked,
+};
+
+GaiaCookiesState GetGaiaCookiesState(SigninClient* signin_client) {
+  bool signin_cookies_allowed = signin_client->AreSigninCookiesAllowed();
+  if (!signin_cookies_allowed)
+    return GaiaCookiesState::kBlocked;
+
+  bool clear_cookies_on_exit = signin_client->AreSigninCookiesDeletedOnExit();
+  if (clear_cookies_on_exit)
+    return GaiaCookiesState::kClearOnExit;
+
+  return GaiaCookiesState::kAllowed;
+}
+
+std::string GetGaiaCookiesStateAsString(const GaiaCookiesState state) {
+  switch (state) {
+    case GaiaCookiesState::kBlocked:
+      return "Not allowed";
+    case GaiaCookiesState::kClearOnExit:
+      return "Cleared on exit";
+    case GaiaCookiesState::kAllowed:
+      return "Allowed";
+  }
+}
+
 std::string GetTimeStr(base::Time time) {
   return base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(time));
 }
@@ -290,17 +319,31 @@
 
   RefreshSigninPrefs();
 
+  client_->AddContentSettingsObserver(this);
   signin_error_controller_->AddObserver(this);
   identity_manager_->AddObserver(this);
   identity_manager_->AddDiagnosticsObserver(this);
 }
 
 void AboutSigninInternals::Shutdown() {
+  client_->RemoveContentSettingsObserver(this);
   signin_error_controller_->RemoveObserver(this);
   identity_manager_->RemoveObserver(this);
   identity_manager_->RemoveDiagnosticsObserver(this);
 }
 
+void AboutSigninInternals::OnContentSettingChanged(
+    const ContentSettingsPattern& primary_pattern,
+    const ContentSettingsPattern& secondary_pattern,
+    ContentSettingsType content_type,
+    const std::string& resource_identifier) {
+  // If this is not a change to cookie settings, just ignore.
+  if (content_type != CONTENT_SETTINGS_TYPE_COOKIES)
+    return;
+
+  NotifyObservers();
+}
+
 void AboutSigninInternals::NotifyObservers() {
   if (!signin_observers_.might_have_observers())
     return;
@@ -578,6 +621,9 @@
           ->GetDetailedStateOfLoadingOfRefreshTokens();
   AddSectionEntry(basic_info, "TokenService Load Status",
                   TokenServiceLoadCredentialsStateToLabel(load_tokens_state));
+  AddSectionEntry(
+      basic_info, "Gaia cookies state",
+      GetGaiaCookiesStateAsString(GetGaiaCookiesState(signin_client)));
 
   if (identity_manager->HasPrimaryAccount()) {
     CoreAccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
diff --git a/components/signin/core/browser/about_signin_internals.h b/components/signin/core/browser/about_signin_internals.h
index 370e47f..ccfd208 100644
--- a/components/signin/core/browser/about_signin_internals.h
+++ b/components/signin/core/browser/about_signin_internals.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/values.h"
+#include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_error_controller.h"
@@ -35,11 +36,11 @@
 
 // This class collects authentication, signin and token information
 // to propagate to about:signin-internals via SigninInternalsUI.
-class AboutSigninInternals
-    : public KeyedService,
-      SigninErrorController::Observer,
-      identity::IdentityManager::Observer,
-      identity::IdentityManager::DiagnosticsObserver {
+class AboutSigninInternals : public KeyedService,
+                             public content_settings::Observer,
+                             SigninErrorController::Observer,
+                             identity::IdentityManager::Observer,
+                             identity::IdentityManager::DiagnosticsObserver {
  public:
   class Observer {
    public:
@@ -217,6 +218,12 @@
   // SigninErrorController::Observer implementation
   void OnErrorChanged() override;
 
+  // content_settings::Observer implementation.
+  void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
+                               const ContentSettingsPattern& secondary_pattern,
+                               ContentSettingsType content_type,
+                               const std::string& resource_identifier) override;
+
   // Weak pointer to the identity manager.
   identity::IdentityManager* identity_manager_;
 
diff --git a/components/signin/core/browser/resources/signin_index.html b/components/signin/core/browser/resources/signin_index.html
index 835d2d2c..64d6602 100644
--- a/components/signin/core/browser/resources/signin_index.html
+++ b/components/signin/core/browser/resources/signin_index.html
@@ -77,7 +77,7 @@
     <div class="account-section">
       <table class="signin-details">
         <tr class="header">
-          <td>Accound Id</td>
+          <td>Account Id</td>
           <td>Has refresh token</td>
           <td>Has persistent auth error</td>
         </tr>
diff --git a/components/signin/core/browser/signin_client.h b/components/signin/core/browser/signin_client.h
index 0b288a6..e49465d 100644
--- a/components/signin/core/browser/signin_client.h
+++ b/components/signin/core/browser/signin_client.h
@@ -79,6 +79,9 @@
   // Returns true if GAIA cookies are allowed in the content area.
   virtual bool AreSigninCookiesAllowed() = 0;
 
+  // Returns true if signin cookies are cleared on exit.
+  virtual bool AreSigninCookiesDeletedOnExit() = 0;
+
   // Adds an observer to listen for changes to the state of sign in cookie
   // settings.
   virtual void AddContentSettingsObserver(
diff --git a/components/signin/core/browser/test_signin_client.cc b/components/signin/core/browser/test_signin_client.cc
index 237beae6..3f945fea 100644
--- a/components/signin/core/browser/test_signin_client.cc
+++ b/components/signin/core/browser/test_signin_client.cc
@@ -70,6 +70,10 @@
   return are_signin_cookies_allowed_;
 }
 
+bool TestSigninClient::AreSigninCookiesDeletedOnExit() {
+  return false;
+}
+
 void TestSigninClient::AddContentSettingsObserver(
     content_settings::Observer* observer) {
 }
diff --git a/components/signin/core/browser/test_signin_client.h b/components/signin/core/browser/test_signin_client.h
index 103cf599..ac713d6 100644
--- a/components/signin/core/browser/test_signin_client.h
+++ b/components/signin/core/browser/test_signin_client.h
@@ -79,6 +79,7 @@
   bool IsFirstRun() const override;
   base::Time GetInstallDate() override;
   bool AreSigninCookiesAllowed() override;
+  bool AreSigninCookiesDeletedOnExit() override;
   void AddContentSettingsObserver(
       content_settings::Observer* observer) override;
   void RemoveContentSettingsObserver(
diff --git a/components/spellcheck/renderer/spellcheck.cc b/components/spellcheck/renderer/spellcheck.cc
index 5f0a221c..f0b2bf9 100644
--- a/components/spellcheck/renderer/spellcheck.cc
+++ b/components/spellcheck/renderer/spellcheck.cc
@@ -118,21 +118,22 @@
 
 class SpellCheck::SpellcheckRequest {
  public:
-  SpellcheckRequest(const base::string16& text,
-                    blink::WebTextCheckingCompletion* completion)
-      : text_(text), completion_(completion) {
-    DCHECK(completion);
+  SpellcheckRequest(
+      const base::string16& text,
+      std::unique_ptr<blink::WebTextCheckingCompletion> completion)
+      : text_(text), completion_(std::move(completion)) {
+    DCHECK(completion_);
   }
   ~SpellcheckRequest() {}
 
   base::string16 text() { return text_; }
-  blink::WebTextCheckingCompletion* completion() { return completion_; }
+  blink::WebTextCheckingCompletion* completion() { return completion_.get(); }
 
  private:
   base::string16 text_;  // Text to be checked in this task.
 
   // The interface to send the misspelled ranges to WebKit.
-  blink::WebTextCheckingCompletion* completion_;
+  std::unique_ptr<blink::WebTextCheckingCompletion> completion_;
 
   DISALLOW_COPY_AND_ASSIGN(SpellcheckRequest);
 };
@@ -387,13 +388,13 @@
 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
 void SpellCheck::RequestTextChecking(
     const base::string16& text,
-    blink::WebTextCheckingCompletion* completion) {
+    std::unique_ptr<blink::WebTextCheckingCompletion> completion) {
   // Clean up the previous request before starting a new request.
   if (pending_request_param_)
     pending_request_param_->completion()->DidCancelCheckingText();
 
-  pending_request_param_.reset(new SpellcheckRequest(
-      text, completion));
+  pending_request_param_.reset(
+      new SpellcheckRequest(text, std::move(completion)));
   // We will check this text after we finish loading the hunspell dictionary.
   if (InitializeIfNeeded())
     return;
diff --git a/components/spellcheck/renderer/spellcheck.h b/components/spellcheck/renderer/spellcheck.h
index e12e4f9..25d1f07 100644
--- a/components/spellcheck/renderer/spellcheck.h
+++ b/components/spellcheck/renderer/spellcheck.h
@@ -103,8 +103,9 @@
   // Requests to spellcheck the specified text in the background. This function
   // posts a background task and calls SpellCheckParagraph() in the task.
 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-  void RequestTextChecking(const base::string16& text,
-                           blink::WebTextCheckingCompletion* completion);
+  void RequestTextChecking(
+      const base::string16& text,
+      std::unique_ptr<blink::WebTextCheckingCompletion> completion);
 #endif
 
   // Creates a list of WebTextCheckingResult objects (used by WebKit) from a
diff --git a/components/spellcheck/renderer/spellcheck_provider.cc b/components/spellcheck/renderer/spellcheck_provider.cc
index 17bbd9c..d3cae78 100644
--- a/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/components/spellcheck/renderer/spellcheck_provider.cc
@@ -112,7 +112,7 @@
 
 void SpellCheckProvider::RequestTextChecking(
     const base::string16& text,
-    WebTextCheckingCompletion* completion) {
+    std::unique_ptr<WebTextCheckingCompletion> completion) {
   // Ignore invalid requests.
   if (text.empty() || !HasWordCharacters(text, 0)) {
     completion->DidCancelCheckingText();
@@ -120,14 +120,14 @@
   }
 
   // Try to satisfy check from cache.
-  if (SatisfyRequestFromCache(text, completion))
+  if (SatisfyRequestFromCache(text, completion.get()))
     return;
 
   // Send this text to a browser. A browser checks the user profile and send
   // this text to the Spelling service only if a user enables this feature.
   last_request_.clear();
   last_results_.Assign(blink::WebVector<blink::WebTextCheckingResult>());
-  last_identifier_ = text_check_completions_.Add(completion);
+  last_identifier_ = text_check_completions_.Add(std::move(completion));
 
 #if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
   // Text check (unified request for grammar and spell check) is only
@@ -193,8 +193,8 @@
 
 void SpellCheckProvider::RequestCheckingOfText(
     const WebString& text,
-    WebTextCheckingCompletion* completion) {
-  RequestTextChecking(text.Utf16(), completion);
+    std::unique_ptr<WebTextCheckingCompletion> completion) {
+  RequestTextChecking(text.Utf16(), std::move(completion));
   UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.async",
                           base::saturated_cast<int>(text.length()));
 }
@@ -205,26 +205,23 @@
     const base::string16& line,
     bool success,
     const std::vector<SpellCheckResult>& results) {
-  WebTextCheckingCompletion* completion =
-      text_check_completions_.Lookup(identifier);
-  if (!completion)
+  if (!text_check_completions_.Lookup(identifier))
     return;
+  std::unique_ptr<WebTextCheckingCompletion> completion(
+      text_check_completions_.Replace(identifier, nullptr));
   text_check_completions_.Remove(identifier);
 
   // If |success| is false, we use local spellcheck as a fallback.
   if (!success) {
-    spellcheck_->RequestTextChecking(line, completion);
+    spellcheck_->RequestTextChecking(line, std::move(completion));
     return;
   }
 
   // Double-check the returned spellchecking results with our spellchecker to
   // visualize the differences between ours and the on-line spellchecker.
   blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
-  spellcheck_->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER,
-                                         0,
-                                         line,
-                                         results,
-                                         &textcheck_results);
+  spellcheck_->CreateTextCheckingResults(SpellCheck::USE_NATIVE_CHECKER, 0,
+                                         line, results, &textcheck_results);
   completion->DidFinishCheckingText(textcheck_results);
 
   // Cache the request and the converted results.
@@ -254,10 +251,10 @@
     const std::vector<SpellCheckResult>& results) {
   // TODO(groby): Unify with SpellCheckProvider::OnRespondSpellingService
   DCHECK(spellcheck_);
-  WebTextCheckingCompletion* completion =
-      text_check_completions_.Lookup(identifier);
-  if (!completion)
+  if (!text_check_completions_.Lookup(identifier))
     return;
+  std::unique_ptr<WebTextCheckingCompletion> completion(
+      text_check_completions_.Replace(identifier, nullptr));
   text_check_completions_.Remove(identifier);
   blink::WebVector<blink::WebTextCheckingResult> textcheck_results;
   spellcheck_->CreateTextCheckingResults(SpellCheck::DO_NOT_MODIFY,
diff --git a/components/spellcheck/renderer/spellcheck_provider.h b/components/spellcheck/renderer/spellcheck_provider.h
index 392186a..b90c7a1 100644
--- a/components/spellcheck/renderer/spellcheck_provider.h
+++ b/components/spellcheck/renderer/spellcheck_provider.h
@@ -36,7 +36,7 @@
       public blink::WebTextCheckClient {
  public:
   using WebTextCheckCompletions =
-      base::IDMap<blink::WebTextCheckingCompletion*>;
+      base::IDMap<std::unique_ptr<blink::WebTextCheckingCompletion>>;
 
   SpellCheckProvider(
       content::RenderFrame* render_frame,
@@ -48,8 +48,9 @@
   // available in the browser process. The function does not have special
   // handling for partial words, as Blink guarantees that no request is made
   // when typing in the middle of a word.
-  void RequestTextChecking(const base::string16& text,
-                           blink::WebTextCheckingCompletion* completion);
+  void RequestTextChecking(
+      const base::string16& text,
+      std::unique_ptr<blink::WebTextCheckingCompletion> completion);
 
   // The number of ongoing spell check host requests.
   size_t pending_text_request_size() const {
@@ -95,7 +96,7 @@
       blink::WebVector<blink::WebString>* optional_suggestions) override;
   void RequestCheckingOfText(
       const blink::WebString& text,
-      blink::WebTextCheckingCompletion* completion) override;
+      std::unique_ptr<blink::WebTextCheckingCompletion> completion) override;
 
 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
   void OnRespondSpellingService(int identifier,
diff --git a/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc b/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
index 40269b8..d179b3b 100644
--- a/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
@@ -17,49 +17,58 @@
 // user finishes typing a word. Also this test verifies that this object checks
 // only a line being edited by the user.
 TEST_F(SpellCheckProviderTest, MultiLineText) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult completion;
 
   // Verify that the SpellCheckProvider class does not spellcheck empty text.
   provider_.ResetResult();
-  provider_.RequestTextChecking(base::string16(), &completion);
+  provider_.RequestTextChecking(
+      base::string16(),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_TRUE(provider_.text_.empty());
   EXPECT_EQ(provider_.spelling_service_call_count_, 0U);
 
   // Verify that the SpellCheckProvider class spellcheck the first word when we
   // stop typing after finishing the first word.
   provider_.ResetResult();
-  provider_.RequestTextChecking(ASCIIToUTF16("First"), &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("First"),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(ASCIIToUTF16("First"), provider_.text_);
   EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
 
   // Verify that the SpellCheckProvider class spellcheck the first line when we
   // type a return key, i.e. when we finish typing a line.
   provider_.ResetResult();
-  provider_.RequestTextChecking(ASCIIToUTF16("First Second\n"), &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("First Second\n"),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(ASCIIToUTF16("First Second\n"), provider_.text_);
   EXPECT_EQ(provider_.spelling_service_call_count_, 2U);
 
   // Verify that the SpellCheckProvider class spellcheck the lines when we
   // finish typing a word "Third" to the second line.
   provider_.ResetResult();
-  provider_.RequestTextChecking(ASCIIToUTF16("First Second\nThird "),
-                                &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("First Second\nThird "),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(ASCIIToUTF16("First Second\nThird "), provider_.text_);
   EXPECT_EQ(provider_.spelling_service_call_count_, 3U);
 
   // Verify that the SpellCheckProvider class does not send a spellcheck request
   // when a user inserts whitespace characters.
   provider_.ResetResult();
-  provider_.RequestTextChecking(ASCIIToUTF16("First Second\nThird   "),
-                                &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("First Second\nThird   "),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_TRUE(provider_.text_.empty());
   EXPECT_EQ(provider_.spelling_service_call_count_, 3U);
 
   // Verify that the SpellCheckProvider class spellcheck the lines when we type
   // a period.
   provider_.ResetResult();
-  provider_.RequestTextChecking(ASCIIToUTF16("First Second\nThird   Fourth."),
-                                &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("First Second\nThird   Fourth."),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(ASCIIToUTF16("First Second\nThird   Fourth."), provider_.text_);
   EXPECT_EQ(provider_.spelling_service_call_count_, 4U);
 }
@@ -67,22 +76,28 @@
 // Tests that the SpellCheckProvider class does not send requests to the
 // spelling service when not necessary.
 TEST_F(SpellCheckProviderTest, CancelUnnecessaryRequests) {
-  FakeTextCheckingCompletion completion;
-  provider_.RequestTextChecking(ASCIIToUTF16("hello."), &completion);
+  FakeTextCheckingResult completion;
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("hello."),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(completion.completion_count_, 1U);
   EXPECT_EQ(completion.cancellation_count_, 0U);
   EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
 
   // Test that the SpellCheckProvider does not send a request with the same text
   // as above.
-  provider_.RequestTextChecking(ASCIIToUTF16("hello."), &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16("hello."),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(completion.completion_count_, 2U);
   EXPECT_EQ(completion.cancellation_count_, 0U);
   EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
 
   // Test that the SpellCheckProvider class cancels an incoming request that
   // does not include any words.
-  provider_.RequestTextChecking(ASCIIToUTF16(":-)"), &completion);
+  provider_.RequestTextChecking(
+      ASCIIToUTF16(":-)"),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(completion.completion_count_, 3U);
   EXPECT_EQ(completion.cancellation_count_, 1U);
   EXPECT_EQ(provider_.spelling_service_call_count_, 1U);
@@ -90,7 +105,9 @@
   // Test that the SpellCheckProvider class sends a request when it receives a
   // Russian word.
   const wchar_t kRussianWord[] = L"\x0431\x0451\x0434\x0440\x0430";
-  provider_.RequestTextChecking(WideToUTF16(kRussianWord), &completion);
+  provider_.RequestTextChecking(
+      WideToUTF16(kRussianWord),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(completion.completion_count_, 4U);
   EXPECT_EQ(completion.cancellation_count_, 1U);
   EXPECT_EQ(provider_.spelling_service_call_count_, 2U);
@@ -99,20 +116,23 @@
 // Tests that the SpellCheckProvider calls didFinishCheckingText() when
 // necessary.
 TEST_F(SpellCheckProviderTest, CompleteNecessaryRequests) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult completion;
 
   base::string16 text = ASCIIToUTF16("Icland is an icland ");
-  provider_.RequestTextChecking(text, &completion);
+  provider_.RequestTextChecking(
+      text, std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(0U, completion.cancellation_count_) << "Should finish checking \""
                                                 << text << "\"";
 
   const int kSubstringLength = 18;
   base::string16 substring = text.substr(0, kSubstringLength);
-  provider_.RequestTextChecking(substring, &completion);
+  provider_.RequestTextChecking(
+      substring, std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(0U, completion.cancellation_count_) << "Should finish checking \""
                                                 << substring << "\"";
 
-  provider_.RequestTextChecking(text, &completion);
+  provider_.RequestTextChecking(
+      text, std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(0U, completion.cancellation_count_) << "Should finish checking \""
                                                 << text << "\"";
 }
diff --git a/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc b/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc
index b92aab3..8e444e3 100644
--- a/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_provider_mac_unittest.cc
@@ -16,9 +16,11 @@
 class SpellCheckProviderMacTest : public SpellCheckProviderTest {};
 
 TEST_F(SpellCheckProviderMacTest, SingleRoundtripSuccess) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult completion;
 
-  provider_.RequestTextChecking(base::ASCIIToUTF16("hello "), &completion);
+  provider_.RequestTextChecking(
+      base::ASCIIToUTF16("hello "),
+      std::make_unique<FakeTextCheckingCompletion>(&completion));
   EXPECT_EQ(completion.completion_count_, 0U);
   EXPECT_EQ(provider_.text_check_requests_.size(), 1U);
   EXPECT_EQ(provider_.pending_text_request_size(), 1U);
@@ -39,10 +41,14 @@
 }
 
 TEST_F(SpellCheckProviderMacTest, TwoRoundtripSuccess) {
-  FakeTextCheckingCompletion completion1;
-  provider_.RequestTextChecking(base::ASCIIToUTF16("hello "), &completion1);
-  FakeTextCheckingCompletion completion2;
-  provider_.RequestTextChecking(base::ASCIIToUTF16("bye "), &completion2);
+  FakeTextCheckingResult completion1;
+  provider_.RequestTextChecking(
+      base::ASCIIToUTF16("hello "),
+      std::make_unique<FakeTextCheckingCompletion>(&completion1));
+  FakeTextCheckingResult completion2;
+  provider_.RequestTextChecking(
+      base::ASCIIToUTF16("bye "),
+      std::make_unique<FakeTextCheckingCompletion>(&completion2));
 
   EXPECT_EQ(completion1.completion_count_, 0U);
   EXPECT_EQ(completion2.completion_count_, 0U);
diff --git a/components/spellcheck/renderer/spellcheck_provider_test.cc b/components/spellcheck/renderer/spellcheck_provider_test.cc
index 4eb50cf..22df2d0 100644
--- a/components/spellcheck/renderer/spellcheck_provider_test.cc
+++ b/components/spellcheck/renderer/spellcheck_provider_test.cc
@@ -14,19 +14,20 @@
 #include "components/spellcheck/renderer/spellcheck.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
 
-FakeTextCheckingCompletion::FakeTextCheckingCompletion()
-    : completion_count_(0), cancellation_count_(0) {}
+FakeTextCheckingCompletion::FakeTextCheckingCompletion(
+    FakeTextCheckingResult* result)
+    : result_(result) {}
 
 FakeTextCheckingCompletion::~FakeTextCheckingCompletion() {}
 
 void FakeTextCheckingCompletion::DidFinishCheckingText(
     const blink::WebVector<blink::WebTextCheckingResult>& results) {
-  ++completion_count_;
+  ++result_->completion_count_;
 }
 
 void FakeTextCheckingCompletion::DidCancelCheckingText() {
-  ++completion_count_;
-  ++cancellation_count_;
+  ++result_->completion_count_;
+  ++result_->cancellation_count_;
 }
 
 TestingSpellCheckProvider::TestingSpellCheckProvider(
@@ -51,7 +52,7 @@
 
 void TestingSpellCheckProvider::RequestTextChecking(
     const base::string16& text,
-    blink::WebTextCheckingCompletion* completion) {
+    std::unique_ptr<blink::WebTextCheckingCompletion> completion) {
   if (!loop_ && !base::MessageLoopCurrent::Get())
     loop_ = std::make_unique<base::MessageLoop>();
   if (!binding_.is_bound()) {
@@ -59,7 +60,7 @@
     binding_.Bind(mojo::MakeRequest(&host_proxy));
     SetSpellCheckHostForTesting(std::move(host_proxy));
   }
-  SpellCheckProvider::RequestTextChecking(text, completion);
+  SpellCheckProvider::RequestTextChecking(text, std::move(completion));
   base::RunLoop().RunUntilIdle();
 }
 
@@ -79,13 +80,13 @@
 void TestingSpellCheckProvider::OnCallSpellingService(
     const base::string16& text) {
   ++spelling_service_call_count_;
-  blink::WebTextCheckingCompletion* completion =
-      text_check_completions_.Lookup(last_identifier_);
-  if (!completion) {
+  if (!text_check_completions_.Lookup(last_identifier_)) {
     ResetResult();
     return;
   }
   text_.assign(text);
+  std::unique_ptr<blink::WebTextCheckingCompletion> completion(
+      text_check_completions_.Replace(last_identifier_, nullptr));
   text_check_completions_.Remove(last_identifier_);
   std::vector<blink::WebTextCheckingResult> results;
   results.push_back(
diff --git a/components/spellcheck/renderer/spellcheck_provider_test.h b/components/spellcheck/renderer/spellcheck_provider_test.h
index 65e4558c..74bb59bc 100644
--- a/components/spellcheck/renderer/spellcheck_provider_test.h
+++ b/components/spellcheck/renderer/spellcheck_provider_test.h
@@ -22,18 +22,22 @@
 class MessageLoop;
 }
 
+struct FakeTextCheckingResult {
+  size_t completion_count_ = 0;
+  size_t cancellation_count_ = 0;
+};
+
 // A fake completion object for verification.
 class FakeTextCheckingCompletion : public blink::WebTextCheckingCompletion {
  public:
-  FakeTextCheckingCompletion();
-  ~FakeTextCheckingCompletion();
+  explicit FakeTextCheckingCompletion(FakeTextCheckingResult*);
+  ~FakeTextCheckingCompletion() override;
 
   void DidFinishCheckingText(
       const blink::WebVector<blink::WebTextCheckingResult>& results) override;
   void DidCancelCheckingText() override;
 
-  size_t completion_count_;
-  size_t cancellation_count_;
+  FakeTextCheckingResult* result_;
 };
 
 // Faked test target, which stores sent message for verification.
@@ -47,8 +51,9 @@
 
   ~TestingSpellCheckProvider() override;
 
-  void RequestTextChecking(const base::string16& text,
-                           blink::WebTextCheckingCompletion* completion);
+  void RequestTextChecking(
+      const base::string16& text,
+      std::unique_ptr<blink::WebTextCheckingCompletion> completion);
 
   void SetLastResults(
       const base::string16 last_request,
diff --git a/components/spellcheck/renderer/spellcheck_provider_unittest.cc b/components/spellcheck/renderer/spellcheck_provider_unittest.cc
index 64d9f3c..eb4fa18 100644
--- a/components/spellcheck/renderer/spellcheck_provider_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_provider_unittest.cc
@@ -9,7 +9,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/public/web/web_text_checking_completion.h"
 #include "third_party/blink/public/web/web_text_checking_result.h"
 
 namespace {
@@ -27,17 +26,19 @@
 };
 
 TEST_F(SpellCheckProviderCacheTest, SubstringWithoutMisspellings) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult result;
+  FakeTextCheckingCompletion completion(&result);
 
   blink::WebVector<blink::WebTextCheckingResult> last_results;
   provider_.SetLastResults(base::ASCIIToUTF16("This is a test"), last_results);
   EXPECT_TRUE(provider_.SatisfyRequestFromCache(base::ASCIIToUTF16("This is a"),
                                                 &completion));
-  EXPECT_EQ(completion.completion_count_, 1U);
+  EXPECT_EQ(result.completion_count_, 1U);
 }
 
 TEST_F(SpellCheckProviderCacheTest, SubstringWithMisspellings) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult result;
+  FakeTextCheckingCompletion completion(&result);
 
   blink::WebVector<blink::WebTextCheckingResult> last_results;
   std::vector<blink::WebTextCheckingResult> results;
@@ -48,21 +49,23 @@
   provider_.SetLastResults(base::ASCIIToUTF16("This isq a test"), last_results);
   EXPECT_TRUE(provider_.SatisfyRequestFromCache(
       base::ASCIIToUTF16("This isq a"), &completion));
-  EXPECT_EQ(completion.completion_count_, 1U);
+  EXPECT_EQ(result.completion_count_, 1U);
 }
 
 TEST_F(SpellCheckProviderCacheTest, ShorterTextNotSubstring) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult result;
+  FakeTextCheckingCompletion completion(&result);
 
   blink::WebVector<blink::WebTextCheckingResult> last_results;
   provider_.SetLastResults(base::ASCIIToUTF16("This is a test"), last_results);
   EXPECT_FALSE(provider_.SatisfyRequestFromCache(
       base::ASCIIToUTF16("That is a"), &completion));
-  EXPECT_EQ(completion.completion_count_, 0U);
+  EXPECT_EQ(result.completion_count_, 0U);
 }
 
 TEST_F(SpellCheckProviderCacheTest, ResetCacheOnCustomDictionaryUpdate) {
-  FakeTextCheckingCompletion completion;
+  FakeTextCheckingResult result;
+  FakeTextCheckingCompletion completion(&result);
 
   blink::WebVector<blink::WebTextCheckingResult> last_results;
   provider_.SetLastResults(base::ASCIIToUTF16("This is a test"), last_results);
@@ -71,7 +74,7 @@
 
   EXPECT_FALSE(provider_.SatisfyRequestFromCache(
       base::ASCIIToUTF16("This is a"), &completion));
-  EXPECT_EQ(completion.completion_count_, 0U);
+  EXPECT_EQ(result.completion_count_, 0U);
 }
 
 }  // namespace
diff --git a/components/spellcheck/renderer/spellcheck_unittest.cc b/components/spellcheck/renderer/spellcheck_unittest.cc
index 010a6f7..5e11c30e 100644
--- a/components/spellcheck/renderer/spellcheck_unittest.cc
+++ b/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -130,23 +130,26 @@
   base::test::ScopedTaskEnvironment task_environment_;
 };
 
+struct MockTextCheckingResult {
+  size_t completion_count_ = 0;
+  blink::WebVector<blink::WebTextCheckingResult> last_results_;
+};
+
 // A fake completion object for verification.
 class MockTextCheckingCompletion : public blink::WebTextCheckingCompletion {
  public:
-  MockTextCheckingCompletion()
-      : completion_count_(0) {
-  }
+  explicit MockTextCheckingCompletion(MockTextCheckingResult* result)
+      : result_(result) {}
 
   void DidFinishCheckingText(
       const blink::WebVector<blink::WebTextCheckingResult>& results) override {
-    completion_count_++;
-    last_results_ = results;
+    result_->completion_count_++;
+    result_->last_results_ = results;
   }
 
-  void DidCancelCheckingText() override { completion_count_++; }
+  void DidCancelCheckingText() override { result_->completion_count_++; }
 
-  size_t completion_count_;
-  blink::WebVector<blink::WebTextCheckingResult> last_results_;
+  MockTextCheckingResult* result_;
 };
 
 // Operates unit tests for the content::SpellCheck::SpellCheckWord() function
@@ -999,9 +1002,11 @@
 
 // Make sure RequestTextChecking does not crash if input is empty.
 TEST_F(SpellCheckTest, RequestSpellCheckWithEmptyString) {
-  MockTextCheckingCompletion completion;
+  MockTextCheckingResult completion;
 
-  spell_check()->RequestTextChecking(base::string16(), &completion);
+  spell_check()->RequestTextChecking(
+      base::string16(),
+      std::make_unique<MockTextCheckingCompletion>(&completion));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1010,10 +1015,11 @@
 
 // A simple test case having no misspellings.
 TEST_F(SpellCheckTest, RequestSpellCheckWithoutMisspelling) {
-  MockTextCheckingCompletion completion;
+  MockTextCheckingResult completion;
 
   const base::string16 text = base::ASCIIToUTF16("hello");
-  spell_check()->RequestTextChecking(text, &completion);
+  spell_check()->RequestTextChecking(
+      text, std::make_unique<MockTextCheckingCompletion>(&completion));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1022,10 +1028,11 @@
 
 // A simple test case having one misspelling.
 TEST_F(SpellCheckTest, RequestSpellCheckWithSingleMisspelling) {
-  MockTextCheckingCompletion completion;
+  MockTextCheckingResult completion;
 
   const base::string16 text = base::ASCIIToUTF16("apple, zz");
-  spell_check()->RequestTextChecking(text, &completion);
+  spell_check()->RequestTextChecking(
+      text, std::make_unique<MockTextCheckingCompletion>(&completion));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1037,10 +1044,11 @@
 
 // A simple test case having a few misspellings.
 TEST_F(SpellCheckTest, RequestSpellCheckWithMisspellings) {
-  MockTextCheckingCompletion completion;
+  MockTextCheckingResult completion;
 
   const base::string16 text = base::ASCIIToUTF16("apple, zz, orange, zz");
-  spell_check()->RequestTextChecking(text, &completion);
+  spell_check()->RequestTextChecking(
+      text, std::make_unique<MockTextCheckingCompletion>(&completion));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1055,7 +1063,7 @@
 // A test case that multiple requests comes at once. Make sure all
 // requests are processed.
 TEST_F(SpellCheckTest, RequestSpellCheckWithMultipleRequests) {
-  MockTextCheckingCompletion completion[3];
+  MockTextCheckingResult completion[3];
 
   const base::string16 text[3] = {
     base::ASCIIToUTF16("what, zz"),
@@ -1064,7 +1072,8 @@
   };
 
   for (int i = 0; i < 3; ++i)
-    spell_check()->RequestTextChecking(text[i], &completion[i]);
+    spell_check()->RequestTextChecking(
+        text[i], std::make_unique<MockTextCheckingCompletion>(&completion[i]));
 
   base::RunLoop().RunUntilIdle();
 
@@ -1081,10 +1090,11 @@
 TEST_F(SpellCheckTest, RequestSpellCheckWithoutInitialization) {
   UninitializeSpellCheck();
 
-  MockTextCheckingCompletion completion;
+  MockTextCheckingResult completion;
   const base::string16 text = base::ASCIIToUTF16("zz");
 
-  spell_check()->RequestTextChecking(text, &completion);
+  spell_check()->RequestTextChecking(
+      text, std::make_unique<MockTextCheckingCompletion>(&completion));
 
   // The task will not be posted yet.
   base::RunLoop().RunUntilIdle();
@@ -1096,7 +1106,7 @@
 TEST_F(SpellCheckTest, RequestSpellCheckMultipleTimesWithoutInitialization) {
   UninitializeSpellCheck();
 
-  MockTextCheckingCompletion completion[3];
+  MockTextCheckingResult completion[3];
   const base::string16 text[3] = {
     base::ASCIIToUTF16("what, zz"),
     base::ASCIIToUTF16("apple, zz"),
@@ -1105,7 +1115,8 @@
 
   // Calls RequestTextchecking a few times.
   for (int i = 0; i < 3; ++i)
-    spell_check()->RequestTextChecking(text[i], &completion[i]);
+    spell_check()->RequestTextChecking(
+        text[i], std::make_unique<MockTextCheckingCompletion>(&completion[i]));
 
   // The last task will be posted after initialization, however the other
   // requests should be pressed without spellchecking.
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl.cc b/components/sync_bookmarks/bookmark_model_observer_impl.cc
index f85d60d..69f418f 100644
--- a/components/sync_bookmarks/bookmark_model_observer_impl.cc
+++ b/components/sync_bookmarks/bookmark_model_observer_impl.cc
@@ -355,6 +355,13 @@
   // Shouldn't try to delete untracked entities.
   DCHECK(entity);
   const std::string& sync_id = entity->metadata()->server_id();
+  // If the entity hasn't been committed and doesn't have an inflight commit
+  // request, simply remove it from the tracker.
+  if (entity->metadata()->server_version() == syncer::kUncommittedVersion &&
+      !entity->commit_may_have_started()) {
+    bookmark_tracker_->Remove(sync_id);
+    return;
+  }
   bookmark_tracker_->MarkDeleted(sync_id);
   // Mark the entity that it needs to be committed.
   bookmark_tracker_->IncrementSequenceNumber(sync_id);
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
index c794478..85f246068 100644
--- a/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
@@ -405,11 +405,13 @@
   ASSERT_THAT(
       bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U);
 
+  bookmark_tracker()->MarkCommitMayHaveStarted(id);
+
   // Remove the folder.
   bookmark_model()->Remove(folder_node);
 
   // Simulate a commit response for the first commit request (the creation).
-  // Don't simulate change in id for simplcity.
+  // Don't simulate change in id for simplicity.
   bookmark_tracker()->UpdateUponCommitResponse(id, id,
                                                /*acked_sequence_number=*/1,
                                                /*server_version=*/1);
@@ -429,6 +431,29 @@
   EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 3U);
 }
 
+TEST_F(BookmarkModelObserverImplTest,
+       BookmarkCreationAndRemovalBeforeCommitRequestShouldBeRemovedDirectly) {
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model()->bookmark_bar_node();
+  const bookmarks::BookmarkNode* folder_node = bookmark_model()->AddFolder(
+      /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("folder"));
+
+  // Node should be tracked now.
+  ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
+  const std::string id = bookmark_tracker()
+                             ->GetEntityForBookmarkNode(folder_node)
+                             ->metadata()
+                             ->server_id();
+  ASSERT_THAT(
+      bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U);
+
+  // Remove the folder.
+  bookmark_model()->Remove(folder_node);
+
+  // Entity should have been dropped.
+  EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 3U);
+}
+
 TEST_F(BookmarkModelObserverImplTest, ShouldPositionSiblings) {
   const std::string kTitle = "title";
   const std::string kUrl = "http://www.url.com";
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index 372daf8..a9cf47e1 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -144,6 +144,10 @@
   BookmarkLocalChangesBuilder builder(bookmark_tracker_.get(), bookmark_model_);
   syncer::CommitRequestDataList local_changes =
       builder.BuildCommitRequests(max_entries);
+  for (const std::unique_ptr<syncer::CommitRequestData>& local_change :
+       local_changes) {
+    bookmark_tracker_->MarkCommitMayHaveStarted(local_change->entity->id);
+  }
   std::move(callback).Run(std::move(local_changes));
 }
 
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc
index 9ab1747..40636dd0 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -108,6 +108,7 @@
     const std::string& sync_id = node_metadata.second->server_id();
     auto entity = std::make_unique<Entity>(node_metadata.first,
                                            std::move(node_metadata.second));
+    entity->set_commit_may_have_started(true);
     if (node_metadata.first) {
       // Non-null node means it's not a tombstone.
       bookmark_node_to_entities_map_[node_metadata.first] = entity.get();
@@ -115,6 +116,10 @@
       // Otherwise, it must be a deletion so we must remember to deletion
       // ordering.
       DCHECK(entity->metadata()->is_deleted());
+      // TODO(crbug.com/516866): The below CHECK is added to debug some crashes.
+      // Should be removed after figuring out the reason for the crash.
+      CHECK_EQ(0, std::count(ordered_local_tombstones_.begin(),
+                             ordered_local_tombstones_.end(), entity.get()));
       ordered_local_tombstones_.push_back(entity.get());
     }
     // TODO(crbug.com/516866): The below CHECK is added to debug some crashes.
@@ -266,6 +271,15 @@
   entity->metadata()->set_server_version(server_version);
 }
 
+void SyncedBookmarkTracker::MarkCommitMayHaveStarted(
+    const std::string& sync_id) {
+  auto it = sync_id_to_entities_map_.find(sync_id);
+  DCHECK(it != sync_id_to_entities_map_.end());
+  Entity* entity = it->second.get();
+  DCHECK(entity);
+  entity->set_commit_may_have_started(true);
+}
+
 void SyncedBookmarkTracker::MarkDeleted(const std::string& sync_id) {
   auto it = sync_id_to_entities_map_.find(sync_id);
   Entity* entity = it->second.get();
@@ -274,6 +288,10 @@
   // Clear all references to the deleted bookmark node.
   bookmark_node_to_entities_map_.erase(entity->bookmark_node());
   entity->clear_bookmark_node();
+  // TODO(crbug.com/516866): The below CHECK is added to debug some crashes.
+  // Should be removed after figuring out the reason for the crash.
+  CHECK_EQ(0, std::count(ordered_local_tombstones_.begin(),
+                         ordered_local_tombstones_.end(), entity));
   ordered_local_tombstones_.push_back(entity);
 }
 
@@ -366,6 +384,10 @@
   std::vector<const SyncedBookmarkTracker::Entity*> ordered_local_changes =
       ReorderUnsyncedEntitiesExceptDeletions(entities_with_local_changes);
   for (const Entity* tombstone_entity : ordered_local_tombstones_) {
+    // TODO(crbug.com/516866): The below CHECK is added to debug some crashes.
+    // Should be removed after figuring out the reason for the crash.
+    CHECK_EQ(0, std::count(ordered_local_changes.begin(),
+                           ordered_local_changes.end(), tombstone_entity));
     ordered_local_changes.push_back(tombstone_entity);
   }
   if (ordered_local_changes.size() > max_entries) {
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h
index b232983..fb08d91a 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -76,6 +76,11 @@
       return metadata_.get();
     }
 
+    bool commit_may_have_started() const { return commit_may_have_started_; }
+    void set_commit_may_have_started(bool value) {
+      commit_may_have_started_ = value;
+    }
+
     // Returns the estimate of dynamically allocated memory in bytes.
     size_t EstimateMemoryUsage() const;
 
@@ -86,6 +91,14 @@
     // Serializable Sync metadata.
     const std::unique_ptr<sync_pb::EntityMetadata> metadata_;
 
+    // Whether there could be a commit sent to the server for this entity. It's
+    // used to protect against sending tombstones for entities that have never
+    // been sent to the server. It's only briefly false between the time was
+    // first added to the tracker until the first commit request is sent to the
+    // server. The tracker sets it to true in the constructor because this code
+    // path is only executed in production when loading from disk.
+    bool commit_may_have_started_ = false;
+
     DISALLOW_COPY_AND_ASSIGN(Entity);
   };
 
@@ -130,8 +143,12 @@
   // Updates the server version of an existing entry for the |sync_id|.
   void UpdateServerVersion(const std::string& sync_id, int64_t server_version);
 
+  // Marks an existing entry for |sync_id| that a commit request might have been
+  // sent to the server.
+  void MarkCommitMayHaveStarted(const std::string& sync_id);
+
   // This class maintains the order of calls to this method and the same order
-  // is gauaranteed when returning local changes in
+  // is guaranteed when returning local changes in
   // GetEntitiesWithLocalChanges() as well as in BuildBookmarkModelMetadata().
   void MarkDeleted(const std::string& sync_id);
 
diff --git a/components/test/data/autofill/heuristics/input/003_i18n_es.html b/components/test/data/autofill/heuristics/input/003_i18n_es.html
index 3cc96b23..f2b0934 100644
--- a/components/test/data/autofill/heuristics/input/003_i18n_es.html
+++ b/components/test/data/autofill/heuristics/input/003_i18n_es.html
@@ -18,8 +18,8 @@
       <label for="ph">Teléfono:</label> <input type="text" id="ph"><br>
       <label for="c1">Nombre de Tarjeta:</label> <input type="text" id="c1"><br>
       <label for="c2">Número de Tarjeta:</label> <input type="text" id="c2"><br>
-      <label for="c3">Fecha de Expiración:</label> <input type="text" id="c3"><br>
-      <label for="c4">Fecha de Expiración:</label> <input type="text" id="c4"><br>
+      <label for="c3">Fecha de Expiración:</label> <input type="search" id="c3"><br>
+      <label for="c4">Fecha de Expiración:</label> <input type="search" id="c4"><br>
     </form>
   </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 3dda067..dcf8654b 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -544,17 +544,9 @@
 int RunBrowserProcessMain(const MainFunctionParams& main_function_params,
                           ContentMainDelegate* delegate) {
   int exit_code = delegate->RunProcess("", main_function_params);
-#if defined(OS_ANDROID)
-  // In Android's browser process, the negative exit code doesn't mean the
-  // default behavior should be used as the UI message loop is managed by
-  // the Java and the browser process's default behavior is always
-  // overridden.
-  return exit_code;
-#else
   if (exit_code >= 0)
     return exit_code;
   return BrowserMain(main_function_params);
-#endif
 }
 #endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
 
diff --git a/content/app/strings/content_strings.grd b/content/app/strings/content_strings.grd
index e5cd237..c86bd6fa 100644
--- a/content/app/strings/content_strings.grd
+++ b/content/app/strings/content_strings.grd
@@ -955,7 +955,7 @@
        Download
       </message>
       <if expr="is_macosx">
-        <message name="IDS_MEDIA_OVERFLOW_MENU_ENTER_PICTURE_IN_PICTURE" desc="Media contr  ls overflow menu item label for a button to enter Picture-in-Picture.">
+        <message name="IDS_MEDIA_OVERFLOW_MENU_ENTER_PICTURE_IN_PICTURE" desc="Media controls overflow menu item label for a button to enter Picture-in-Picture.">
           Picture in Picture
         </message>
       </if>
@@ -966,16 +966,16 @@
       </if>
       <if expr="is_macosx">
         <message name="IDS_MEDIA_OVERFLOW_MENU_EXIT_PICTURE_IN_PICTURE" desc="Media controls overflow menu item label for a button to exit Picture-in-Picture.">
-          Exit Picture in Picture
+          Exit Picture-in-Picture
         </message>
       </if>
       <if expr="not is_macosx">
         <message name="IDS_MEDIA_OVERFLOW_MENU_EXIT_PICTURE_IN_PICTURE" desc="Media controls overflow menu item label for a button to exit Picture-in-Picture.">
-          Exit picture in picture
+          Exit picture-in-picture
         </message>
       </if>
       <message name="IDS_MEDIA_PICTURE_IN_PICTURE_INTERSTITIAL_TEXT" desc="Text message shown to user when in picture in picture mode. When a video is in picture in picture mode, an interstitial with this text appears where the video player is positioned. The video continues to play back in another window that gives the experience that the video is 'popped out'.">
-        Playing in picture-in-picture mode
+        Playing in picture-in-picture
       </message>
       <message name="IDS_MEDIA_REMOTING_CAST_TEXT" desc="Text message shown to the user when casting a video to a known remote device.">
        Now casting to <ph name="DEVICE_FRIENDLY_NAME">$1<ex>Living Room TV</ex></ph>
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index f7b2435..47207ee 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1155,6 +1155,8 @@
     "loader/resource_request_info_impl.h",
     "loader/resource_requester_info.cc",
     "loader/resource_requester_info.h",
+    "loader/sec_fetch_site_resource_handler.cc",
+    "loader/sec_fetch_site_resource_handler.h",
     "loader/shared_cors_origin_access_list_impl.cc",
     "loader/shared_cors_origin_access_list_impl.h",
     "loader/source_stream_to_data_pipe.cc",
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc
index ed57071..3e4873e 100644
--- a/content/browser/browser_process_sub_thread.cc
+++ b/content/browser/browser_process_sub_thread.cc
@@ -197,6 +197,10 @@
 #if BUILDFLAG(CLANG_COVERAGE)
       // On coverage build, browser_tests runs 10x slower.
       const int kMaxSecondsToWaitForNetworkProcess = 100;
+#elif defined(OS_CHROMEOS)
+      // ChromeOS will kill the browser process if it doesn't shut down within
+      // 3 seconds, so make sure we wait for less than that.
+      const int kMaxSecondsToWaitForNetworkProcess = 1;
 #else
       const int kMaxSecondsToWaitForNetworkProcess = 10;
 #endif
diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc
index da0893f..c00d975 100644
--- a/content/browser/browsing_instance.cc
+++ b/content/browser/browsing_instance.cc
@@ -26,8 +26,7 @@
           BrowsingInstanceId::FromUnsafeValue(next_browsing_instance_id_++),
           BrowserOrResourceContext(browser_context)),
       active_contents_count_(0u),
-      default_process_(nullptr),
-      default_site_instance_(nullptr) {
+      default_process_(nullptr) {
   DCHECK(browser_context);
 }
 
@@ -52,7 +51,8 @@
 
 bool BrowsingInstance::IsDefaultSiteInstance(
     const SiteInstanceImpl* site_instance) const {
-  return site_instance != nullptr && site_instance == default_site_instance_;
+  return site_instance != nullptr &&
+         site_instance == default_site_instance_.get();
 }
 
 bool BrowsingInstance::HasSiteInstance(const GURL& url) {
@@ -117,18 +117,11 @@
       !SiteInstanceImpl::DoesSiteRequireDedicatedProcess(isolation_context_,
                                                          url)) {
     DCHECK(!default_process_);
-    scoped_refptr<SiteInstanceImpl> site_instance = default_site_instance_;
-    if (!site_instance) {
-      site_instance = new SiteInstanceImpl(this);
-      site_instance->SetSite(SiteInstanceImpl::GetDefaultSiteURL());
-
-      // Keep a copy of the pointer so it can be used for other URLs. This is
-      // safe because the SiteInstanceImpl destructor will call
-      // UnregisterSiteInstance() to clear this copy when the last
-      // reference to |site_instance| is destroyed.
-      default_site_instance_ = site_instance.get();
+    if (!default_site_instance_) {
+      default_site_instance_ = new SiteInstanceImpl(this);
+      default_site_instance_->SetSite(SiteInstanceImpl::GetDefaultSiteURL());
     }
-    return site_instance;
+    return default_site_instance_;
   }
 
   return nullptr;
@@ -140,7 +133,7 @@
 
   // Explicitly prevent the |default_site_instance_| from being added since
   // the map is only supposed to contain instances that map to a single site.
-  if (site_instance == default_site_instance_)
+  if (site_instance == default_site_instance_.get())
     return;
 
   std::string site = site_instance->GetSiteURL().possibly_invalid_spec();
@@ -160,12 +153,6 @@
 void BrowsingInstance::UnregisterSiteInstance(SiteInstanceImpl* site_instance) {
   DCHECK(site_instance->browsing_instance_.get() == this);
   DCHECK(site_instance->HasSite());
-
-  if (site_instance == default_site_instance_) {
-    // The last reference to the default SiteInstance is being destroyed.
-    default_site_instance_ = nullptr;
-  }
-
   std::string site = site_instance->GetSiteURL().possibly_invalid_spec();
 
   // Only unregister the SiteInstance if it is the same one that is registered
@@ -188,7 +175,6 @@
   // us are gone.
   DCHECK(site_instance_map_.empty());
   DCHECK_EQ(0u, active_contents_count_);
-  DCHECK(!default_site_instance_);
   if (default_process_)
     default_process_->RemoveObserver(this);
 }
diff --git a/content/browser/browsing_instance.h b/content/browser/browsing_instance.h
index 775b64a8..d371ea108 100644
--- a/content/browser/browsing_instance.h
+++ b/content/browser/browsing_instance.h
@@ -203,9 +203,8 @@
   // |site_instance_map_| and it does not require a dedicated process.
   // This field and |default_process_| are mutually exclusive and this field
   // should only be set if kProcessSharingWithStrictSiteInstances is not
-  // enabled. This is a raw pointer to avoid a reference cycle between the
-  // BrowsingInstance and the SiteInstanceImpl.
-  SiteInstanceImpl* default_site_instance_;
+  // enabled.
+  scoped_refptr<SiteInstanceImpl> default_site_instance_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowsingInstance);
 };
diff --git a/content/browser/devtools/inspector_fuzzer.cc b/content/browser/devtools/inspector_fuzzer.cc
index d2babebf..4c45d1e8 100644
--- a/content/browser/devtools/inspector_fuzzer.cc
+++ b/content/browser/devtools/inspector_fuzzer.cc
@@ -14,6 +14,10 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   using namespace inspector_protocol_encoding;
 
+  if (size > 64 * 1024) {
+    return 0;
+  }
+
   span<uint8_t> fuzz{data, size};
 
   // We need to handle whatever the parser parses. So, we handle the parsed
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index afd924f..e89a2121 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -232,26 +232,12 @@
   // TODO(mkwst): Extract this logic out somewhere that can be shared between
   // Blink and //content.
   if (IsFetchMetadataEnabled() && IsOriginSecure(url)) {
-    std::string site_value = "cross-site";
-    std::string user_value = has_user_gesture ? "?1" : std::string();
-
     // Navigations that aren't triggerable from the web (e.g. typing in the
-    // address bar, or clicking a bookmark) are labeled as 'none'. Webby
-    // navigations compare the |initiator_origin| to the navigation target.
-    if (!PageTransitionIsWebTriggerable(transition)) {
-      site_value = "none";
+    // address bar, or clicking a bookmark) are labeled as user-initiated.
+    std::string user_value = has_user_gesture ? "?1" : std::string();
+    if (!PageTransitionIsWebTriggerable(transition))
       user_value = "?1";
-    } else if (initiator_origin) {
-      url::Origin target_origin = url::Origin::Create(url);
-      if (initiator_origin->IsSameOriginWith(target_origin)) {
-        site_value = "same-origin";
-      } else if (net::registry_controlled_domains::SameDomainOrHost(
-                     *initiator_origin, target_origin,
-                     net::registry_controlled_domains::
-                         INCLUDE_PRIVATE_REGISTRIES)) {
-        site_value = "same-site";
-      }
-    }
+
     std::string destination;
     std::string mode = "navigate";
     switch (frame_tree_node->frame_owner_element_type()) {
@@ -280,9 +266,9 @@
       headers->SetHeaderIfMissing("Sec-Fetch-Dest", destination.c_str());
     }
     headers->SetHeaderIfMissing("Sec-Fetch-Mode", mode.c_str());
-    headers->SetHeaderIfMissing("Sec-Fetch-Site", site_value.c_str());
     if (!user_value.empty())
       headers->SetHeaderIfMissing("Sec-Fetch-User", user_value.c_str());
+    // Sec-Fetch-Site is covered by network::SetSecFetchSiteHeader function.
   }
 
   // Ask whether we should request a policy.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index ac73b61e..aa264d9 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1758,12 +1758,12 @@
   return true;
 }
 
-void RenderFrameHostImpl::DeleteRenderFrame() {
+void RenderFrameHostImpl::DeleteRenderFrame(FrameDeleteIntention intent) {
   if (!is_active())
     return;
 
   if (render_frame_created_) {
-    Send(new FrameMsg_Delete(routing_id_));
+    Send(new FrameMsg_Delete(routing_id_, intent));
 
     if (!frame_tree_node_->IsMainFrame() && IsCurrent()) {
       // If this subframe has an unload handler (and isn't speculative), ensure
@@ -2036,7 +2036,8 @@
       // observers are notified of its deletion.
       std::unique_ptr<FrameTreeNode> node_to_delete(std::move(*iter));
       children_.erase(iter);
-      node_to_delete->current_frame_host()->DeleteRenderFrame();
+      node_to_delete->current_frame_host()->DeleteRenderFrame(
+          FrameDeleteIntention::kNotMainFrame);
       // Speculative RenderFrameHosts are deleted by the FrameTreeNode's
       // RenderFrameHostManager's destructor. RenderFrameProxyHosts send
       // FrameMsg_Delete automatically in the destructor.
@@ -2059,7 +2060,8 @@
   // this RenderFrameHostImpl to detach the current frame's children, rather
   // than messaging each child's current frame host...
   for (auto& child : children)
-    child->current_frame_host()->DeleteRenderFrame();
+    child->current_frame_host()->DeleteRenderFrame(
+        FrameDeleteIntention::kNotMainFrame);
 }
 
 void RenderFrameHostImpl::SetLastCommittedUrl(const GURL& url) {
@@ -2096,11 +2098,6 @@
   // descendant frames to execute unload handlers. Start executing those
   // handlers now.
   StartPendingDeletionOnSubtree();
-
-  // Ensure that deleted subframes are not visible from the others processes
-  // anymore.
-  frame_tree_node_->render_manager()->ResetProxyHosts();
-
   // Some children with no unload handler may be eligible for immediate
   // deletion. Cut the dead branches now. This is a performance optimization.
   PendingDeletionCheckCompletedOnSubtree();  // Can delete |this|.
@@ -2394,16 +2391,11 @@
     return;
 
   // Start pending deletion on this frame and its children.
-  DeleteRenderFrame();
+  DeleteRenderFrame(FrameDeleteIntention::kNotMainFrame);
   StartPendingDeletionOnSubtree();
-
-  // Ensure that deleted subframes are not visible from the others processes
-  // anymore.
-  frame_tree_node()->render_manager()->ResetProxyHosts();
-
   // Some children with no unload handler may be eligible for immediate
   // deletion. Cut the dead branches now. This is a performance optimization.
-  PendingDeletionCheckCompletedOnSubtree();  // May delete |this|.
+  PendingDeletionCheckCompletedOnSubtree();
 }
 
 void RenderFrameHostImpl::OnBeforeUnloadACK(
@@ -4530,17 +4522,13 @@
           local_ancestor = rfh;
       }
 
-      local_ancestor->DeleteRenderFrame();
+      local_ancestor->DeleteRenderFrame(FrameDeleteIntention::kNotMainFrame);
       if (local_ancestor != child) {
         child->unload_state_ =
             child->GetSuddenTerminationDisablerState(blink::kUnloadHandler)
                 ? UnloadState::InProgress
                 : UnloadState::Completed;
       }
-
-      // Ensure that deleted subframes are not visible from the others processes
-      // anymore.
-      node->render_manager()->ResetProxyHosts();
     }
   }
 }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 723d745..2c3a4ae 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -41,6 +41,7 @@
 #include "content/common/content_export.h"
 #include "content/common/content_security_policy/csp_context.h"
 #include "content/common/frame.mojom.h"
+#include "content/common/frame_delete_intention.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/image_downloader/image_downloader.mojom.h"
@@ -332,7 +333,7 @@
 
   // Deletes the RenderFrame in the renderer process.
   // Postcondition: |is_active()| will return false.
-  void DeleteRenderFrame();
+  void DeleteRenderFrame(FrameDeleteIntention intent);
 
   // Tracks whether the RenderFrame for this RenderFrameHost has been created in
   // the renderer process.  This is currently only used for subframes.
@@ -1055,12 +1056,6 @@
                            NavigationCommitInIframePendingDeletionABC);
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
                            CommittedOriginIncompatibleWithOriginLock);
-  FRIEND_TEST_ALL_PREFIXES(
-      SitePerProcessBrowserTest,
-      IsDetachedSubframeObservableDuringUnloadHandlerSameProcess);
-  FRIEND_TEST_ALL_PREFIXES(
-      SitePerProcessBrowserTest,
-      IsDetachedSubframeObservableDuringUnloadHandlerCrossProcess);
 
   class DroppedInterfaceRequestLogger;
 
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index de85226a..184de12 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -823,7 +823,10 @@
 std::unique_ptr<RenderFrameHostImpl>
 RenderFrameHostManager::UnsetSpeculativeRenderFrameHost() {
   speculative_render_frame_host_->GetProcess()->RemovePendingView();
-  speculative_render_frame_host_->DeleteRenderFrame();
+  speculative_render_frame_host_->DeleteRenderFrame(
+      frame_tree_node_->parent()
+          ? FrameDeleteIntention::kNotMainFrame
+          : FrameDeleteIntention::kSpeculativeMainFrameForNavigationCancelled);
   return std::move(speculative_render_frame_host_);
 }
 
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index d592a07..7f0d8867 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -165,13 +165,6 @@
 bool RenderFrameProxyHost::InitRenderFrameProxy() {
   DCHECK(!render_frame_proxy_created_);
 
-  // If the current RenderFrameHost is pending deletion, no new proxies should
-  // be created for it, since this frame should no longer be visible from other
-  // processes. We can get here with postMessage while trying to recreate
-  // proxies for the sender.
-  if (!frame_tree_node_->current_frame_host()->is_active())
-    return false;
-
   // It is possible to reach this when the process is dead (in particular, when
   // creating proxies from CreateProxiesForChildFrame).  In that case, don't
   // create the proxy.  The process shouldn't be resurrected just to create
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 5d721ca..c8b1f46 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -52,6 +52,7 @@
 #include "content/browser/loader/resource_message_filter.h"
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/loader/resource_requester_info.h"
+#include "content/browser/loader/sec_fetch_site_resource_handler.h"
 #include "content/browser/loader/stream_resource_handler.h"
 #include "content/browser/loader/throttling_resource_handler.h"
 #include "content/browser/loader/upload_data_stream_builder.h"
@@ -1160,6 +1161,8 @@
   plugin_service = PluginService::GetInstance();
 #endif
 
+  handler.reset(new SecFetchSiteResourceHandler(request, std::move(handler)));
+
   if (!IsResourceTypeFrame(resource_type)) {
     // Add a handler to block cross-site documents from the renderer process.
     handler.reset(new CrossSiteDocumentResourceHandler(
diff --git a/content/browser/loader/sec_fetch_site_resource_handler.cc b/content/browser/loader/sec_fetch_site_resource_handler.cc
new file mode 100644
index 0000000..378981d
--- /dev/null
+++ b/content/browser/loader/sec_fetch_site_resource_handler.cc
@@ -0,0 +1,68 @@
+// 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 "content/browser/loader/sec_fetch_site_resource_handler.h"
+
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "services/network/sec_fetch_site.h"
+
+namespace content {
+
+SecFetchSiteResourceHandler::SecFetchSiteResourceHandler(
+    net::URLRequest* request,
+    std::unique_ptr<ResourceHandler> next_handler)
+    : LayeredResourceHandler(request, std::move(next_handler)),
+      factory_params_(CreateURLLoaderFactoryParams()) {}
+
+SecFetchSiteResourceHandler::~SecFetchSiteResourceHandler() = default;
+
+void SecFetchSiteResourceHandler::OnWillStart(
+    const GURL& url,
+    std::unique_ptr<ResourceController> controller) {
+  SetHeader(nullptr);
+
+  next_handler_->OnWillStart(url, std::move(controller));
+}
+
+void SecFetchSiteResourceHandler::OnRequestRedirected(
+    const net::RedirectInfo& redirect_info,
+    network::ResourceResponse* response,
+    std::unique_ptr<ResourceController> controller) {
+  SetHeader(&redirect_info.new_url);
+
+  next_handler_->OnRequestRedirected(redirect_info, response,
+                                     std::move(controller));
+}
+
+void SecFetchSiteResourceHandler::SetHeader(const GURL* new_url_from_redirect) {
+  network::SetSecFetchSiteHeader(request(), new_url_from_redirect,
+                                 *factory_params_);
+}
+
+network::mojom::URLLoaderFactoryParamsPtr
+SecFetchSiteResourceHandler::CreateURLLoaderFactoryParams() {
+  auto result = network::mojom::URLLoaderFactoryParams::New();
+
+  // Translate |info->GetChildID()| (an int, -1 designates a browser process)
+  // into |result->process_id| (an uint32_t, 0 designates a browser process).
+  ResourceRequestInfoImpl* info = GetRequestInfo();
+  if (!info || info->GetChildID() == -1) {
+    result->process_id = network::mojom::kBrowserProcessId;
+  } else {
+    result->process_id = info->GetChildID();
+    DCHECK_NE(network::mojom::kBrowserProcessId, result->process_id);
+  }
+
+  // |request_initiator_site_lock| is not enforced in the legacy,
+  // pre-NetworkService path, so below we plug in a lock that is obviously
+  // compatible with the request initiator.
+  result->request_initiator_site_lock = request()->initiator();
+
+  // Note that some fields of |result| might be left at their default values at
+  // this point.  This is okay - we only care about the two fields that
+  // the network::SetSecFetchSiteHeader function will inspect.
+  return result;
+}
+
+}  // namespace content
diff --git a/content/browser/loader/sec_fetch_site_resource_handler.h b/content/browser/loader/sec_fetch_site_resource_handler.h
new file mode 100644
index 0000000..8e8e8750
--- /dev/null
+++ b/content/browser/loader/sec_fetch_site_resource_handler.h
@@ -0,0 +1,52 @@
+// 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 CONTENT_BROWSER_LOADER_SEC_FETCH_SITE_RESOURCE_HANDLER_H_
+#define CONTENT_BROWSER_LOADER_SEC_FETCH_SITE_RESOURCE_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/browser/loader/layered_resource_handler.h"
+#include "content/browser/loader/resource_controller.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "url/gurl.h"
+
+namespace net {
+struct RedirectInfo;
+class URLRequest;
+}  // namespace net
+
+namespace content {
+
+class SecFetchSiteResourceHandler : public LayeredResourceHandler {
+ public:
+  SecFetchSiteResourceHandler(net::URLRequest* request,
+                              std::unique_ptr<ResourceHandler> next_handler);
+
+ private:
+  ~SecFetchSiteResourceHandler() override;
+  void OnWillStart(const GURL& url,
+                   std::unique_ptr<ResourceController> controller) override;
+  void OnRequestRedirected(
+      const net::RedirectInfo& redirect_info,
+      network::ResourceResponse* response,
+      std::unique_ptr<ResourceController> controller) override;
+
+  // Creates URLLoaderFactoryParams with just enough information filled in to
+  // satisfy the needs of network::SetSecFetchSiteHeader function.
+  network::mojom::URLLoaderFactoryParamsPtr CreateURLLoaderFactoryParams();
+
+  // Sets the Sec-Fetch-Site header (based on the method argument and also on
+  // the state of the |url_request()| and on |factory_params_|).
+  void SetHeader(const GURL* new_url_from_redirect);
+
+  network::mojom::URLLoaderFactoryParamsPtr factory_params_;
+
+  DISALLOW_COPY_AND_ASSIGN(SecFetchSiteResourceHandler);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_SEC_FETCH_SITE_RESOURCE_HANDLER_H_
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index f5ac630..083957ab9 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/run_loop.h"
 #include "base/strings/string16.h"
 #include "base/test/mock_log.h"
-#include "base/test/scoped_command_line.h"
 #include "base/test/scoped_feature_list.h"
 #include "content/browser/browsing_instance.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -239,33 +238,6 @@
   EXPECT_EQ(1, browser_client()->GetAndClearSiteInstanceDeleteCount());
   EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
   // contents is now deleted, along with instance and browsing_instance
-
-  // Ensure that default SiteInstances are deleted when all references to them
-  // are gone.
-  {
-    base::test::ScopedCommandLine scoped_command_line;
-
-    // Disable site isolation so we can get default SiteInstances on all
-    // platforms.
-    scoped_command_line.GetProcessCommandLine()->AppendSwitch(
-        switches::kDisableSiteIsolation);
-
-    auto site_instance1 = SiteInstanceImpl::CreateForURL(
-        browser_context.get(), GURL("http://foo.com"));
-    // TODO(958060): Remove the creation of this second instance and update
-    // the deletion count below once CreateForURL() starts returning a default
-    // SiteInstance for sites that don't require a dedicated process.
-    auto site_instance2 =
-        site_instance1->GetRelatedSiteInstance(GURL("http://bar.com"));
-    EXPECT_FALSE(site_instance1->IsDefaultSiteInstance());
-    EXPECT_TRUE(static_cast<SiteInstanceImpl*>(site_instance2.get())
-                    ->IsDefaultSiteInstance());
-    site_instance1.reset();
-    site_instance2.reset();
-
-    EXPECT_EQ(2, browser_client()->GetAndClearSiteInstanceDeleteCount());
-    EXPECT_EQ(1, browser_client()->GetAndClearBrowsingInstanceDeleteCount());
-  }
 }
 
 // Test to ensure GetProcess returns and creates processes correctly.
diff --git a/content/browser/site_per_process_unload_browsertest.cc b/content/browser/site_per_process_unload_browsertest.cc
index 621ba674..b17d101d 100644
--- a/content/browser/site_per_process_unload_browsertest.cc
+++ b/content/browser/site_per_process_unload_browsertest.cc
@@ -1016,189 +1016,6 @@
   }
 }
 
-// Regression test for https://crbug.com/960006.
-//
-// 1. Navigate to a1(a2(b3),c4),
-// 2. b3 has a slow unload handler.
-// 3. a2 navigates same process.
-// 4. When the new document is loaded, a message is sent to c4 to check it
-//    cannot see b3 anymore, even if b3 is still unloading.
-IN_PROC_BROWSER_TEST_F(
-    SitePerProcessBrowserTest,
-    IsDetachedSubframeObservableDuringUnloadHandlerSameProcess) {
-  GURL page_url(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(a(b),c)"));
-  EXPECT_TRUE(NavigateToURL(shell(), page_url));
-  RenderFrameHostImpl* node1 =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetFrameTree()
-          ->root()
-          ->current_frame_host();
-  RenderFrameHostImpl* node2 = node1->child_at(0)->current_frame_host();
-  RenderFrameHostImpl* node3 = node2->child_at(0)->current_frame_host();
-  RenderFrameHostImpl* node4 = node1->child_at(1)->current_frame_host();
-  ASSERT_TRUE(ExecJs(node1, "window.name = 'node1'"));
-  ASSERT_TRUE(ExecJs(node2, "window.name = 'node2'"));
-  ASSERT_TRUE(ExecJs(node3, "window.name = 'node3'"));
-  ASSERT_TRUE(ExecJs(node4, "window.name = 'node4'"));
-
-  // Test sanity check.
-  EXPECT_EQ(true, EvalJs(node1, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node2, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node3, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node4, "!!top.node2.node3"));
-
-  // Simulate a long-running unload handler in |node3|.
-  auto detach_filter = base::MakeRefCounted<DropMessageFilter>(
-      FrameMsgStart, FrameHostMsg_Detach::ID);
-  node3->GetProcess()->AddFilter(detach_filter.get());
-  node2->DisableSwapOutTimerForTesting();
-  ASSERT_TRUE(ExecJs(node3, "window.onunload = ()=>{}"));
-
-  // Prepare |node4| to respond to postMessage with a report of whether it can
-  // still find |node3|.
-  const char* kPostMessageHandlerScript = R"(
-      window.postMessageGotData == false;
-      window.postMessageCallback = function() {};
-      function receiveMessage(event) {
-          console.log('node4 - receiveMessage...');
-
-          var can_node3_be_found = false;
-          try {
-            can_node3_be_found = !!top.node2.node3;
-          } catch(e) {
-            can_node3_be_found = false;
-          }
-
-          window.postMessageGotData = true;
-          window.postMessageData = can_node3_be_found;
-          window.postMessageCallback(window.postMessageData);
-      }
-      window.addEventListener("message", receiveMessage, false);
-  )";
-  ASSERT_TRUE(ExecJs(node4, kPostMessageHandlerScript));
-
-  // Make |node1| navigate |node2| same process and after the navigation
-  // succeeds, send a post message to |node4|. We expect that the effects of the
-  // commit should be visible to |node4| by the time it receives the posted
-  // message.
-  const char* kNavigationScript = R"(
-      var node2_frame = document.getElementsByTagName('iframe')[0];
-      node2_frame.onload = function() {
-          console.log('node2_frame.onload ...');
-          node4.postMessage('try to find node3', '*');
-      };
-      node2_frame.src = $1;
-  )";
-  GURL url = embedded_test_server()->GetURL("a.com", "/title1.html");
-  ASSERT_TRUE(ExecJs(node1, JsReplace(kNavigationScript, url)));
-
-  // Check if |node4| has seen |node3| even after |node2| navigation finished
-  // (no other frame should see |node3| after the navigation of its parent).
-  const char* kPostMessageResultsScript = R"(
-      new Promise(function (resolve, reject) {
-          if (window.postMessageGotData)
-            resolve(window.postMessageData);
-          else
-            window.postMessageCallback = resolve;
-      });
-  )";
-  EXPECT_EQ(false, EvalJs(node4, kPostMessageResultsScript));
-}
-
-// Regression test for https://crbug.com/960006.
-//
-// 1. Navigate to a1(a2(b3),c4),
-// 2. b3 has a slow unload handler.
-// 3. a2 navigates cross process.
-// 4. When the new document is loaded, a message is sent to c4 to check it
-//    cannot see b3 anymore, even if b3 is still unloading.
-//
-// Note: This test is the same as the above, except it uses a cross-process
-// navigation at step 3.
-IN_PROC_BROWSER_TEST_F(
-    SitePerProcessBrowserTest,
-    IsDetachedSubframeObservableDuringUnloadHandlerCrossProcess) {
-  GURL page_url(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(a(b),c)"));
-  EXPECT_TRUE(NavigateToURL(shell(), page_url));
-  RenderFrameHostImpl* node1 =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetFrameTree()
-          ->root()
-          ->current_frame_host();
-  RenderFrameHostImpl* node2 = node1->child_at(0)->current_frame_host();
-  RenderFrameHostImpl* node3 = node2->child_at(0)->current_frame_host();
-  RenderFrameHostImpl* node4 = node1->child_at(1)->current_frame_host();
-  ASSERT_TRUE(ExecJs(node1, "window.name = 'node1'"));
-  ASSERT_TRUE(ExecJs(node2, "window.name = 'node2'"));
-  ASSERT_TRUE(ExecJs(node3, "window.name = 'node3'"));
-  ASSERT_TRUE(ExecJs(node4, "window.name = 'node4'"));
-
-  // Test sanity check.
-  EXPECT_EQ(true, EvalJs(node1, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node2, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node3, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node4, "!!top.node2.node3"));
-
-  // Add a long-running unload handler to |node3|.
-  auto detach_filter = base::MakeRefCounted<DropMessageFilter>(
-      FrameMsgStart, FrameHostMsg_Detach::ID);
-  node3->GetProcess()->AddFilter(detach_filter.get());
-  node2->DisableSwapOutTimerForTesting();
-  ASSERT_TRUE(ExecJs(node3, "window.onunload = ()=>{}"));
-
-  // Prepare |node4| to respond to postMessage with a report of whether it can
-  // still find |node3|.
-  const char* kPostMessageHandlerScript = R"(
-      window.postMessageGotData == false;
-      window.postMessageCallback = function() {};
-      function receiveMessage(event) {
-          console.log('node4 - receiveMessage...');
-
-          var can_node3_be_found = false;
-          try {
-            can_node3_be_found = !!top.node2.node3;
-          } catch(e) {
-            can_node3_be_found = false;
-          }
-
-          window.postMessageGotData = true;
-          window.postMessageData = can_node3_be_found;
-          window.postMessageCallback(window.postMessageData);
-      }
-      window.addEventListener("message", receiveMessage, false);
-  )";
-  ASSERT_TRUE(ExecJs(node4, kPostMessageHandlerScript));
-
-  // Make |node1| navigate |node2| cross process and after the navigation
-  // succeeds, send a post message to |node4|. We expect that the effects of the
-  // commit should be visible to |node4| by the time it receives the posted
-  // message.
-  const char* kNavigationScript = R"(
-      var node2_frame = document.getElementsByTagName('iframe')[0];
-      node2_frame.onload = function() {
-          console.log('node2_frame.onload ...');
-          node4.postMessage('try to find node3', '*');
-      };
-      node2_frame.src = $1;
-  )";
-  GURL url = embedded_test_server()->GetURL("d.com", "/title1.html");
-  ASSERT_TRUE(ExecJs(node1, JsReplace(kNavigationScript, url)));
-
-  // Check if |node4| has seen |node3| even after |node2| navigation finished
-  // (no other frame should see |node3| after the navigation of its parent).
-  const char* kPostMessageResultsScript = R"(
-      new Promise(function (resolve, reject) {
-          if (window.postMessageGotData)
-            resolve(window.postMessageData);
-          else
-            window.postMessageCallback = resolve;
-      });
-  )";
-  EXPECT_EQ(false, EvalJs(node4, kPostMessageResultsScript));
-}
-
 // Test the unload timeout is effective.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, UnloadTimeout) {
   GURL main_url(embedded_test_server()->GetURL(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index aa8c31f..0acd4b2c 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -689,7 +689,8 @@
   // Do not update state as the WebContents is being destroyed.
   frame_tree_.root()->ResetNavigationRequest(true, true);
   if (root->speculative_frame_host()) {
-    root->speculative_frame_host()->DeleteRenderFrame();
+    root->speculative_frame_host()->DeleteRenderFrame(
+        FrameDeleteIntention::kSpeculativeMainFrameForShutdown);
     root->speculative_frame_host()->SetRenderFrameCreated(false);
     root->speculative_frame_host()->ResetNavigationRequests();
   }
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 085cc75b..6c9931c8 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -222,20 +222,8 @@
   if ((base::FeatureList::IsEnabled(network::features::kFetchMetadata) ||
        experimental_features_enabled) &&
       IsOriginSecure(resource_request->url)) {
-    // The worker's origin can be different from the constructor's origin, for
-    // example, when the worker created from the extension.
-    // TODO(hiroshige): Add DCHECK to make sure the same-originness once the
-    // cross-origin workers are deprecated (https://crbug.com/867302).
-    std::string site_value = "cross-site";
-    if (resource_request->request_initiator->IsSameOriginWith(
-            url::Origin::Create(resource_request->url))) {
-      site_value = "same-origin";
-    }
-    resource_request->headers.SetHeaderIfMissing("Sec-Fetch-Site",
-                                                 site_value.c_str());
     resource_request->headers.SetHeaderIfMissing("Sec-Fetch-Mode",
                                                  "same-origin");
-    // We don't set `Sec-Fetch-User` for subresource requests.
 
     if (base::FeatureList::IsEnabled(
             network::features::kFetchMetadataDestination) ||
@@ -243,6 +231,10 @@
       resource_request->headers.SetHeaderIfMissing("Sec-Fetch-Dest",
                                                    "sharedworker");
     }
+
+    // Note that the `Sec-Fetch-User` header is always false (and therefore
+    // omitted) for subresource requests. Also note that `Sec-Fetch-Site` is
+    // covered elsewhere - by the network::SetSecFetchSiteHeader function.
   }
 }
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 0b464d4..4029ff0 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -112,6 +112,7 @@
     "font_list_fontconfig.cc",
     "font_list_mac.mm",
     "font_list_win.cc",
+    "frame_delete_intention.h",
     "frame_message_enums.h",
     "frame_message_structs.cc",
     "frame_message_structs.h",
diff --git a/content/common/frame_delete_intention.h b/content/common/frame_delete_intention.h
new file mode 100644
index 0000000..f30103c3
--- /dev/null
+++ b/content/common/frame_delete_intention.h
@@ -0,0 +1,27 @@
+// 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 CONTENT_COMMON_FRAME_DELETE_INTENTION_H_
+#define CONTENT_COMMON_FRAME_DELETE_INTENTION_H_
+
+namespace content {
+
+enum class FrameDeleteIntention {
+  // The frame being deleted isn't a (speculative) main frame.
+  kNotMainFrame,
+  // The frame being deleted is a speculative main frame, and it is being
+  // deleted as part of the shutdown for that WebContents. The entire RenderView
+  // etc will be destroyed by a separate IPC sent later.
+  kSpeculativeMainFrameForShutdown,
+  // The frame being deleted is a speculative main frame, and it is being
+  // deleted because the speculative navigation was cancelled. This is not part
+  // of shutdown.
+  kSpeculativeMainFrameForNavigationCancelled,
+
+  kMaxValue = kSpeculativeMainFrameForNavigationCancelled
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_FRAME_DELETE_INTENTION_H_
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 9308081..78b5de6 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -26,6 +26,7 @@
 #include "content/common/content_param_traits.h"
 #include "content/common/content_security_policy/csp_context.h"
 #include "content/common/content_security_policy_header.h"
+#include "content/common/frame_delete_intention.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/frame_message_structs.h"
 #include "content/common/frame_owner_properties.h"
@@ -101,6 +102,8 @@
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
 
 #define IPC_MESSAGE_START FrameMsgStart
+IPC_ENUM_TRAITS_MAX_VALUE(content::FrameDeleteIntention,
+                          content::FrameDeleteIntention::kMaxValue)
 IPC_ENUM_TRAITS_MAX_VALUE(blink::FrameOwnerElementType,
                           blink::FrameOwnerElementType::kMaxValue)
 IPC_ENUM_TRAITS_MAX_VALUE(
@@ -813,7 +816,7 @@
 IPC_MESSAGE_ROUTED1(FrameMsg_VisualStateRequest, uint64_t /* id */)
 
 // Instructs the renderer to delete the RenderFrame.
-IPC_MESSAGE_ROUTED0(FrameMsg_Delete)
+IPC_MESSAGE_ROUTED1(FrameMsg_Delete, content::FrameDeleteIntention)
 
 // Instructs the renderer to invoke the frame's beforeunload event handler.
 // Expects the result to be returned via FrameHostMsg_BeforeUnload_ACK.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index b8106b9..be8e442 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2418,7 +2418,47 @@
   SwapIn();
 }
 
-void RenderFrameImpl::OnDeleteFrame() {
+void RenderFrameImpl::OnDeleteFrame(FrameDeleteIntention intent) {
+  // The main frame (when not provisional) is owned by the renderer's frame tree
+  // via WebViewImpl. When a provisional main frame is swapped in, the ownership
+  // moves from the browser to the renderer, but this happens in the renderer
+  // process and is then the browser is informed.
+  // If the provisional main frame is swapped in while the browser is destroying
+  // it, the browser may request to delete |this|, thinking it has ownership
+  // of it, but the renderer has already taken ownership via SwapIn().
+  switch (intent) {
+    case FrameDeleteIntention::kNotMainFrame:
+      // The frame was not a main frame, so the browser should always have
+      // ownership of it and we can just proceed with deleting it on
+      // request.
+      DCHECK(!is_main_frame_);
+      break;
+    case FrameDeleteIntention::kSpeculativeMainFrameForShutdown:
+      // In this case the renderer has taken ownership of the provisional main
+      // frame but the browser did not know yet and is shutting down. We can
+      // ignore this request as the frame will be destroyed when the RenderView
+      // is. This handles the shutdown case of https://crbug.com/957858.
+      DCHECK(is_main_frame_);
+      if (in_frame_tree_)
+        return;
+      break;
+    case FrameDeleteIntention::kSpeculativeMainFrameForNavigationCancelled:
+      // In this case the browser was navigating and cancelled the speculative
+      // navigation. The renderer *should* undo the SwapIn() but the old state
+      // has already been destroyed. Both ignoring the message or handling it
+      // would leave the renderer in an inconsistent state now. If we ignore it
+      // then the browser thinks the RenderView has a remote main frame, but it
+      // is incorrect. If we handle it, then we are deleting a local main frame
+      // out from under the RenderView and we will have bad pointers in the
+      // renderer. So all we can do is crash. We should instead prevent this
+      // scenario by blocking the browser from dropping the speculative main
+      // frame when a commit (and ownership transfer) is imminent.
+      // TODO(dcheng): This is the case of https://crbug.com/838348.
+      DCHECK(is_main_frame_);
+      CHECK(!in_frame_tree_);
+      break;
+  }
+
   // This will result in a call to RenderFrameImpl::FrameDetached, which
   // deletes the object. Do not access |this| after detach.
   frame_->Detach();
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index e63b99d1..097fe84 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -34,6 +34,7 @@
 #include "content/common/buildflags.h"
 #include "content/common/download/mhtml_file_writer.mojom.h"
 #include "content/common/frame.mojom.h"
+#include "content/common/frame_delete_intention.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/host_zoom.mojom.h"
 #include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
@@ -1108,7 +1109,7 @@
   void OnSwapOut(int proxy_routing_id,
                  bool is_loading,
                  const FrameReplicationState& replicated_frame_state);
-  void OnDeleteFrame();
+  void OnDeleteFrame(FrameDeleteIntention intent);
   void OnStop();
   void OnCollapse(bool collapse);
   void OnShowContextMenu(const gfx::Point& location);
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 644316c..6a5c000 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -497,7 +497,7 @@
       1, "foo", true /* match_case */, true /* forward */,
       false /* find_next */, true /* force */, false /* wrap_within_frame */);
 
-  FrameMsg_Delete delete_message(0);
+  FrameMsg_Delete delete_message(0, FrameDeleteIntention::kNotMainFrame);
   frame()->OnMessageReceived(delete_message);
 }
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 64c6c26..6a00f40 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1969,6 +1969,7 @@
           : base::TimeDelta::FromMilliseconds(
                 blink::mojom::kDefaultCaretBlinkIntervalInMilliseconds));
 
+#if defined(USE_AURA)
   if (renderer_prefs.use_custom_colors) {
     blink::SetFocusRingColor(renderer_prefs.focus_ring_color);
     blink::SetSelectionColors(renderer_prefs.active_selection_bg_color,
@@ -1978,6 +1979,7 @@
     if (webview())
       webview()->MainFrameWidget()->ThemeChanged();
   }
+#endif
 
   if (webview() &&
       old_accept_languages != renderer_preferences_.accept_languages) {
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.cc b/content/renderer/webgraphicscontext3d_provider_impl.cc
index b828238..8352ee02 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.cc
+++ b/content/renderer/webgraphicscontext3d_provider_impl.cc
@@ -98,7 +98,7 @@
       std::make_unique<cc::GpuImageDecodeCache>(
           provider_.get(), use_transfer_cache, color_type, kMaxWorkingSetBytes,
           provider_->ContextCapabilities().max_texture_size,
-          cc::PaintImage::kDefaultGeneratorClientId, color_space));
+          cc::PaintImage::kDefaultGeneratorClientId));
   DCHECK(insertion_result.second);
   cache_iterator = insertion_result.first;
   return cache_iterator->second.get();
diff --git a/content/shell/browser/shell_views.cc b/content/shell/browser/shell_views.cc
index b0314b8..eb4329b 100644
--- a/content/shell/browser/shell_views.cc
+++ b/content/shell/browser/shell_views.cc
@@ -336,14 +336,7 @@
   _setmode(_fileno(stderr), _O_BINARY);
 #endif
 #if defined(OS_CHROMEOS)
-  ui::ContextFactory* ui_context_factory =
-      aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL
-          ? GetContextFactory()
-          : nullptr;
-  wm_test_helper_ = new wm::WMTestHelper(
-      default_window_size,
-      ServiceManagerConnection::GetForProcess()->GetConnector(),
-      ui_context_factory);
+  wm_test_helper_ = new wm::WMTestHelper(default_window_size);
 #else
   wm_state_ = new wm::WMState;
   views::InstallDesktopScreenIfNecessary();
diff --git a/content/shell/test_runner/spell_check_client.cc b/content/shell/test_runner/spell_check_client.cc
index effb4e8..5b6f0cbc 100644
--- a/content/shell/test_runner/spell_check_client.cc
+++ b/content/shell/test_runner/spell_check_client.cc
@@ -65,7 +65,7 @@
 
 void SpellCheckClient::RequestCheckingOfText(
     const blink::WebString& text,
-    blink::WebTextCheckingCompletion* completion) {
+    std::unique_ptr<blink::WebTextCheckingCompletion> completion) {
   if (!enabled_ || text.IsEmpty()) {
     if (completion) {
       completion->DidCancelCheckingText();
@@ -76,11 +76,11 @@
 
   if (last_requested_text_checking_completion_) {
     last_requested_text_checking_completion_->DidCancelCheckingText();
-    last_requested_text_checking_completion_ = nullptr;
+    last_requested_text_checking_completion_.reset();
     RequestResolved();
   }
 
-  last_requested_text_checking_completion_ = completion;
+  last_requested_text_checking_completion_ = std::move(completion);
   last_requested_text_check_string_ = text;
   if (spell_check_.HasInCache(text)) {
     FinishLastTextCheck();
@@ -120,7 +120,7 @@
                                            &results);
   }
   last_requested_text_checking_completion_->DidFinishCheckingText(results);
-  last_requested_text_checking_completion_ = nullptr;
+  last_requested_text_checking_completion_.reset();
   RequestResolved();
 
   if (test_runner_->shouldDumpSpellCheckCallbacks())
diff --git a/content/shell/test_runner/spell_check_client.h b/content/shell/test_runner/spell_check_client.h
index 53a9295..ff85b98 100644
--- a/content/shell/test_runner/spell_check_client.h
+++ b/content/shell/test_runner/spell_check_client.h
@@ -49,7 +49,7 @@
       blink::WebVector<blink::WebString>* optional_suggestions) override;
   void RequestCheckingOfText(
       const blink::WebString& text,
-      blink::WebTextCheckingCompletion* completion) override;
+      std::unique_ptr<blink::WebTextCheckingCompletion> completion) override;
 
  private:
   void FinishLastTextCheck();
@@ -64,7 +64,8 @@
   MockSpellCheck spell_check_;
 
   blink::WebString last_requested_text_check_string_;
-  blink::WebTextCheckingCompletion* last_requested_text_checking_completion_;
+  std::unique_ptr<blink::WebTextCheckingCompletion>
+      last_requested_text_checking_completion_;
 
   v8::Persistent<v8::Function> resolved_callback_;
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 407c342..98455d6b 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1137,7 +1137,6 @@
       "//ppapi/tests/test_case.html",
       "//ppapi/tests/test_page.css",
       "//ppapi/tests/test_url_loader_data/",
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
     ]
diff --git a/content/test/fuzzer/BUILD.gn b/content/test/fuzzer/BUILD.gn
index d0b69441..32652f0 100644
--- a/content/test/fuzzer/BUILD.gn
+++ b/content/test/fuzzer/BUILD.gn
@@ -147,7 +147,6 @@
     "//third_party/inspector_protocol:encoding",
   ]
   seed_corpus = "//components/cbor/reader_fuzzer_corpus/"
-  libfuzzer_options = [ "max_len=65535" ]
 }
 
 fuzzer_test("http_structured_header_fuzzer") {
diff --git a/device/gamepad/gamepad_service.cc b/device/gamepad/gamepad_service.cc
index e77b609..8609511 100644
--- a/device/gamepad/gamepad_service.cc
+++ b/device/gamepad/gamepad_service.cc
@@ -15,6 +15,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "device/gamepad/gamepad_consumer.h"
 #include "device/gamepad/gamepad_data_fetcher.h"
+#include "device/gamepad/gamepad_data_fetcher_manager.h"
 #include "device/gamepad/gamepad_provider.h"
 #include "services/service_manager/public/cpp/connector.h"
 
@@ -64,6 +65,11 @@
     std::unique_ptr<service_manager::Connector> service_manager_connector) {
   if (!service_manager_connector_)
     service_manager_connector_ = std::move(service_manager_connector);
+
+  // Ensures GamepadDataFetcherManager is created on UI thread. Otherwise,
+  // GamepadPlatformDataFetcherLinux::Factory would be created with the
+  // wrong thread for its |dbus_runner_|.
+  GamepadDataFetcherManager::GetInstance();
 }
 
 service_manager::Connector* GamepadService::GetConnector() {
diff --git a/docs/README.md b/docs/README.md
index a7642e43..3107d57 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -278,7 +278,8 @@
 
 ### Misc Chrome-OS-Specific Docs
 *   [Setting up captive portals and other restrictive networks](login/restrictive_networks.md)
-*   [Enrolling a device in OOBE/Login](login/enterprise_enrollment.md)
+*   [Enterprise Enrollment](enterprise/enrollment.md)
+    *   [Kiosk mode and public sessions](enterprise/kiosk_public_session.md)
 *   [Debugging UI in OOBE/login/lock](login/ui_debugging.md)
 *   [Chrome Logging on Chrome OS](chrome_os_logging.md)
 
diff --git a/docs/enterprise/enrollment.md b/docs/enterprise/enrollment.md
new file mode 100644
index 0000000..d3f379a
--- /dev/null
+++ b/docs/enterprise/enrollment.md
@@ -0,0 +1,85 @@
+# Enterprise Enrollment on Chrome OS
+
+Enterprise Enrollment is a process that marks a device as belonging to
+particular organization and enables [management](management.md) of the device
+by organization admins.
+
+[TOC]
+
+## Requirements
+
+Only **devices without owner** can be enrolled. Ownership of the device is
+established either during Enterprise Enrollment (the organization becomes the
+owner of the device) or during first user sign-in (in this case this user
+becomes the owner of the device).
+
+Ownership of the device can be reset using factory reset (```Ctrl+Alt+Shift+R```
+on the login screen), if it is not disabled via device policy.
+
+Developers can reset ownership by running following commands as root in shell:
+```
+pkill -9 chrome
+rm -rf /home/chronos/Local\ State /var/lib/whitelist /home/.shadow
+rm /home/chronos/.oobe_completed
+crossystem clear_tpm_owner_request=1
+reboot
+```
+
+Only **enterprise users** can enroll devices (device will be owned by the
+organization user belongs to).
+
+#### Instructions for Google Employees
+Are you a Google employee? See
+[http://go/managed-devices/faq/using-yaps](https://goto.google.com/managed-devices/faq/using-yaps)
+to learn how to use simple development device management server.
+
+See
+[http://go/managed-devices/faq/test-account](https://goto.google.com/managed-devices/faq/test-account)
+for instuctions on how to get enterprise account for testing.
+
+## Enrollment scenarios
+
+There are several enrollment scenarios, exact choice is made based on
+following factors:
+ * How the authentication is performed
+ * If enrollment can be avoided by user
+ * What initiates enrollment.
+
+#### Instructions for Google Employees
+Are you a Google employee? See
+[go/chromeos-enrollment-overview](https://goto.google.com/chromeos-enrollment-overview)
+for other enrollment scenarios in development.
+
+### Manual enrollment
+
+Enrollment can be triggered manually on the login screen via `Ctrl+Alt+E`
+shortcut. User will have to authenticate using username/password. User can
+cancel enrollment attempt and return to login screen.
+
+### Re-enrollment
+
+During initial setup device queries management service to check if it was
+previously enrolled, and if organization admins indicated that device should
+be enrolled again.
+
+This is set on https://admin.google.com/ under `Enrollment & Access` section on
+`Device Management>Chrome>Device Settings` page.
+
+Authentication is the same as in **Manual enrollment** case, and whether
+enrollment can be skipped depends on policy set by admins.
+
+### OEM-triggered Enrollment
+
+Device manufacturers can provide special [OEM manifest](https://cs.chromium.org/chromium/src/chromeos/system/statistics_provider.cc?rcl=2e366a611abdd2be6995e625f3281d40fab5b5e3&l=83)
+that controls if device should be enrolled, and if enrollment is forced.
+Authentication is the same as in **Manual enrollment** case.
+
+### Offline demo-mode enrollment
+
+This mode is intended for demo ChromeOS features e.g. in retail stores. This
+enrollment does not require network connection, it enrolls device to a fixed
+domain and uses policy from a local resource.
+
+Demo enrollment can be triggered during initial setup on welcome/network
+screens via `Ctrl+Alt+D` shortcut. No authentication is required during
+enrollment.
diff --git a/docs/enterprise/kiosk_public_session.md b/docs/enterprise/kiosk_public_session.md
index e10517f..5a038b5 100644
--- a/docs/enterprise/kiosk_public_session.md
+++ b/docs/enterprise/kiosk_public_session.md
@@ -1,6 +1,6 @@
-#Kiosk mode and public sessions (ChromeOS)
+#Kiosk mode and public sessions (Chrome OS)
 
-When ChromeOS device is enterprise enrolled, organization admins can add two
+When Chrome OS device is enterprise enrolled, organization admins can add two
 special types of users on the device. Those are Public sessions and Kiosk apps.
 
 ## Public sessions
diff --git a/docs/enterprise/management.md b/docs/enterprise/management.md
new file mode 100644
index 0000000..6203cf7
--- /dev/null
+++ b/docs/enterprise/management.md
@@ -0,0 +1,12 @@
+# Enterprise Management on Chrome OS
+
+Once enrolled, Chrome OS device can be managed by organization admins via
+https://admin.google.com/.
+
+Few notable management options are:
+
+`Kiosk settings` section on `Device Management>Chrome>Device Settings` page
+allows to configure [public sessions / Kiosk mode](kiosk_public_session.md).
+
+`Enrollment & Access` section on `Device Management>Chrome>Device Settings`
+page controls if device should be automatically re-enrolled after factory reset.
diff --git a/docs/login/enterprise_enrollment.md b/docs/login/enterprise_enrollment.md
deleted file mode 100644
index aeb8fb37..0000000
--- a/docs/login/enterprise_enrollment.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Enterprise Enrollment on Login
-
-The easiest way to test enterprise enrollment on login is to use an actual
-enterprise account. If you don't have one, reach out a teammate; anyone with an
-account can add new accounts.
-
-Once you have an enterprise account, run chrome and [enroll the device](https://support.google.com/chrome/a/answer/1360534?hl=en). The shortcut combo is
-`Ctrl+Alt+E`.
-
-Note, that you can only enroll device if it does not have owner (no user have
-signed in on the device, nor it was already enrolled). If device have an owner
-you would need to clear the ownership first. If you're testing on device and
-wish to clear enrollment state, the easiest way is to run
-`crossystem clear_tpm_owner_request=1` and then reboot. This clears
-TPM state which will destroy cryptohome and enrollment state. When the device
-boots next it will check and see if it needs to be force re-enrolled.
-
-Policy can be configured at admin.google.com; log in with your enterprise
-account. Whoever created the account should have granted you superuser
-privileges. You may need to log in using an incognito window if your primary
-Google account is part of an enterprise domain.
-
-Few notable policy sections in admin.google.com under
-`Device Management>Chrome>Device Settings` are `Enrollment & Access` that
-controls if device would be automatically re-enrolled after wipe and
-`Kiosk settings` that allows to configure public sessions / Kiosk mode for
-the ChromeOS device.
-
-When you're changing policies in admin.google.com, pay attention to the
-organization you are modifying. Try to only adjust your test organization to
-avoid propagating changes to other users.
\ No newline at end of file
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index 2e1d8f7..e904d61 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -244,7 +244,6 @@
   data = [
     "//extensions/test/data/",
     "//net/tools/testserver/",
-    "//third_party/pyftpdlib/",
     "//third_party/pywebsocket/src/mod_pywebsocket/",
     "//third_party/tlslite/",
     "$root_out_dir/extensions_shell_and_test.pak",
diff --git a/extensions/browser/api/diagnostics/diagnostics_api.cc b/extensions/browser/api/diagnostics/diagnostics_api.cc
index 668daa8..de23088 100644
--- a/extensions/browser/api/diagnostics/diagnostics_api.cc
+++ b/extensions/browser/api/diagnostics/diagnostics_api.cc
@@ -8,27 +8,15 @@
 
 const char kErrorPingNotImplemented[] = "Not implemented";
 const char kErrorPingFailed[] = "Failed to send ping packet";
-}
+
+}  // namespace
 
 namespace extensions {
 
 namespace SendPacket = api::diagnostics::SendPacket;
 
-DiagnosticsSendPacketFunction::DiagnosticsSendPacketFunction() {
-}
-
-DiagnosticsSendPacketFunction::~DiagnosticsSendPacketFunction() {
-}
-
-bool DiagnosticsSendPacketFunction::Prepare() {
-  parameters_ = SendPacket::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(parameters_.get());
-  return true;
-}
-
-bool DiagnosticsSendPacketFunction::Respond() {
-  return error_.empty();
-}
+DiagnosticsSendPacketFunction::DiagnosticsSendPacketFunction() = default;
+DiagnosticsSendPacketFunction::~DiagnosticsSendPacketFunction() = default;
 
 void DiagnosticsSendPacketFunction::OnCompleted(
     SendPacketResultCode result_code,
@@ -39,17 +27,16 @@
       api::diagnostics::SendPacketResult result;
       result.ip = ip;
       result.latency = latency;
-      results_ = SendPacket::Results::Create(result);
+      Respond(OneArgument(SendPacket::Results::Create(result)));
       break;
     }
     case SEND_PACKET_NOT_IMPLEMENTED:
-      SetError(kErrorPingNotImplemented);
+      Respond(Error(kErrorPingNotImplemented));
       break;
     case SEND_PACKET_FAILED:
-      SetError(kErrorPingFailed);
+      Respond(Error(kErrorPingFailed));
       break;
   }
-  AsyncWorkCompleted();
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/diagnostics/diagnostics_api.h b/extensions/browser/api/diagnostics/diagnostics_api.h
index 3aeecc5..604a335 100644
--- a/extensions/browser/api/diagnostics/diagnostics_api.h
+++ b/extensions/browser/api/diagnostics/diagnostics_api.h
@@ -8,12 +8,12 @@
 #include <memory>
 #include <string>
 
-#include "extensions/browser/api/async_api_function.h"
+#include "extensions/browser/extension_function.h"
 #include "extensions/common/api/diagnostics.h"
 
 namespace extensions {
 
-class DiagnosticsSendPacketFunction : public AsyncApiFunction {
+class DiagnosticsSendPacketFunction : public UIThreadExtensionFunction {
  public:
   // Result code for sending packet. Platform specific AsyncWorkStart() will
   // finish with this ResultCode so we can maximize shared code.
@@ -35,19 +35,13 @@
  protected:
   ~DiagnosticsSendPacketFunction() override;
 
-  // AsyncApiFunction:
-  bool Prepare() override;
-  // This methods will be implemented differently on different platforms.
-  void AsyncWorkStart() override;
-  bool Respond() override;
+  // UIThreadExtensionFunction:
+  ResponseAction Run() override;
 
  private:
-  void SendPingPacket();
   void OnCompleted(SendPacketResultCode result_code,
                    const std::string& ip,
                    double latency);
-
-  std::unique_ptr<api::diagnostics::SendPacket::Params> parameters_;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc b/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
index e9b213c..2fed6d12 100644
--- a/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
+++ b/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
@@ -66,23 +66,27 @@
 
 }  // namespace
 
-void DiagnosticsSendPacketFunction::AsyncWorkStart() {
+ExtensionFunction::ResponseAction DiagnosticsSendPacketFunction::Run() {
+  auto params = api::diagnostics::SendPacket::Params::Create(*args_);
+
   std::map<std::string, std::string> config;
   config[kCount] = kDefaultCount;
-  if (parameters_->options.ttl)
-    config[kTTL] = base::NumberToString(*parameters_->options.ttl);
-  if (parameters_->options.timeout)
-    config[kTimeout] = base::NumberToString(*parameters_->options.timeout);
-  if (parameters_->options.size)
-    config[kSize] = base::NumberToString(*parameters_->options.size);
+  if (params->options.ttl)
+    config[kTTL] = base::NumberToString(*params->options.ttl);
+  if (params->options.timeout)
+    config[kTimeout] = base::NumberToString(*params->options.timeout);
+  if (params->options.size)
+    config[kSize] = base::NumberToString(*params->options.size);
 
   chromeos::DBusThreadManager::Get()
       ->GetDebugDaemonClient()
       ->TestICMPWithOptions(
-          parameters_->options.ip, config,
+          params->options.ip, config,
           base::Bind(
               OnTestICMPCompleted,
               base::Bind(&DiagnosticsSendPacketFunction::OnCompleted, this)));
+
+  return RespondLater();
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/feedback_private/feedback_private_api.cc b/extensions/browser/api/feedback_private/feedback_private_api.cc
index e8befae..2ac1eff 100644
--- a/extensions/browser/api/feedback_private/feedback_private_api.cc
+++ b/extensions/browser/api/feedback_private/feedback_private_api.cc
@@ -19,10 +19,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/system/sys_info.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "components/feedback/feedback_report.h"
+#include "components/feedback/feedback_util.h"
 #include "components/feedback/system_logs/system_logs_fetcher.h"
 #include "components/feedback/tracing_manager.h"
 #include "extensions/browser/api/extensions_api_client.h"
@@ -61,11 +61,6 @@
 
 constexpr char kBluetoothLogsAttachmentName[] = "bluetooth_logs.bz2";
 
-bool IsGoogleEmail(const std::string& email) {
-  return base::EndsWith(email, "@google.com",
-                        base::CompareCase::INSENSITIVE_ASCII);
-}
-
 // Getting the filename of a blob prepends a "C:\fakepath" to the filename.
 // This is undesirable, strip it if it exists.
 std::string StripFakepath(const std::string& path) {
@@ -78,17 +73,12 @@
 
 // Returns the type of the landing page which is shown to the user when the
 // report is successfully sent.
-feedback_private::LandingPageType GetLandingPageType(const std::string& email) {
+feedback_private::LandingPageType GetLandingPageType(
+    const feedback::FeedbackData& feedback_data) {
 #if defined(OS_CHROMEOS)
-  const std::string board =
-      base::ToLowerASCII(base::SysInfo::GetLsbReleaseBoard());
-  if (board.find("eve") == std::string::npos)
-    return feedback_private::LANDING_PAGE_TYPE_NORMAL;
-
-  if (!IsGoogleEmail(email))
-    return feedback_private::LANDING_PAGE_TYPE_NORMAL;
-
-  return feedback_private::LANDING_PAGE_TYPE_TECHSTOP;
+  return ExtensionsAPIClient::Get()
+      ->GetFeedbackPrivateDelegate()
+      ->GetLandingPageType(feedback_data);
 #else
   return feedback_private::LANDING_PAGE_TYPE_NORMAL;
 #endif  // defined(OS_CHROMEOS)
@@ -231,10 +221,10 @@
   SystemInformationList sys_info_list;
   if (sys_info) {
     sys_info_list.reserve(sys_info->size());
-    const bool google_email =
-        IsGoogleEmail(ExtensionsAPIClient::Get()
-                          ->GetFeedbackPrivateDelegate()
-                          ->GetSignedInUserEmail(browser_context()));
+    const bool google_email = feedback_util::IsGoogleEmail(
+        ExtensionsAPIClient::Get()
+            ->GetFeedbackPrivateDelegate()
+            ->GetSignedInUserEmail(browser_context()));
     for (auto& itr : *sys_info) {
       // We only send the list of all the crash report IDs if the user has a
       // @google.com email. We strip this here so that the system information
@@ -391,7 +381,7 @@
   service->SendFeedback(
       feedback_data,
       base::Bind(&FeedbackPrivateSendFeedbackFunction::OnCompleted, this,
-                 GetLandingPageType(feedback_data->user_email())));
+                 GetLandingPageType(*feedback_data)));
 }
 
 void FeedbackPrivateSendFeedbackFunction::OnCompleted(
diff --git a/extensions/browser/api/feedback_private/feedback_private_delegate.h b/extensions/browser/api/feedback_private/feedback_private_delegate.h
index 8435071..cdd67b1 100644
--- a/extensions/browser/api/feedback_private/feedback_private_delegate.h
+++ b/extensions/browser/api/feedback_private/feedback_private_delegate.h
@@ -69,6 +69,11 @@
   // called when feedback is complete for the login profile.
   virtual void UnloadFeedbackExtension(
       content::BrowserContext* context) const = 0;
+
+  // Returns the type of the landing page which is shown to the user when the
+  // report is successfully sent.
+  virtual api::feedback_private::LandingPageType GetLandingPageType(
+      const feedback::FeedbackData& feedback_data) const = 0;
 #endif
 
   // Returns the normalized email address of the signed-in user associated with
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
index b4332ad..355d584 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/mime_handler_view_mode.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_renderer_host.h"
 #include "extensions/browser/api/extensions_api_client.h"
@@ -525,6 +526,11 @@
 // the embedder knows about it.
 IN_PROC_BROWSER_TEST_F(MimeHandlerViewBrowserPluginSpecificTest,
                        AcceptTouchEvents) {
+  if (content::MimeHandlerViewMode::UsesCrossProcessFrame()) {
+    // This test requires BrowserPlugin which does not exist in frame-based
+    // MimeHandlerView.
+    return;
+  }
   RunTest("testBasic.csv");
   content::RenderViewHost* embedder_rvh =
       GetEmbedderWebContents()->GetRenderViewHost();
@@ -559,6 +565,11 @@
 // Verify that a BrowserPlugin captures mouse input on MouseDown.
 IN_PROC_BROWSER_TEST_F(MimeHandlerViewBrowserPluginSpecificTest,
                        MouseCaptureOnMouseDown) {
+  if (content::MimeHandlerViewMode::UsesCrossProcessFrame()) {
+    // This test requires BrowserPlugin which does not exist in frame-based
+    // MimeHandlerView.
+    return;
+  }
   RunTest("testBasic.csv");
   auto* guest_web_contents = GetGuestViewManager()->WaitForSingleGuestCreated();
   auto* guest_widget = MimeHandlerViewGuest::FromWebContents(guest_web_contents)
diff --git a/extensions/common/api/feedback_private.idl b/extensions/common/api/feedback_private.idl
index 4585ed73..bc131b8 100644
--- a/extensions/common/api/feedback_private.idl
+++ b/extensions/common/api/feedback_private.idl
@@ -99,8 +99,8 @@
   enum Status {success, delayed};
 
   // The type of the landing page shown to the user when the feedback report is
-  // successfully sent.
-  enum LandingPageType {normal, techstop};
+  // successfully sent, if one should be shown.
+  enum LandingPageType {normal, techstop, noLandingPage};
 
   // Allowed log sources on Chrome OS.
   enum LogSource {
diff --git a/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc b/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc
index 6ff3ef1a..39b30f2 100644
--- a/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc
+++ b/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.cc
@@ -52,6 +52,12 @@
     content::BrowserContext* context) const {
   NOTIMPLEMENTED();
 }
+
+api::feedback_private::LandingPageType
+ShellFeedbackPrivateDelegate::GetLandingPageType(
+    const feedback::FeedbackData& feedback_data) const {
+  return api::feedback_private::LANDING_PAGE_TYPE_NOLANDINGPAGE;
+}
 #endif
 
 std::string ShellFeedbackPrivateDelegate::GetSignedInUserEmail(
diff --git a/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.h b/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.h
index 448f9c0fb..99d68d9 100644
--- a/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.h
+++ b/extensions/shell/browser/api/feedback_private/shell_feedback_private_delegate.h
@@ -29,6 +29,8 @@
   void FetchExtraLogs(scoped_refptr<feedback::FeedbackData> feedback_data,
                       FetchExtraLogsCallback callback) const override;
   void UnloadFeedbackExtension(content::BrowserContext* context) const override;
+  api::feedback_private::LandingPageType GetLandingPageType(
+      const feedback::FeedbackData& feedback_data) const override;
 #endif  // defined(OS_CHROMEOS)
   std::string GetSignedInUserEmail(
       content::BrowserContext* context) const override;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index bc72d26..ed29f683 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -28,6 +28,7 @@
 #include "base/containers/span.h"
 #include "base/debug/alias.h"
 #include "base/debug/dump_without_crashing.h"
+#include "base/hash/hash.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/ranges.h"
@@ -87,7 +88,6 @@
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "gpu/config/gpu_preferences.h"
 #include "third_party/angle/src/image_util/loadimage.h"
-#include "third_party/smhasher/src/City.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/point.h"
@@ -4449,7 +4449,10 @@
   if (((shader_spec == SH_WEBGL_SPEC || shader_spec == SH_WEBGL2_SPEC) &&
        features().enable_shader_name_hashing) ||
       force_shader_name_hashing_for_test)
-    resources.HashFunction = &CityHash64;
+    resources.HashFunction = [](const char* data, size_t length) {
+      return static_cast<uint64_t>(
+          base::FastHash(base::as_bytes(base::make_span(data, length))));
+    };
   else
     resources.HashFunction = nullptr;
 
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index e870907..d127356c2 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -731,7 +731,6 @@
     "$root_out_dir/headless_lib.pak",
     "//net/tools/testserver/",
     "//third_party/blink/web_tests/http/tests/inspector-protocol/",
-    "//third_party/pyftpdlib/",
     "//third_party/pywebsocket/",
     "//third_party/tlslite/",
     "test/data/",
diff --git a/ios/chrome/browser/infobars/BUILD.gn b/ios/chrome/browser/infobars/BUILD.gn
index d58902f..78fd90d 100644
--- a/ios/chrome/browser/infobars/BUILD.gn
+++ b/ios/chrome/browser/infobars/BUILD.gn
@@ -43,6 +43,7 @@
   ]
   deps = [
     ":infobars",
+    ":public",
     "//ios/chrome/browser/ui/infobars:feature_flags",
     "//ios/chrome/browser/ui/infobars:infobars_ui",
     "//ios/web",
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.h b/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
index 811ef92..d12c8d4 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.h
@@ -9,6 +9,7 @@
 #import "ios/web/public/web_state/web_state_user_data.h"
 
 #include "components/infobars/core/infobar_manager.h"
+#import "ios/chrome/browser/infobars/infobar_type.h"
 
 namespace web {
 class WebState;
@@ -37,7 +38,10 @@
 
   // Returns wheter an Infobar badge is being displayed for the TabHelper
   // Webstate.
-  bool IsInfobarBadgeDisplaying();
+  bool is_infobar_displaying();
+  // Returns the type of the Infobar being displayed.
+  InfobarType infobar_type();
+
   ~InfobarBadgeTabHelper() override;
 
  private:
@@ -58,6 +62,8 @@
   __weak id<InfobarBadgeTabHelperDelegate> delegate_ = nil;
   // Returns wheter an Infobar is being displayed.
   bool is_infobar_displaying_;
+  // The type of the Infobar being displayed.
+  InfobarType infobar_type_;
 
   WEB_STATE_USER_DATA_KEY_DECL();
   DISALLOW_COPY_AND_ASSIGN(InfobarBadgeTabHelper);
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
index fd997bc..383390b 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper.mm
@@ -47,10 +47,14 @@
   delegate_.badgeState |= InfobarBadgeStateAccepted;
 }
 
-bool InfobarBadgeTabHelper::IsInfobarBadgeDisplaying() {
+bool InfobarBadgeTabHelper::is_infobar_displaying() {
   return is_infobar_displaying_;
 }
 
+InfobarType InfobarBadgeTabHelper::infobar_type() {
+  return infobar_type_;
+}
+
 InfobarBadgeTabHelper::~InfobarBadgeTabHelper() = default;
 
 #pragma mark - Private
@@ -87,11 +91,12 @@
 
 void InfobarBadgeTabHelper::UpdateBadgeForInfobar(infobars::InfoBar* infobar,
                                                   bool display) {
-  is_infobar_displaying_ = display;
   InfoBarIOS* infobar_ios = static_cast<InfoBarIOS*>(infobar);
   id<InfobarUIDelegate> controller_ = infobar_ios->InfobarUIDelegate();
   if (IsInfobarUIRebootEnabled() && [controller_ isPresented]) {
-    [delegate_ displayBadge:display];
+    is_infobar_displaying_ = display;
+    infobar_type_ = controller_.infobarType;
+    [delegate_ displayBadge:display type:infobar_type_];
   }
 }
 
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper_delegate.h b/ios/chrome/browser/infobars/infobar_badge_tab_helper_delegate.h
index aa886b12..f3a28f36 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper_delegate.h
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper_delegate.h
@@ -7,6 +7,8 @@
 
 #import <Foundation/Foundation.h>
 
+#import "ios/chrome/browser/infobars/infobar_type.h"
+
 // States for the InfobarBadge.
 typedef NS_OPTIONS(NSUInteger, InfobarBadgeState) {
   // Default state. e.g. the Banner is being displayed or there's nothing
@@ -24,7 +26,7 @@
 @protocol InfobarBadgeTabHelperDelegate
 
 // Asks the delegate to display or stop displaying a badge.
-- (void)displayBadge:(BOOL)display;
+- (void)displayBadge:(BOOL)display type:(InfobarType)infobarType;
 
 // Current state for the displayed InfobarBadge.
 @property(nonatomic, assign) InfobarBadgeState badgeState;
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
index b70f568..3f2f3369 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
@@ -32,12 +32,14 @@
 @interface InfobarBadgeTabHelperTestDelegate
     : NSObject <InfobarBadgeTabHelperDelegate>
 @property(nonatomic, assign) BOOL displayingBadge;
+@property(nonatomic, assign) InfobarType infobarType;
 @end
 
 @implementation InfobarBadgeTabHelperTestDelegate
 @synthesize badgeState = _badgeState;
-- (void)displayBadge:(BOOL)display {
+- (void)displayBadge:(BOOL)display type:(InfobarType)infobarType {
   self.displayingBadge = display;
+  self.infobarType = infobarType;
 }
 @end
 
@@ -153,7 +155,7 @@
         new TestInfoBarDelegate(@"Title");
     InfobarConfirmCoordinator* coordinator = [[InfobarConfirmCoordinator alloc]
         initWithInfoBarDelegate:test_infobar_delegate
-                           type:InfobarType::kInfobarTypeConfirm];
+                           type:InfobarType::kInfobarTypePasswordSave];
     coordinator.browserState = browser_state_.get();
     coordinator.badgeDelegate = infobar_badge_ui_delegate_;
 
@@ -244,6 +246,12 @@
   EXPECT_FALSE(infobar_badge_tab_delegate_.badgeState);
 }
 
+// Test that the correct InfobarType is set.
+TEST_F(InfobarBadgeTabHelperTest, TestInfobarBadgeType) {
+  EXPECT_EQ(infobar_badge_tab_delegate_.infobarType,
+            InfobarType::kInfobarTypePasswordSave);
+}
+
 // Tests that once the Modal is presented the default state is
 // InfobarBadgeStateSelected.
 TEST_F(InfobarBadgeTabHelperTest, TestInfobarBadgeStateOnModalPresentation) {
diff --git a/ios/chrome/browser/signin/ios_chrome_signin_client.h b/ios/chrome/browser/signin/ios_chrome_signin_client.h
index d358d63..ddb9fd0 100644
--- a/ios/chrome/browser/signin/ios_chrome_signin_client.h
+++ b/ios/chrome/browser/signin/ios_chrome_signin_client.h
@@ -45,6 +45,7 @@
   void DoFinalInit() override;
   bool IsFirstRun() const override;
   bool AreSigninCookiesAllowed() override;
+  bool AreSigninCookiesDeletedOnExit() override;
   void AddContentSettingsObserver(
       content_settings::Observer* observer) override;
   void RemoveContentSettingsObserver(
diff --git a/ios/chrome/browser/signin/ios_chrome_signin_client.mm b/ios/chrome/browser/signin/ios_chrome_signin_client.mm
index 452259d1..f9900765 100644
--- a/ios/chrome/browser/signin/ios_chrome_signin_client.mm
+++ b/ios/chrome/browser/signin/ios_chrome_signin_client.mm
@@ -75,6 +75,10 @@
   return signin::SettingsAllowSigninCookies(cookie_settings_.get());
 }
 
+bool IOSChromeSigninClient::AreSigninCookiesDeletedOnExit() {
+  return signin::SettingsDeleteSigninCookiesOnExit(cookie_settings_.get());
+}
+
 void IOSChromeSigninClient::AddContentSettingsObserver(
     content_settings::Observer* observer) {
   host_content_settings_map_->AddObserver(observer);
diff --git a/ios/chrome/browser/ui/alert_view_controller/BUILD.gn b/ios/chrome/browser/ui/alert_view_controller/BUILD.gn
index 7b3acef..6501e6c 100644
--- a/ios/chrome/browser/ui/alert_view_controller/BUILD.gn
+++ b/ios/chrome/browser/ui/alert_view_controller/BUILD.gn
@@ -9,10 +9,13 @@
     "alert_consumer.h",
     "alert_view_controller.h",
     "alert_view_controller.mm",
+    "non_modal_view_controller_presenter.h",
+    "non_modal_view_controller_presenter.mm",
   ]
   deps = [
     "//base",
     "//ios/chrome/browser/ui/elements",
+    "//ios/chrome/browser/ui/presenters",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui_util",
   ]
diff --git a/ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.h b/ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.h
new file mode 100644
index 0000000..32d4053
--- /dev/null
+++ b/ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.h
@@ -0,0 +1,19 @@
+// 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 IOS_CHROME_BROWSER_UI_ALERT_VIEW_CONTROLLER_NON_MODAL_VIEW_CONTROLLER_PRESENTER_H_
+#define IOS_CHROME_BROWSER_UI_ALERT_VIEW_CONTROLLER_NON_MODAL_VIEW_CONTROLLER_PRESENTER_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/ui/presenters/contained_presenter.h"
+
+// Presents a view controller above the base view controller in a non modal
+// style. Allowing any interaction outside the presented view controller. The
+// animation in is a fade in and scale down, while the animation out is just a
+// fade out.
+@interface NonModalViewControllerPresenter : NSObject <ContainedPresenter>
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_ALERT_VIEW_CONTROLLER_NON_MODAL_VIEW_CONTROLLER_PRESENTER_H_
diff --git a/ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.mm b/ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.mm
new file mode 100644
index 0000000..1ff2ad3
--- /dev/null
+++ b/ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.mm
@@ -0,0 +1,102 @@
+// 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.
+
+#import "ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.h"
+
+#include "base/logging.h"
+#import "ios/chrome/browser/ui/presenters/contained_presenter_delegate.h"
+#import "ios/chrome/common/ui_util/constraints_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+constexpr CGFloat kAnimationInDuration = 0.15;
+constexpr CGFloat kAnimationInScale = 1.3;
+constexpr CGFloat kAnimationOutDuration = 0.1;
+}  // namespace
+
+@interface NonModalViewControllerPresenter ()
+
+// The container for the presentation.
+@property(nonatomic, strong, readwrite) UIView* containerView;
+
+// The presenter animator, so if dismiss happens while presenting, it is smooth.
+@property(nonatomic, strong, readwrite) UIViewPropertyAnimator* animator;
+
+@end
+
+@implementation NonModalViewControllerPresenter
+
+@synthesize baseViewController, presentedViewController, delegate;
+
+- (void)prepareForPresentation {
+  DCHECK(self.baseViewController);
+  DCHECK(self.presentedViewController);
+
+  // Add child view controller.
+  [self.baseViewController addChildViewController:self.presentedViewController];
+
+  // Prepare the container view.
+  self.containerView =
+      [[UIView alloc] initWithFrame:self.baseViewController.view.bounds];
+  self.containerView.alpha = 0.0;
+  self.containerView.transform = CGAffineTransformScale(
+      CGAffineTransformIdentity, kAnimationInScale, kAnimationInScale);
+
+  // Add the presented view in the container.
+  self.presentedViewController.view.translatesAutoresizingMaskIntoConstraints =
+      NO;
+  [self.containerView addSubview:self.presentedViewController.view];
+  AddSameConstraints(self.presentedViewController.view, self.containerView);
+
+  // Add the container to the presenting view controller.
+  self.containerView.translatesAutoresizingMaskIntoConstraints = NO;
+  [self.baseViewController.view addSubview:self.containerView];
+  AddSameConstraints(self.containerView, self.baseViewController.view);
+}
+
+- (void)presentAnimated:(BOOL)animated {
+  DCHECK(!self.animator) << "Presenting again is not supported.";
+  __weak __typeof(self) weakSelf = self;
+  self.animator = [[UIViewPropertyAnimator alloc]
+      initWithDuration:animated ? kAnimationInDuration : 0
+                 curve:UIViewAnimationCurveEaseOut
+            animations:^{
+              weakSelf.containerView.alpha = 1.0;
+              weakSelf.containerView.transform = CGAffineTransformIdentity;
+            }];
+  [self.animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+    [weakSelf.presentedViewController
+        didMoveToParentViewController:weakSelf.baseViewController];
+    [weakSelf.delegate containedPresenterDidPresent:weakSelf];
+  }];
+  [self.animator startAnimation];
+}
+
+- (void)dismissAnimated:(BOOL)animated {
+  if (self.animator.state == UIViewAnimatingStateActive) {
+    [self.animator stopAnimation:YES];
+  }
+
+  [self.presentedViewController willMoveToParentViewController:nil];
+
+  __weak __typeof(self) weakSelf = self;
+  UIViewPropertyAnimator* dismissAnimator = [[UIViewPropertyAnimator alloc]
+      initWithDuration:animated ? kAnimationOutDuration : 0
+                 curve:UIViewAnimationCurveEaseOut
+            animations:^{
+              weakSelf.containerView.alpha = 0.0;
+            }];
+  [dismissAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+    [weakSelf.presentedViewController.view removeFromSuperview];
+    [weakSelf.presentedViewController removeFromParentViewController];
+    [weakSelf.containerView removeFromSuperview];
+    [weakSelf.delegate containedPresenterDidDismiss:weakSelf];
+  }];
+  [dismissAnimator startAnimation];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index fdf67818..0e357ae 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -39,6 +39,7 @@
     "//ios/chrome/browser/browser_state:browser_state",
     "//ios/chrome/browser/geolocation:geolocation_internal",
     "//ios/chrome/browser/infobars:badge",
+    "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/ntp",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/ssl",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_consumer.h b/ios/chrome/browser/ui/location_bar/location_bar_consumer.h
index d206951..44af363 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_consumer.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_consumer.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_CONSUMER_H_
 #define IOS_CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_CONSUMER_H_
 
+#import "ios/chrome/browser/infobars/infobar_type.h"
+
 // Consumer for the location bar mediator.
 @protocol LocationBarConsumer
 
@@ -33,7 +35,7 @@
 // Notifies the consumer to display or hide the Infobar badge.
 // TODO(crbug.com/935804): This method is currently only being used in the
 // Infobar redesign.
-- (void)displayInfobarBadge:(BOOL)display;
+- (void)displayInfobarBadge:(BOOL)display type:(InfobarType)infobarType;
 
 // Notifies the consumer that the InfobarBadge select state has changed.
 // TODO(crbug.com/935804): This method is currently only being used in the
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 7adf81c..f3648c3 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -18,6 +18,7 @@
 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
+#include "ios/chrome/browser/infobars/infobar_metrics_recorder.h"
 #import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/chrome/browser/ui/commands/browser_commands.h"
@@ -381,8 +382,15 @@
   self.viewController.searchByImageEnabled = searchByImageSupported;
 }
 
-- (void)displayInfobarBadge:(BOOL)display {
-  [self.viewController displayInfobarButton:display];
+- (void)displayInfobarBadge:(BOOL)display type:(InfobarType)infobarType {
+  InfobarMetricsRecorder* metricsRecorder;
+  // If the Badge will be displayed create a metrics recorder to log its
+  // interactions, if its hidden metrics recorder should be nil.
+  if (display)
+    metricsRecorder = [[InfobarMetricsRecorder alloc] initWithType:infobarType];
+
+  [self.viewController displayInfobarButton:display
+                            metricsRecorder:metricsRecorder];
 }
 
 - (void)selectInfobarBadge:(BOOL)select {
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
index b635290..cc07e15 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
@@ -161,9 +161,9 @@
 
 #pragma mark - InfobarBadgeTabHelper
 
-- (void)displayBadge:(BOOL)display {
+- (void)displayBadge:(BOOL)display type:(InfobarType)infobarType {
   DCHECK(IsInfobarUIRebootEnabled());
-  [self.consumer displayInfobarBadge:display];
+  [self.consumer displayInfobarBadge:display type:infobarType];
 }
 
 - (void)setBadgeState:(InfobarBadgeState)badgeState {
@@ -192,8 +192,9 @@
       if (self.consumer) {
         // Whenever the WebState changes ask the corresponding
         // InfobarBadgeTabHelper if a badge should be displayed.
-        [self.consumer displayInfobarBadge:infobarBadgeTabHelper
-                                               ->IsInfobarBadgeDisplaying()];
+        [self.consumer
+            displayInfobarBadge:infobarBadgeTabHelper->is_infobar_displaying()
+                           type:infobarBadgeTabHelper->infobar_type()];
       }
     }
 
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
index 01f09556..f41ef47a 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/ui/location_bar/location_bar_consumer.h"
 #import "ios/chrome/browser/ui/orchestrator/location_bar_animatee.h"
 
+@class InfobarMetricsRecorder;
 @class OmniboxTextFieldIOS;
 @protocol ActivityServiceCommands;
 @protocol ApplicationCommands;
@@ -73,10 +74,11 @@
 - (void)updateForNTP:(BOOL)isNTP;
 // Sets |enabled| of the share button.
 - (void)setShareButtonEnabled:(BOOL)enabled;
-// Displays or hides the InfobarButton.
+// Displays or hides the InfobarButton. |metricsRecorder| can be nil.
 // TODO(crbug.com/935804): This method is currently only being used in the
 // Infobar redesign.
-- (void)displayInfobarButton:(BOOL)display;
+- (void)displayInfobarButton:(BOOL)display
+             metricsRecorder:(InfobarMetricsRecorder*)metricsRecorder;
 // If |selected| is YES applies the selected styling to the InfobarButton, if NO
 // it removes it.
 // TODO(crbug.com/935804): This method is currently only being used in the
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
index a02c779..e21c90a 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
@@ -10,6 +10,7 @@
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/open_from_clipboard/clipboard_recent_content.h"
 #include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/infobars/infobar_metrics_recorder.h"
 #import "ios/chrome/browser/ui/commands/activity_service_commands.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
@@ -63,6 +64,9 @@
 // to preserve leading button visibility during animations.
 @property(nonatomic, assign) BOOL shouldShowLeadingButton;
 
+// Used to build and record Infobar metrics.
+@property(nonatomic, strong) InfobarMetricsRecorder* infobarMetricsRecorder;
+
 // Starts voice search, updating the NamedGuide to be constrained to the
 // trailing button.
 - (void)startVoiceSearch;
@@ -252,7 +256,9 @@
   }
 }
 
-- (void)displayInfobarButton:(BOOL)display {
+- (void)displayInfobarButton:(BOOL)display
+             metricsRecorder:(InfobarMetricsRecorder*)metricsRecorder {
+  self.infobarMetricsRecorder = metricsRecorder;
   self.shouldShowLeadingButton = display;
   [self.locationBarSteadyView.leadingButton displayBadge:display animated:YES];
 }
diff --git a/ios/chrome/browser/ui/settings/cells/search_engine_item.mm b/ios/chrome/browser/ui/settings/cells/search_engine_item.mm
index dabaa8b..b7fbc8e7 100644
--- a/ios/chrome/browser/ui/settings/cells/search_engine_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/search_engine_item.mm
@@ -6,6 +6,7 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_detail_text_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
@@ -63,6 +64,8 @@
     if (styler.cellTitleColor)
       cell.titleLabel.textColor = styler.cellTitleColor;
 
+    cell.URLLabel.textColor = UIColorFromRGB(kSettingsCellsURLTextColor);
+
     [cell configureUILayout];
   } else {
     TableViewDetailTextCell* cell =
diff --git a/ios/chrome/browser/ui/settings/cells/settings_cells_constants.h b/ios/chrome/browser/ui/settings/cells/settings_cells_constants.h
index 2af94bc..2af8843 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_cells_constants.h
+++ b/ios/chrome/browser/ui/settings/cells/settings_cells_constants.h
@@ -10,6 +10,9 @@
 // The color of the detail text for the settings cells.
 extern const int kSettingsCellsDetailTextColor;
 
+// The color of the URL text for the settings cells.
+extern const int kSettingsCellsURLTextColor;
+
 // Default height for the settings cells.
 extern const CGFloat kSettingsCellDefaultHeight;
 
diff --git a/ios/chrome/browser/ui/settings/cells/settings_cells_constants.mm b/ios/chrome/browser/ui/settings/cells/settings_cells_constants.mm
index 441374c..8aaef5a 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_cells_constants.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_cells_constants.mm
@@ -9,5 +9,6 @@
 #endif
 
 const int kSettingsCellsDetailTextColor = 0x767676;
+const int kSettingsCellsURLTextColor = 0x5F6368;
 
 const CGFloat kSettingsCellDefaultHeight = 70;
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h
index 4fb670a..6c20c49 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -11,6 +11,7 @@
 
 #include "base/compiler_specific.h"
 #import "components/content_settings/core/common/content_settings.h"
+#import "ios/testing/earl_grey/base_eg_test_helper_impl.h"
 #include "url/gurl.h"
 
 @class ElementSelector;
@@ -28,14 +29,17 @@
 
 }  // namespace chrome_test_util
 
+#define ChromeEarlGrey \
+  [ChromeEarlGreyImpl invokedFromFile:@"" __FILE__ lineNumber:__LINE__]
+
 // Test methods that perform actions on Chrome. These methods may read or alter
 // Chrome's internal state programmatically or via the UI, but in both cases
 // will properly synchronize the UI for Earl Grey tests.
-@interface ChromeEarlGrey : NSObject
+@interface ChromeEarlGreyImpl : BaseEGTestHelperImpl
 
 #pragma mark - History Utilities
 // Clears browsing history.
-+ (NSError*)clearBrowsingHistory WARN_UNUSED_RESULT;
+- (NSError*)clearBrowsingHistory WARN_UNUSED_RESULT;
 
 @end
 
@@ -43,128 +47,128 @@
 // category.
 // TODO(crbug.com/922813): Update these helpers to compile under EG2 and move
 // them into the main class declaration as they are converted.
-@interface ChromeEarlGrey (EG1)
+@interface ChromeEarlGreyImpl (EG1)
 
 #pragma mark - Cookie Utilities
 
 // Returns cookies as key value pairs, where key is a cookie name and value is a
 // cookie value.
 // NOTE: this method fails the test if there are errors getting cookies.
-+ (NSDictionary*)cookies;
+- (NSDictionary*)cookies;
 
 #pragma mark - Navigation Utilities
 
 // Loads |URL| in the current WebState with transition type
 // ui::PAGE_TRANSITION_TYPED, and waits for the loading to complete within a
 // timeout, or a GREYAssert is induced.
-+ (NSError*)loadURL:(const GURL&)URL WARN_UNUSED_RESULT;
+- (NSError*)loadURL:(const GURL&)URL WARN_UNUSED_RESULT;
 
 // Reloads the page and waits for the loading to complete within a timeout, or a
 // GREYAssert is induced.
-+ (NSError*)reload WARN_UNUSED_RESULT;
+- (NSError*)reload WARN_UNUSED_RESULT;
 
 // Navigates back to the previous page and waits for the loading to complete
 // within a timeout, or a GREYAssert is induced.
-+ (NSError*)goBack WARN_UNUSED_RESULT;
+- (NSError*)goBack WARN_UNUSED_RESULT;
 
 // Navigates forward to the next page and waits for the loading to complete
 // within a timeout, or a GREYAssert is induced.
-+ (NSError*)goForward WARN_UNUSED_RESULT;
+- (NSError*)goForward WARN_UNUSED_RESULT;
 
 // Opens a new tab and waits for the new tab animation to complete.
-+ (NSError*)openNewTab WARN_UNUSED_RESULT;
+- (NSError*)openNewTab WARN_UNUSED_RESULT;
 
 // Opens a new incognito tab and waits for the new tab animation to complete.
-+ (NSError*)openNewIncognitoTab WARN_UNUSED_RESULT;
+- (NSError*)openNewIncognitoTab WARN_UNUSED_RESULT;
 
 // Closes all tabs in the current mode (incognito or normal), and waits for the
 // UI to complete. If current mode is Incognito, mode will be switched to
 // normal after closing all tabs.
-+ (void)closeAllTabsInCurrentMode;
+- (void)closeAllTabsInCurrentMode;
 
 // Closes all incognito tabs and waits for the UI to complete.
-+ (NSError*)closeAllIncognitoTabs WARN_UNUSED_RESULT;
+- (NSError*)closeAllIncognitoTabs WARN_UNUSED_RESULT;
 
 // Closes the current tab and waits for the UI to complete.
-+ (void)closeCurrentTab;
+- (void)closeCurrentTab;
 
 // Waits for the page to finish loading within a timeout, or a GREYAssert is
 // induced.
-+ (NSError*)waitForPageToFinishLoading WARN_UNUSED_RESULT;
+- (NSError*)waitForPageToFinishLoading WARN_UNUSED_RESULT;
 
 // Taps html element with |elementID| in the current web view.
-+ (NSError*)tapWebViewElementWithID:(NSString*)elementID WARN_UNUSED_RESULT;
+- (NSError*)tapWebViewElementWithID:(NSString*)elementID WARN_UNUSED_RESULT;
 
 // Waits for a static html view containing |text|. If the condition is not met
 // within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForStaticHTMLViewContainingText:(NSString*)text
+- (NSError*)waitForStaticHTMLViewContainingText:(NSString*)text
     WARN_UNUSED_RESULT;
 
 // Waits for there to be no static html view, or a static html view that does
 // not contain |text|. If the condition is not met within a timeout, a
 // GREYAssert is induced.
-+ (NSError*)waitForStaticHTMLViewNotContainingText:(NSString*)text
+- (NSError*)waitForStaticHTMLViewNotContainingText:(NSString*)text
     WARN_UNUSED_RESULT;
 
 // Waits for a Chrome error page. If it is not found within a timeout, a
 // GREYAssert is induced.
-+ (NSError*)waitForErrorPage WARN_UNUSED_RESULT;
+- (NSError*)waitForErrorPage WARN_UNUSED_RESULT;
 
 // Waits for the current web view to contain |text|. If the condition is not met
 // within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForWebViewContainingText:(std::string)text WARN_UNUSED_RESULT;
+- (NSError*)waitForWebViewContainingText:(std::string)text WARN_UNUSED_RESULT;
 
 // Waits for the current web view to contain an element matching |selector|.
 // If the condition is not met within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForWebViewContainingElement:(ElementSelector*)selector
+- (NSError*)waitForWebViewContainingElement:(ElementSelector*)selector
     WARN_UNUSED_RESULT;
 
 // Waits for there to be no web view containing |text|. If the condition is not
 // met within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForWebViewNotContainingText:(std::string)text
+- (NSError*)waitForWebViewNotContainingText:(std::string)text
     WARN_UNUSED_RESULT;
 
 // Waits for there to be |count| number of non-incognito tabs. If the condition
 // is not met within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForMainTabCount:(NSUInteger)count WARN_UNUSED_RESULT;
+- (NSError*)waitForMainTabCount:(NSUInteger)count WARN_UNUSED_RESULT;
 
 // Waits for there to be |count| number of incognito tabs. If the condition is
 // not met within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForIncognitoTabCount:(NSUInteger)count WARN_UNUSED_RESULT;
+- (NSError*)waitForIncognitoTabCount:(NSUInteger)count WARN_UNUSED_RESULT;
 
 // Waits for there to be a web view containing a blocked |image_id|.  When
 // blocked, the image element will be smaller than the actual image size.
-+ (NSError*)waitForWebViewContainingBlockedImageElementWithID:
+- (NSError*)waitForWebViewContainingBlockedImageElementWithID:
     (std::string)imageID WARN_UNUSED_RESULT;
 
 // Waits for there to be a web view containing loaded image with |image_id|.
 // When loaded, the image element will have the same size as actual image.
-+ (NSError*)waitForWebViewContainingLoadedImageElementWithID:
+- (NSError*)waitForWebViewContainingLoadedImageElementWithID:
     (std::string)imageID WARN_UNUSED_RESULT;
 
 // Waits for the bookmark internal state to be done loading. If it does not
 // happen within a timeout, a GREYAssert is induced.
-+ (NSError*)waitForBookmarksToFinishLoading WARN_UNUSED_RESULT;
+- (NSError*)waitForBookmarksToFinishLoading WARN_UNUSED_RESULT;
 
 // Clears bookmarks and if any bookmark still presents. Returns nil on success,
 // or else an NSError indicating why the operation failed.
-+ (NSError*)clearBookmarks;
+- (NSError*)clearBookmarks;
 
 // Waits for the matcher to return an element that is sufficiently visible.
-+ (NSError*)waitForElementWithMatcherSufficientlyVisible:
+- (NSError*)waitForElementWithMatcherSufficientlyVisible:
     (id<GREYMatcher>)matcher WARN_UNUSED_RESULT;
 
 #pragma mark - Settings Utilities
 
 // Sets value for content setting.
-+ (NSError*)setContentSettings:(ContentSetting)setting WARN_UNUSED_RESULT;
+- (NSError*)setContentSettings:(ContentSetting)setting WARN_UNUSED_RESULT;
 
 #pragma mark - Sign Utilities
 
 // Signs the user out, clears the known accounts entirely and checks whether
 // the accounts were correctly removed from the keychain. Returns nil on
 // success, or else an NSError indicating why the operation failed.
-+ (NSError*)signOutAndClearAccounts WARN_UNUSED_RESULT;
+- (NSError*)signOutAndClearAccounts WARN_UNUSED_RESULT;
 
 @end
 
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index d8f2585..8ee6d3c5 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -49,11 +49,11 @@
 GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(ChromeEarlGreyAppInterface)
 #endif  // defined(CHROME_EARL_GREY_2)
 
-@implementation ChromeEarlGrey
+@implementation ChromeEarlGreyImpl
 
 #pragma mark - History Utilities
 
-+ (NSError*)clearBrowsingHistory {
+- (NSError*)clearBrowsingHistory {
   NSError* error = [ChromeEarlGreyAppInterface clearBrowsingHistory];
 
   // After clearing browsing history via code, wait for the UI to be done
@@ -100,11 +100,11 @@
 
 }  // namespace chrome_test_util
 
-@implementation ChromeEarlGrey (EG1)
+@implementation ChromeEarlGreyImpl (EG1)
 
 #pragma mark - Cookie Utilities
 
-+ (NSDictionary*)cookies {
+- (NSDictionary*)cookies {
   NSString* const kGetCookiesScript =
       @"document.cookie ? document.cookie.split(/;\\s*/) : [];";
 
@@ -129,7 +129,7 @@
 
 #pragma mark - Navigation Utilities
 
-+ (NSError*)loadURL:(const GURL&)URL {
+- (NSError*)loadURL:(const GURL&)URL {
   chrome_test_util::LoadUrl(URL);
   NSError* loadingError = [ChromeEarlGrey waitForPageToFinishLoading];
   if (loadingError) {
@@ -147,24 +147,24 @@
   return nil;
 }
 
-+ (NSError*)reload {
+- (NSError*)reload {
   [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload];
   return [ChromeEarlGrey waitForPageToFinishLoading];
 }
 
-+ (NSError*)goBack {
+- (NSError*)goBack {
   [chrome_test_util::BrowserCommandDispatcherForMainBVC() goBack];
 
   return [ChromeEarlGrey waitForPageToFinishLoading];
 }
 
-+ (NSError*)goForward {
+- (NSError*)goForward {
   [chrome_test_util::BrowserCommandDispatcherForMainBVC() goForward];
 
   return [ChromeEarlGrey waitForPageToFinishLoading];
 }
 
-+ (NSError*)openNewTab {
+- (NSError*)openNewTab {
   chrome_test_util::OpenNewTab();
   NSError* error = [ChromeEarlGrey waitForPageToFinishLoading];
   if (!error) {
@@ -173,7 +173,7 @@
   return error;
 }
 
-+ (NSError*)openNewIncognitoTab {
+- (NSError*)openNewIncognitoTab {
   chrome_test_util::OpenNewIncognitoTab();
   NSError* error = [ChromeEarlGrey waitForPageToFinishLoading];
   if (!error) {
@@ -182,12 +182,12 @@
   return error;
 }
 
-+ (void)closeAllTabsInCurrentMode {
+- (void)closeAllTabsInCurrentMode {
   chrome_test_util::CloseAllTabsInCurrentMode();
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
 }
 
-+ (NSError*)closeAllIncognitoTabs {
+- (NSError*)closeAllIncognitoTabs {
   if (!chrome_test_util::CloseAllIncognitoTabs()) {
     return testing::NSErrorWithLocalizedDescription(@"Tabs did not close");
   }
@@ -196,12 +196,12 @@
   return nil;
 }
 
-+ (void)closeCurrentTab {
+- (void)closeCurrentTab {
   chrome_test_util::CloseCurrentTab();
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
 }
 
-+ (NSError*)waitForPageToFinishLoading {
+- (NSError*)waitForPageToFinishLoading {
   if (!chrome_test_util::WaitForPageToFinishLoading()) {
     return testing::NSErrorWithLocalizedDescription(
         @"Page did not complete loading.");
@@ -210,7 +210,7 @@
   return nil;
 }
 
-+ (NSError*)tapWebViewElementWithID:(NSString*)elementID {
+- (NSError*)tapWebViewElementWithID:(NSString*)elementID {
   BOOL success =
       web::test::TapWebViewElementWithId(chrome_test_util::GetCurrentWebState(),
                                          base::SysNSStringToUTF8(elementID));
@@ -224,13 +224,13 @@
   return nil;
 }
 
-+ (NSError*)waitForErrorPage {
+- (NSError*)waitForErrorPage {
   NSString* const kErrorPageText =
       l10n_util::GetNSString(IDS_ERRORPAGES_HEADING_NOT_AVAILABLE);
   return [self waitForStaticHTMLViewContainingText:kErrorPageText];
 }
 
-+ (NSError*)waitForStaticHTMLViewContainingText:(NSString*)text {
+- (NSError*)waitForStaticHTMLViewContainingText:(NSString*)text {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
     return chrome_test_util::StaticHtmlViewContainingText(
         chrome_test_util::GetCurrentWebState(), base::SysNSStringToUTF8(text));
@@ -246,7 +246,7 @@
   return nil;
 }
 
-+ (NSError*)waitForStaticHTMLViewNotContainingText:(NSString*)text {
+- (NSError*)waitForStaticHTMLViewNotContainingText:(NSString*)text {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
     return !chrome_test_util::StaticHtmlViewContainingText(
         chrome_test_util::GetCurrentWebState(), base::SysNSStringToUTF8(text));
@@ -262,7 +262,7 @@
   return nil;
 }
 
-+ (NSError*)waitForWebViewContainingText:(std::string)text {
+- (NSError*)waitForWebViewContainingText:(std::string)text {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
     return web::test::IsWebViewContainingText(
         chrome_test_util::GetCurrentWebState(), text);
@@ -278,7 +278,7 @@
   return nil;
 }
 
-+ (NSError*)waitForWebViewContainingElement:(ElementSelector*)selector {
+- (NSError*)waitForWebViewContainingElement:(ElementSelector*)selector {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
     return web::test::IsWebViewContainingElement(
         chrome_test_util::GetCurrentWebState(), selector);
@@ -294,7 +294,7 @@
   return nil;
 }
 
-+ (NSError*)waitForWebViewNotContainingText:(std::string)text {
+- (NSError*)waitForWebViewNotContainingText:(std::string)text {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
     return !web::test::IsWebViewContainingText(
         chrome_test_util::GetCurrentWebState(), text);
@@ -310,7 +310,7 @@
   return nil;
 }
 
-+ (NSError*)waitForMainTabCount:(NSUInteger)count {
+- (NSError*)waitForMainTabCount:(NSUInteger)count {
   // Allow the UI to become idle, in case any tabs are being opened or closed.
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
@@ -328,7 +328,7 @@
   return nil;
 }
 
-+ (NSError*)waitForIncognitoTabCount:(NSUInteger)count {
+- (NSError*)waitForIncognitoTabCount:(NSUInteger)count {
   // Allow the UI to become idle, in case any tabs are being opened or closed.
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
@@ -346,7 +346,7 @@
   return nil;
 }
 
-+ (NSError*)waitForWebViewContainingBlockedImageElementWithID:
+- (NSError*)waitForWebViewContainingBlockedImageElementWithID:
     (std::string)imageID {
   bool success = web::test::WaitForWebViewContainingImage(
       imageID, chrome_test_util::GetCurrentWebState(),
@@ -362,7 +362,7 @@
   return nil;
 }
 
-+ (NSError*)waitForWebViewContainingLoadedImageElementWithID:
+- (NSError*)waitForWebViewContainingLoadedImageElementWithID:
     (std::string)imageID {
   bool success = web::test::WaitForWebViewContainingImage(
       imageID, chrome_test_util::GetCurrentWebState(),
@@ -378,7 +378,7 @@
   return nil;
 }
 
-+ (NSError*)waitForBookmarksToFinishLoading {
+- (NSError*)waitForBookmarksToFinishLoading {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{
     return chrome_test_util::BookmarksLoaded();
   });
@@ -391,7 +391,7 @@
   return nil;
 }
 
-+ (NSError*)clearBookmarks {
+- (NSError*)clearBookmarks {
   bool success = chrome_test_util::ClearBookmarks();
   if (!success) {
     return testing::NSErrorWithLocalizedDescription(
@@ -400,7 +400,7 @@
   return nil;
 }
 
-+ (NSError*)waitForElementWithMatcherSufficientlyVisible:
+- (NSError*)waitForElementWithMatcherSufficientlyVisible:
     (id<GREYMatcher>)matcher {
   bool success = WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool {
     NSError* error = nil;
@@ -423,14 +423,14 @@
 
 #pragma mark - Settings Utilities
 
-+ (NSError*)setContentSettings:(ContentSetting)setting {
+- (NSError*)setContentSettings:(ContentSetting)setting {
   chrome_test_util::SetContentSettingsBlockPopups(setting);
   return nil;
 }
 
 #pragma mark - Sign Utilities
 
-+ (NSError*)signOutAndClearAccounts {
+- (NSError*)signOutAndClearAccounts {
   bool success = chrome_test_util::SignOutAndClearAccounts();
   if (!success) {
     return testing::NSErrorWithLocalizedDescription(
diff --git a/ios/showcase/alert/sc_alert_coordinator.mm b/ios/showcase/alert/sc_alert_coordinator.mm
index 03e8438..95fcfa00 100644
--- a/ios/showcase/alert/sc_alert_coordinator.mm
+++ b/ios/showcase/alert/sc_alert_coordinator.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/ui/alert_view_controller/alert_action.h"
 #import "ios/chrome/browser/ui/alert_view_controller/alert_view_controller.h"
+#import "ios/chrome/browser/ui/alert_view_controller/non_modal_view_controller_presenter.h"
 #import "ios/chrome/browser/ui/elements/text_field_configuration.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -16,6 +17,7 @@
 @property(nonatomic, strong)
     UIViewController* presentationContextViewController;
 @property(nonatomic, strong) UISwitch* blockAlertSwitch;
+@property(nonatomic, strong) NonModalViewControllerPresenter* presenter;
 @end
 
 @implementation SCAlertCoordinator
@@ -119,14 +121,12 @@
 }
 
 - (void)showAlert {
-  __weak __typeof(self) weakSelf = self;
+  __weak __typeof__(self) weakSelf = self;
   AlertAction* action =
       [AlertAction actionWithTitle:@"OK"
                              style:UIAlertActionStyleDefault
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   [self presentAlertWithTitle:@"chromium.org says"
                       message:@"This is an alert message from a website."
@@ -140,22 +140,18 @@
                                        placeholder:@"placehorder"
                            accessibilityIdentifier:nil
                                    secureTextEntry:NO];
-  __weak __typeof(self) weakSelf = self;
+  __weak __typeof__(self) weakSelf = self;
   AlertAction* OKAction =
       [AlertAction actionWithTitle:@"OK"
                              style:UIAlertActionStyleDefault
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   AlertAction* cancelAction =
       [AlertAction actionWithTitle:@"Cancel"
                              style:UIAlertActionStyleCancel
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   [self presentAlertWithTitle:@"chromium.org says"
                       message:@"This is a promp message from a website."
@@ -164,22 +160,18 @@
 }
 
 - (void)showConfirm {
-  __weak __typeof(self) weakSelf = self;
+  __weak __typeof__(self) weakSelf = self;
   AlertAction* OKAction =
       [AlertAction actionWithTitle:@"OK"
                              style:UIAlertActionStyleDefault
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   AlertAction* cancelAction =
       [AlertAction actionWithTitle:@"Cancel"
                              style:UIAlertActionStyleCancel
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   [self presentAlertWithTitle:@"chromium.org says"
                       message:@"This is a confirm message from a website."
@@ -199,22 +191,18 @@
                            accessibilityIdentifier:nil
                                    secureTextEntry:YES];
 
-  __weak __typeof(self) weakSelf = self;
+  __weak __typeof__(self) weakSelf = self;
   AlertAction* OKAction =
       [AlertAction actionWithTitle:@"Sign In"
                              style:UIAlertActionStyleDefault
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   AlertAction* cancelAction =
       [AlertAction actionWithTitle:@"Cancel"
                              style:UIAlertActionStyleCancel
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   [self presentAlertWithTitle:@"Sign In"
                       message:@"https://www.chromium.org requires a "
@@ -234,22 +222,18 @@
                                        placeholder:@"Password"
                            accessibilityIdentifier:nil
                                    secureTextEntry:YES];
-  __weak __typeof(self) weakSelf = self;
+  __weak __typeof__(self) weakSelf = self;
   AlertAction* OKAction =
       [AlertAction actionWithTitle:@"Sign In"
                              style:UIAlertActionStyleDefault
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   AlertAction* cancelAction =
       [AlertAction actionWithTitle:@"Cancel"
                              style:UIAlertActionStyleCancel
                            handler:^(AlertAction* action) {
-                             [weakSelf.presentationContextViewController
-                                 dismissViewControllerAnimated:YES
-                                                    completion:nil];
+                             [weakSelf.presenter dismissAnimated:YES];
                            }];
   NSString* message =
       @"It was the best of times, it was the worst of times, it was the age of "
@@ -282,14 +266,12 @@
   [alert setTextFieldConfigurations:textFieldConfigurations];
 
   if (self.blockAlertSwitch.isOn) {
-    __weak __typeof(self) weakSelf = self;
+    __weak __typeof__(self) weakSelf = self;
     AlertAction* blockAction =
         [AlertAction actionWithTitle:@"Block Dialogs"
                                style:UIAlertActionStyleDestructive
                              handler:^(AlertAction* action) {
-                               [weakSelf.presentationContextViewController
-                                   dismissViewControllerAnimated:YES
-                                                      completion:nil];
+                               [weakSelf.presenter dismissAnimated:YES];
                              }];
     NSArray* newActions = [actions arrayByAddingObject:blockAction];
     [alert setActions:newActions];
@@ -297,11 +279,11 @@
     [alert setActions:actions];
   }
 
-  alert.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
-  alert.modalPresentationStyle = UIModalPresentationOverCurrentContext;
-  [self.presentationContextViewController presentViewController:alert
-                                                       animated:true
-                                                     completion:nil];
+  self.presenter = [[NonModalViewControllerPresenter alloc] init];
+  self.presenter.baseViewController = self.presentationContextViewController;
+  self.presenter.presentedViewController = alert;
+  [self.presenter prepareForPresentation];
+  [self.presenter presentAnimated:YES];
 }
 
 @end
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 86a1a2e..e0314873 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -343,7 +343,6 @@
     "net/cookies/wk_http_system_cookie_store_unittest.mm",
     "net/crw_cert_verification_controller_unittest.mm",
     "net/crw_ssl_status_updater_unittest.mm",
-    "net/request_tracker_impl_unittest.mm",
   ]
 }
 
diff --git a/ios/web/net/BUILD.gn b/ios/web/net/BUILD.gn
index 867e94ea..cce1d23 100644
--- a/ios/web/net/BUILD.gn
+++ b/ios/web/net/BUILD.gn
@@ -29,8 +29,6 @@
     "crw_cert_verification_controller.mm",
     "crw_ssl_status_updater.h",
     "crw_ssl_status_updater.mm",
-    "request_tracker_impl.h",
-    "request_tracker_impl.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/web/net/request_tracker_impl.h b/ios/web/net/request_tracker_impl.h
deleted file mode 100644
index 7656637..0000000
--- a/ios/web/net/request_tracker_impl.h
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_
-#define IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_
-
-#import <Foundation/Foundation.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#import "ios/net/request_tracker.h"
-#include "ios/web/public/web_thread.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "url/gurl.h"
-
-@class SSLCarrier;
-struct TrackerCounts;
-
-namespace net {
-class URLRequest;
-class URLRequestContext;
-class SSLInfo;
-}
-
-namespace web {
-
-class BrowserState;
-class CertificatePolicyCache;
-
-// Structure to capture the current state of a page.
-struct PageCounts {
- public:
-  PageCounts()
-      : finished(0),
-        finished_bytes(0),
-        unfinished(0),
-        unfinished_no_estimate(0),
-        unfinished_no_estimate_bytes_done(0),
-        unfinished_estimated_bytes_left(0),
-        unfinished_estimate_bytes_done(0),
-        largest_byte_size_known(0) {}
-
-  // Count of finished requests.
-  uint64_t finished;
-  // Total bytes count dowloaded for all finished requests.
-  uint64_t finished_bytes;
-  // Count  of unfinished requests.
-  uint64_t unfinished;
-  // Count of unfinished requests with unknown size.
-  uint64_t unfinished_no_estimate;
-  // Total bytes count dowloaded for unfinished requests of unknown size.
-  uint64_t unfinished_no_estimate_bytes_done;
-  // Count of unfinished requests with an estimated size.
-  uint64_t unfinished_estimated_bytes_left;
-  // Total bytes count dowloaded for unfinished requests with an estimated size.
-  uint64_t unfinished_estimate_bytes_done;
-  // Size of the request with the most bytes on the page.
-  uint64_t largest_byte_size_known;
-};
-
-// RequestTrackerImpl captures and stores all the network requests that
-// initiated from a particular tab. It only keeps the URLs and eventually, if
-// available, the expected length of the result and the length of the received
-// data so far as this is used to build a progress bar for a page.
-// Note that the Request tracker has no notion of a page, it only tracks the
-// requests by tab. In order for the tracker to know that a request is for a
-// page or a subresource it is necessary for the tab to call StartPageLoad()
-// with the URL of the page once it is known to avoid storing all the requests
-// forever.
-//
-// The consumer needs to implement the CRWRequestTrackerImplDelegate protocol
-// and needs to call StartPageLoad() and FinishPageLoad() to indicate the page
-// boundaries. StartPageLoad() will also have the side effect of clearing past
-// requests from memory. The consumer is assumed to be on the UI thread at all
-// times.
-//
-// RequestTrackerImpl objects are created and destroyed on the UI thread and
-// must be owned by some other object on the UI thread by way of a
-// scoped_refptr, as returned by the public static constructor method,
-// CreateTrackerForRequestGroupID. All consumer API methods will be called
-// through this pointer.
-
-class RequestTrackerImpl;
-
-struct RequestTrackerImplTraits {
-  static void Destruct(const RequestTrackerImpl* t);
-};
-
-class RequestTrackerImpl
-    : public base::RefCountedThreadSafe<RequestTrackerImpl,
-                                        RequestTrackerImplTraits>,
-      public net::RequestTracker {
- public:
-#pragma mark Public Consumer API
-  // Consumer API methods should only be called on the UI thread.
-
-  // Create a new RequestTrackerImpl associated with a particular tab. The
-  // profile must be the one associated to the given tab. This method has to be
-  // called *once* per tab and needs to be called before triggering any network
-  // request. The caller of CreateTrackerForRequestGroupID owns the tracker, and
-  // this class also keeps a global map of all active trackers. When the owning
-  // object releases it, the class removes it from the global map.
-  static scoped_refptr<RequestTrackerImpl> CreateTrackerForRequestGroupID(
-      NSString* request_group_id,
-      BrowserState* browser_state,
-      net::URLRequestContextGetter* context_getter);
-
-  // The network layer has no way to know which network request is the primary
-  // one for a page load. The tab knows, either because it initiated the page
-  // load via the URL or received a callback informing it of the page change.
-  // Every time this happens the tab should call this method to clear the
-  // resources tracked.
-  // This will forget all the finished requests made before this URL in history.
-  // user_info is to be used by the consumer to store more additional specific
-  // info about the page, as an URL is not unique.
-  void StartPageLoad(const GURL& url, id user_info);
-
-  // In order to properly provide progress information the tracker needs to know
-  // when the page is fully loaded. |load_success| indicates if the page
-  // successfully loaded.
-  void FinishPageLoad(const GURL& url, bool load_success);
-
-  // Tells the tracker that history.pushState() or history.replaceState()
-  // changed the page URL.
-  void HistoryStateChange(const GURL& url);
-
-  // Marks the tracker as closed. An owner must call this before the tracker is
-  // deleted. Once closed, no further calls will be made to the delegate.
-  void Close();
-
-  // Call |callback| on the UI thread after any pending request cancellations
-  // have completed on the IO thread.
-  // This should be used to delete a profile for which all of the trackers
-  // that use the profile's request context are closed.
-  static void RunAfterRequestsCancel(const base::Closure& callback);
-
-  // Block until all pending IO thread activity has completed. This should only
-  // be used when Chrome is shutting down, and after all request trackers have
-  // had Close() called on them.
-  static void BlockUntilTrackersShutdown();
-
-#pragma mark Client utility methods.
-
-  // Finds the tracker given the tab ID. As calling this method involves a lock
-  // it is expected that the provider will call it only once.
-  // Returns a weak pointer, which should only be dereferenced on the IO thread.
-  // Returns NULL if no tracker exists for |request_group_id|.
-  static RequestTrackerImpl* GetTrackerForRequestGroupID(
-      NSString* request_group_id);
-
-  // Utility method for clients to post tasks to the IO thread from the UI
-  // thread.
-  void PostIOTask(const base::Closure& task);
-
-  // Utility method for clients to post tasks to the IO thread from the IO
-  // thread.
-  void ScheduleIOTask(const base::Closure& task);
-
-  // Utility method for clients to conditionally post tasks to the UI thread
-  // from the IO thread. The task will not be posted if the request tracker
-  // is in the process of closing (thus it "is open").
-  void PostUITaskIfOpen(const base::Closure& task);
-  // Static version of the method, where |tracker| is a RequestTrackerImpl
-  // passed as a base::WeakPtr<RequestTracker>.
-  static void PostUITaskIfOpen(const base::WeakPtr<RequestTracker> tracker,
-                               const base::Closure& task);
-
-#pragma mark Testing methods
-
-  void SetCertificatePolicyCacheForTest(web::CertificatePolicyCache* cache);
-
-#pragma mark Accessors used by internal classes and network clients.
-  int identifier() { return identifier_; }
-  bool has_mixed_content() { return has_mixed_content_; }
-
-  // RequestTracker implementation.
-  void StartRequest(net::URLRequest* request) override;
-  void CaptureExpectedLength(const net::URLRequest* request,
-                             uint64_t length) override;
-  void CaptureReceivedBytes(const net::URLRequest* request,
-                            uint64_t byte_count) override;
-  void CaptureCertificatePolicyCache(
-      const net::URLRequest* request,
-      const SSLCallback& should_continue) override;
-  void StopRequest(net::URLRequest* request) override;
-  void StopRedirectedRequest(net::URLRequest* request) override;
-  void OnSSLCertificateError(const net::URLRequest* request,
-                             const net::SSLInfo& ssl_info,
-                             bool recoverable,
-                             const SSLCallback& should_continue) override;
-  net::URLRequestContext* GetRequestContext() override;
-
- private:
-  friend class base::RefCountedThreadSafe<RequestTrackerImpl>;
-  friend struct RequestTrackerImplTraits;
-
-#pragma mark Object lifecycle API
-  // Private. RequestTrackerImpls are created through
-  // CreateTrackerForRequestGroupID().
-  RequestTrackerImpl(NSString* request_group_id,
-                     net::URLRequestContextGetter* context_getter);
-
-  void InitOnIOThread(
-      const scoped_refptr<web::CertificatePolicyCache>& policy_cache);
-
-  // Private destructor because the object is reference counted. A no-op; the
-  // useful destruction work happens in Destruct().
-  ~RequestTrackerImpl() override;
-
-  // Handles pre-destruction destruction tasks. This is invoked by
-  // RequestTrackerImplTraits::Destruct whenever the reference count of a
-  // RequestTrackerImpl is zero, and this will untimately delete the
-  // RequestTrackerImpl.
-  void Destruct();
-
-#pragma mark Private Provider API
-  // Private methods that implement provider API features. All are only called
-  // on the IO thread.
-
-  // Called when something has changed (network load progress or SSL status)
-  // that the consumer should know about. Notifications are asynchronous and
-  // batched.
-  void Notify();
-
-  // If no other notifications are pending, notifies the consumer of SSL status
-  // and load progress.
-  void StackNotification();
-
-  // If the counts is for a request currently waiting for the user to approve it
-  // will reevaluate the approval.
-  void EvaluateSSLCallbackForCounts(TrackerCounts* counts);
-
-  // Loop through all the requests waiting for approval and invoke
-  // |-evaluateSSLCallbackForCounts:| on all the ones with an |UNKNOWN|
-  // judgment.
-  void ReevaluateCallbacksForAllCounts();
-
-  // To cancel a rejected request due to a SSL issue.
-  void CancelRequestForCounts(TrackerCounts* counts);
-
-  // Estimate the page load progress. Returns -1 if the progress didn't change
-  // since the last time this method was invoked.
-  float EstimatedProgress();
-
-  // The URL change notification is often late, therefore the mixed content
-  // status and the certificate policies may need to be recomputed.
-  void RecomputeMixedContent(const TrackerCounts* split_position);
-
-  // Remove all finished request up to the last instance of |url|. If url is not
-  // found, this will clear all the requests.
-  void TrimToURL(const GURL& url, id user_info);
-
-  // Sets page_url_ to the new URL if it's a valid history state change (i.e.
-  // the URL's have the same origin) and if the tab is currently loading.
-  void HistoryStateChangeToURL(const GURL& full_url);
-
-  // Note that the page started by a call to Trim is no longer loading.
-  // |load_success| indicates if the page successfully loaded.
-  void StopPageLoad(const GURL& url, bool load_success);
-
-#pragma mark Internal utilities for task posting
-  // Posts |task| to |thread|. Must not be called from |thread|. If |thread| is
-  // the IO thread, silently returns if |is_closing_| is true.
-  void PostTask(const base::Closure& task, web::WebThread::ID thread);
-
-  // Posts |block| to |thread|, safely passing in |caller| to |block|.
-  void PostBlock(id caller, void (^block)(id), web::WebThread::ID thread);
-
-#pragma mark Other internal methods.
-  // Returns the current state of the page.
-  PageCounts pageCounts();
-
-  // Like description, but cannot be called from any thread. It must be called
-  // only from the IO thread.
-  NSString* UnsafeDescription();
-
-#pragma mark Non thread-safe fields, only accessed from the IO thread.
-  // All the tracked requests for the page, indexed by net::URLRequest (Cast as
-  // a void* to avoid the temptation of accessing it from the wrong thread).
-  // This map is not exhaustive: it is only meant to estimate the loading
-  // progress, and thus requests corresponding to old navigation events are not
-  // in it.
-  std::map<const void*, TrackerCounts*> counts_by_request_;
-  // A list of all the TrackerCounts, including the finished ones.
-  std::vector<std::unique_ptr<TrackerCounts>> counts_;
-  // The system shall never allow the page load estimate to go back.
-  float previous_estimate_;
-  // Index of the first request to consider for building the estimation.
-  unsigned int estimate_start_index_;
-  // How many notifications are currently queued, to avoid notifying too often.
-  int notification_depth_;
-  // Set to |YES| if the page has mixed content
-  bool has_mixed_content_;
-  // Set to true if between TrimToURL and StopPageLoad.
-  bool is_loading_;
-  // Set to true in TrimToURL if starting a new estimate round. Set to false by
-  // StartRequest once the new round is started.
-  bool new_estimate_round_;
-
-#pragma mark Other fields.
-  scoped_refptr<web::CertificatePolicyCache> policy_cache_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  // Current page URL, as far as we know.
-  GURL page_url_;
-  // Userinfo attached to the page, passed back by the delegate.
-  id user_info_;
-  // A tracker identifier (a simple increasing number) used to store
-  // certificates.
-  int identifier_;
-  // The string that identifies the tab this tracker serves. Used to index
-  // g_trackers.
-  NSString* request_group_id_;
-  // Flag to synchronize deletion and callback creation. Lives on the IO thread.
-  // True when this tracker has beed Close()d. If this is the case, no further
-  // references to it should be generated (for example by binding it into a
-  // callback), and the expectation is that it will soon be deleted.
-  bool is_closing_;
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_NET_REQUEST_TRACKER_IMPL_H_
diff --git a/ios/web/net/request_tracker_impl.mm b/ios/web/net/request_tracker_impl.mm
deleted file mode 100644
index 09e04092..0000000
--- a/ios/web/net/request_tracker_impl.mm
+++ /dev/null
@@ -1,891 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/web/net/request_tracker_impl.h"
-
-#include <pthread.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/synchronization/lock.h"
-#include "base/task/post_task.h"
-#include "ios/web/common/url_util.h"
-#include "ios/web/history_state_util.h"
-#include "ios/web/public/browser_state.h"
-#include "ios/web/public/certificate_policy_cache.h"
-#include "ios/web/public/web_task_traits.h"
-#include "ios/web/public/web_thread.h"
-#import "net/base/mac/url_conversions.h"
-#include "net/url_request/url_request.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-
-// A map of all RequestTrackerImpls for tabs that are:
-// * Currently open
-// * Recently closed waiting for all their network operations to finish.
-// The code accesses this variable from two threads: the consumer is expected to
-// always access it from the main thread, the provider is accessing it from the
-// WebThread, a thread created by the UIWebView/CFURL. For this reason access to
-// this variable must always gated by |g_trackers_lock|.
-typedef std::unordered_map<std::string, web::RequestTrackerImpl*> TrackerMap;
-
-TrackerMap* g_trackers = NULL;
-base::Lock* g_trackers_lock = NULL;
-pthread_once_t g_once_control = PTHREAD_ONCE_INIT;
-
-// Flag, lock, and function to implement BlockUntilTrackersShutdown().
-// |g_waiting_on_io_thread| is guarded by |g_waiting_on_io_thread_lock|;
-// it is set to true when the shutdown wait starts, then a call to
-// StopIOThreadWaiting is posted to the IO thread (enqueued after any pending
-// request terminations) while the posting method loops over a check on the
-// |g_waiting_on_io_thread|.
-static bool g_waiting_on_io_thread = false;
-base::Lock* g_waiting_on_io_thread_lock = NULL;
-void StopIOThreadWaiting() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  base::AutoLock scoped_lock(*g_waiting_on_io_thread_lock);
-  g_waiting_on_io_thread = false;
-}
-
-// Initialize global state. Calls to this should be conditional on
-// |g_once_control| (that is, this should only be called once, across all
-// threads).
-void InitializeGlobals() {
-  g_trackers = new TrackerMap;
-  g_trackers_lock = new base::Lock;
-  g_waiting_on_io_thread_lock = new base::Lock;
-}
-
-// Each request tracker get a unique increasing number, used anywhere an
-// identifier is needed for tracker (e.g. storing certs).
-int g_next_request_tracker_id = 0;
-
-// Add |tracker| to |g_trackers| under |key|.
-static void RegisterTracker(web::RequestTrackerImpl* tracker, NSString* key) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  pthread_once(&g_once_control, &InitializeGlobals);
-  {
-    std::string scoped_key = base::SysNSStringToUTF8(key);
-    base::AutoLock scoped_lock(*g_trackers_lock);
-    DCHECK(!g_trackers->count(scoped_key));
-    (*g_trackers)[scoped_key] = tracker;
-  }
-}
-
-}  // namespace
-
-// The structure used to gather the information about the resources loaded.
-struct TrackerCounts {
- public:
-  TrackerCounts(const GURL& tracked_url, const net::URLRequest* tracked_request)
-      : url(tracked_url),
-        site_for_cookies_origin(
-            tracked_request->site_for_cookies().GetOrigin()),
-        request(tracked_request),
-        ssl_info(net::SSLInfo()),
-        ssl_judgment(web::CertPolicy::ALLOWED),
-        allowed_by_user(false),
-        expected_length(0),
-        processed(0),
-        done(false) {
-    DCHECK_CURRENTLY_ON(web::WebThread::IO);
-    is_subrequest =
-        tracked_request->site_for_cookies().is_valid() &&
-        tracked_request->url() != tracked_request->site_for_cookies();
-  }
-
-  // The resource url.
-  const GURL url;
-  // The origin of the url of the top level document of the resource. This is
-  // used to ignore request coming from an old document when detecting mixed
-  // content.
-  const GURL site_for_cookies_origin;
-  // The request associated with this struct. As a void* to prevent access from
-  // the wrong thread.
-  const void* request;
-  // SSLInfo for the request.
-  net::SSLInfo ssl_info;
-  // Is the SSL request blocked waiting for user choice.
-  web::CertPolicy::Judgment ssl_judgment;
-  // True if |ssl_judgment| is ALLOWED as the result of a user choice.
-  bool allowed_by_user;
-  // block to call to cancel or authorize a blocked request.
-  net::RequestTracker::SSLCallback ssl_callback;
-  // If known, the expected length of the resource in bytes.
-  uint64_t expected_length;
-  // Number of bytes loaded so far.
-  uint64_t processed;
-  // Set to true is the resource is fully loaded.
-  bool done;
-  // Set to true if the request has a main request set.
-  bool is_subrequest;
-
-  NSString* Description() {
-    NSString* spec = base::SysUTF8ToNSString(url.spec());
-    NSString* status = nil;
-    if (done) {
-      status = [NSString stringWithFormat:@"\t-- Done -- (%04qu) bytes",
-          processed];
-    } else if (!expected_length) {
-      status = [NSString stringWithFormat:@"\t>> Loading (%04qu) bytes",
-          processed];
-    } else {
-      status = [NSString stringWithFormat:@"\t>> Loading (%04qu/%04qu)",
-          processed, expected_length];
-    }
-
-    NSString* ssl = @"";
-    if (ssl_info.is_valid()) {
-      NSString* subject = base::SysUTF8ToNSString(
-          ssl_info.cert.get()->subject().GetDisplayName());
-      NSString* issuer = base::SysUTF8ToNSString(
-          ssl_info.cert.get()->issuer().GetDisplayName());
-
-      ssl = [NSString stringWithFormat:
-          @"\n\t\tcert for '%@' issued by '%@'", subject, issuer];
-
-      if (!net::IsCertStatusMinorError(ssl_info.cert_status)) {
-        ssl = [NSString stringWithFormat:@"%@ (status: %0xd)",
-            ssl, ssl_info.cert_status];
-      }
-    }
-    return [NSString stringWithFormat:@"%@\n\t\t%@%@", status, spec, ssl];
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(TrackerCounts);
-};
-
-namespace web {
-
-#pragma mark Consumer API
-
-// static
-scoped_refptr<RequestTrackerImpl>
-RequestTrackerImpl::CreateTrackerForRequestGroupID(
-    NSString* request_group_id,
-    BrowserState* browser_state,
-    net::URLRequestContextGetter* context_getter) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  DCHECK(request_group_id);
-
-  scoped_refptr<RequestTrackerImpl> tracker =
-      new RequestTrackerImpl(request_group_id, context_getter);
-
-  scoped_refptr<CertificatePolicyCache> policy_cache =
-      BrowserState::GetCertificatePolicyCache(browser_state);
-  DCHECK(policy_cache);
-
-  // Take care of the IO-thread init.
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO},
-                           base::BindOnce(&RequestTrackerImpl::InitOnIOThread,
-                                          tracker, policy_cache));
-  RegisterTracker(tracker.get(), request_group_id);
-  return tracker;
-}
-
-void RequestTrackerImpl::StartPageLoad(const GURL& url, id user_info) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  id scoped_user_info = user_info;
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO},
-                           base::BindOnce(&RequestTrackerImpl::TrimToURL, this,
-                                          url, scoped_user_info));
-}
-
-void RequestTrackerImpl::FinishPageLoad(const GURL& url, bool load_success) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO},
-                           base::BindOnce(&RequestTrackerImpl::StopPageLoad,
-                                          this, url, load_success));
-}
-
-void RequestTrackerImpl::HistoryStateChange(const GURL& url) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  base::PostTaskWithTraits(
-      FROM_HERE, {web::WebThread::IO},
-      base::BindOnce(&RequestTrackerImpl::HistoryStateChangeToURL, this, url));
-}
-
-// Close is called when an owning object (a Tab or something that acts like
-// it) is done with the RequestTrackerImpl. There may still be queued calls on
-// the UI thread that will make use of the fields being cleaned-up here; they
-// must ensure they they operate without crashing with the cleaned-up values.
-void RequestTrackerImpl::Close() {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  // Mark the tracker as closing on the IO thread. Note that because the local
-  // scoped_refptr here retains |this|, we a are guaranteed that destruiction
-  // won't begin until the block completes, and thus |is_closing_| will always
-  // be set before destruction begins.
-  base::PostTaskWithTraits(
-      FROM_HERE, {web::WebThread::IO},
-      base::BindOnce(
-          [](RequestTrackerImpl* tracker) { tracker->is_closing_ = true; },
-          base::RetainedRef(this)));
-
-  // The user_info is no longer needed.
-  user_info_ = nil;
-}
-
-// static
-void RequestTrackerImpl::RunAfterRequestsCancel(const base::Closure& callback) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  // Post a no-op to the IO thread, and after that has executed, run |callback|.
-  // This ensures that |callback| runs after anything elese queued on the IO
-  // thread, in particular CancelRequest() calls made from closing trackers.
-  base::PostTaskWithTraitsAndReply(FROM_HERE, {web::WebThread::IO},
-                                   base::DoNothing(), callback);
-}
-
-// static
-void RequestTrackerImpl::BlockUntilTrackersShutdown() {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  // Initialize the globals as part of the shutdown to prevent a crash when
-  // trying to acquire the lock if it was never initialised. It can happen
-  // if the application is terminated when no RequestTracker has been created
-  // (which can happen if no UIWebView has been created). See crbug.com/684611
-  // for information on such a crash.
-  //
-  // As RequestTracker are deprecated and are only used in Sign-In workflow
-  // it is simpler to just do the initialisation here than tracking whether
-  // the method should be called or not by client code.
-  pthread_once(&g_once_control, &InitializeGlobals);
-  {
-    base::AutoLock scoped_lock(*g_waiting_on_io_thread_lock);
-    g_waiting_on_io_thread = true;
-  }
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO},
-                           base::BindOnce(&StopIOThreadWaiting));
-
-  // Poll endlessly until the wait flag is unset on the IO thread by
-  // StopIOThreadWaiting().
-  // (Consider instead having a hard time cap, like 100ms or so, after which
-  // we stop blocking. In that case this method would return a boolean
-  // indicating if the wait completed or not).
-  while (1) {
-    base::AutoLock scoped_lock(*g_waiting_on_io_thread_lock);
-    if (!g_waiting_on_io_thread)
-      return;
-    // Ensure that other threads have a chance to run even on a single-core
-    // devices.
-    pthread_yield_np();
-  }
-}
-
-#pragma mark Provider API
-
-// static
-RequestTrackerImpl* RequestTrackerImpl::GetTrackerForRequestGroupID(
-    NSString* request_group_id) {
-  DCHECK(request_group_id);
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  RequestTrackerImpl* tracker = nullptr;
-  TrackerMap::iterator map_it;
-  pthread_once(&g_once_control, &InitializeGlobals);
-  {
-    base::AutoLock scoped_lock(*g_trackers_lock);
-    map_it = g_trackers->find(base::SysNSStringToUTF8(request_group_id));
-    if (map_it != g_trackers->end())
-      tracker = map_it->second;
-  }
-  return tracker;
-}
-
-net::URLRequestContext* RequestTrackerImpl::GetRequestContext() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  return request_context_getter_->GetURLRequestContext();
-}
-
-void RequestTrackerImpl::StartRequest(net::URLRequest* request) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  DCHECK(!counts_by_request_.count(request));
-  DCHECK(!request->url().SchemeIsFile());
-
-  if (new_estimate_round_) {
-    // Starting a new estimate round. Ignore the previous requests for the
-    // calculation.
-    counts_by_request_.clear();
-    estimate_start_index_ = counts_.size();
-    new_estimate_round_ = false;
-  }
-  const GURL& url = request->original_url();
-  auto counts =
-      std::make_unique<TrackerCounts>(GURLByRemovingRefFromGURL(url), request);
-  counts_by_request_[request] = counts.get();
-  counts_.push_back(std::move(counts));
-  if (page_url_.SchemeIsCryptographic() && !url.SchemeIsCryptographic())
-    has_mixed_content_ = true;
-  Notify();
-}
-
-void RequestTrackerImpl::CaptureExpectedLength(const net::URLRequest* request,
-                                               uint64_t length) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  if (counts_by_request_.count(request)) {
-    TrackerCounts* counts = counts_by_request_[request];
-    DCHECK(!counts->done);
-    if (length < counts->processed) {
-      // Something is wrong with the estimate. Ignore it.
-      counts->expected_length = 0;
-    } else {
-      counts->expected_length = length;
-    }
-    Notify();
-  }
-}
-
-void RequestTrackerImpl::CaptureReceivedBytes(const net::URLRequest* request,
-                                              uint64_t byte_count) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  if (counts_by_request_.count(request)) {
-    TrackerCounts* counts = counts_by_request_[request];
-    DCHECK(!counts->done);
-    const net::SSLInfo& ssl_info = request->ssl_info();
-    if (ssl_info.is_valid())
-      counts->ssl_info = ssl_info;
-    counts->processed += byte_count;
-    if (counts->expected_length > 0 &&
-        counts->expected_length < counts->processed) {
-      // Something is wrong with the estimate, it is too low. Ignore it.
-      counts->expected_length = 0;
-    }
-    Notify();
-  }
-}
-
-void RequestTrackerImpl::StopRequest(net::URLRequest* request) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-
-  if (counts_by_request_.count(request)) {
-    StopRedirectedRequest(request);
-    Notify();
-  }
-}
-
-void RequestTrackerImpl::StopRedirectedRequest(net::URLRequest* request) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-
-  if (counts_by_request_.count(request)) {
-    TrackerCounts* counts = counts_by_request_[request];
-    DCHECK(!counts->done);
-    const net::SSLInfo& ssl_info = request->ssl_info();
-    if (ssl_info.is_valid())
-      counts->ssl_info = ssl_info;
-    counts->done = true;
-    counts_by_request_.erase(request);
-  }
-}
-
-void RequestTrackerImpl::CaptureCertificatePolicyCache(
-    const net::URLRequest* request,
-    const RequestTracker::SSLCallback& should_continue) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  std::string host = request->url().host();
-  CertPolicy::Judgment judgment = policy_cache_->QueryPolicy(
-      request->ssl_info().cert.get(), host, request->ssl_info().cert_status);
-  if (judgment == CertPolicy::UNKNOWN) {
-    // The request comes from the cache, and has been loaded even though the
-    // policy is UNKNOWN. Display the interstitial page now.
-    OnSSLCertificateError(request, request->ssl_info(), true, should_continue);
-    return;
-  }
-
-  // Notify the  delegate that a judgment has been used.
-  DCHECK(judgment == CertPolicy::ALLOWED);
-  should_continue.Run(true);
-}
-
-void RequestTrackerImpl::OnSSLCertificateError(
-    const net::URLRequest* request,
-    const net::SSLInfo& ssl_info,
-    bool recoverable,
-    const RequestTracker::SSLCallback& should_continue) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  DCHECK(ssl_info.is_valid());
-
-  if (counts_by_request_.count(request)) {
-    TrackerCounts* counts = counts_by_request_[request];
-
-    DCHECK(!counts->done);
-    // Store the ssl error.
-    counts->ssl_info = ssl_info;
-    counts->ssl_callback = should_continue;
-    counts->ssl_judgment =
-        recoverable ? CertPolicy::UNKNOWN : CertPolicy::DENIED;
-    ReevaluateCallbacksForAllCounts();
-  }
-}
-
-#pragma mark Client utility methods.
-
-void RequestTrackerImpl::PostUITaskIfOpen(const base::Closure& task) {
-  PostTask(task, web::WebThread::UI);
-}
-
-// static
-void RequestTrackerImpl::PostUITaskIfOpen(
-    const base::WeakPtr<RequestTracker> tracker,
-    const base::Closure& task) {
-  if (!tracker)
-    return;
-  RequestTrackerImpl* tracker_impl =
-      static_cast<RequestTrackerImpl*>(tracker.get());
-  tracker_impl->PostUITaskIfOpen(task);
-}
-
-void RequestTrackerImpl::PostIOTask(const base::Closure& task) {
-  PostTask(task, web::WebThread::IO);
-}
-
-void RequestTrackerImpl::ScheduleIOTask(const base::Closure& task) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO}, task);
-}
-
-#pragma mark Private Object Lifecycle API
-
-RequestTrackerImpl::RequestTrackerImpl(
-    NSString* request_group_id,
-    net::URLRequestContextGetter* context_getter)
-    : previous_estimate_(0.0f),  // Not active by default.
-      estimate_start_index_(0),
-      notification_depth_(0),
-      has_mixed_content_(false),
-      is_loading_(false),
-      new_estimate_round_(true),
-      request_context_getter_(context_getter),
-      identifier_(++g_next_request_tracker_id),
-      request_group_id_([request_group_id copy]),
-      is_closing_(false) {
-  DCHECK_CURRENTLY_ON(web::WebThread::UI);
-}
-
-void RequestTrackerImpl::InitOnIOThread(
-    const scoped_refptr<CertificatePolicyCache>& policy_cache) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  Init();
-  DCHECK(policy_cache);
-  policy_cache_ = policy_cache;
-}
-
-RequestTrackerImpl::~RequestTrackerImpl() {
-}
-
-void RequestTrackerImplTraits::Destruct(const RequestTrackerImpl* t) {
-  // RefCountedThreadSafe assumes we can do all the destruct tasks with a
-  // const pointer, but we actually can't.
-  RequestTrackerImpl* inconstant_t = const_cast<RequestTrackerImpl*>(t);
-  if (web::WebThread::CurrentlyOn(web::WebThread::IO)) {
-    inconstant_t->Destruct();
-  } else {
-    // Use BindBlock rather than Bind to avoid creating another scoped_refpter
-    // to |this|. |inconstant_t| isn't retained by the block, but since this
-    // method is the mechanism by which all RequestTrackerImpl instances are
-    // destroyed, the object inconstant_t points to won't be deleted while
-    // the block is executing (and Destruct() itself will do the deleting).
-    base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO}, base::BindOnce(^{
-                               inconstant_t->Destruct();
-                             }));
-  }
-}
-
-void RequestTrackerImpl::Destruct() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  DCHECK(is_closing_);
-
-  pthread_once(&g_once_control, &InitializeGlobals);
-  {
-    base::AutoLock scoped_lock(*g_trackers_lock);
-    g_trackers->erase(base::SysNSStringToUTF8(request_group_id_));
-  }
-  InvalidateWeakPtrs();
-  // Delete on the UI thread.
-  base::PostTaskWithTraits(FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
-                             delete this;
-                           }));
-}
-
-#pragma mark Other private methods
-
-void RequestTrackerImpl::Notify() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  if (is_closing_)
-    return;
-  // Notify() is called asynchronously, it runs later on the same
-  // thread. This is used to collate notifications together, avoiding
-  // blanketing the UI with a stream of information.
-  notification_depth_ += 1;
-  base::PostTaskWithTraits(
-      FROM_HERE, {web::WebThread::IO},
-      base::BindOnce(&RequestTrackerImpl::StackNotification, this));
-}
-
-void RequestTrackerImpl::StackNotification() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  if (is_closing_)
-    return;
-
-  // There is no point in sending the notification if there is another one
-  // already queued. This queue is processing very lightweight changes and
-  // should be exhausted very easily.
-  --notification_depth_;
-  if (notification_depth_)
-    return;
-}
-
-void RequestTrackerImpl::EvaluateSSLCallbackForCounts(TrackerCounts* counts) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  DCHECK(policy_cache_);
-
-  // Ignore non-SSL requests.
-  if (!counts->ssl_info.is_valid())
-    return;
-
-  CertPolicy::Judgment judgment =
-      policy_cache_->QueryPolicy(counts->ssl_info.cert.get(),
-                                 counts->url.host(),
-                                 counts->ssl_info.cert_status);
-
-  if (judgment != CertPolicy::ALLOWED) {
-    // Apply some fine tuning.
-    // TODO(droger): This logic is duplicated from SSLPolicy. Sharing the code
-    // would be better.
-    switch (net::MapCertStatusToNetError(counts->ssl_info.cert_status)) {
-      case net::ERR_CERT_NO_REVOCATION_MECHANISM:
-        // Ignore this error.
-        judgment = CertPolicy::ALLOWED;
-        break;
-      case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
-        // We ignore this error but it will show a warning status in the
-        // location bar.
-        judgment = CertPolicy::ALLOWED;
-        break;
-      case net::ERR_CERT_CONTAINS_ERRORS:
-      case net::ERR_CERT_REVOKED:
-      case net::ERR_CERT_INVALID:
-      case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
-      case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
-        judgment = CertPolicy::DENIED;
-        break;
-      case net::ERR_CERT_COMMON_NAME_INVALID:
-      case net::ERR_CERT_DATE_INVALID:
-      case net::ERR_CERT_AUTHORITY_INVALID:
-      case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
-      case net::ERR_CERT_WEAK_KEY:
-      case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
-      case net::ERR_CERT_VALIDITY_TOO_LONG:
-        // Nothing. If DENIED it will stay denied. If UNKNOWN it will be
-        // shown to the user for decision.
-        break;
-      default:
-        NOTREACHED();
-        judgment = CertPolicy::DENIED;
-        break;
-    }
-  }
-
-  counts->ssl_judgment = judgment;
-
-  switch (judgment) {
-    case CertPolicy::UNKNOWN:
-    case CertPolicy::DENIED:
-      // Simply cancel the request.
-      CancelRequestForCounts(counts);
-      break;
-    case CertPolicy::ALLOWED:
-      counts->ssl_callback.Run(YES);
-      counts->ssl_callback = base::DoNothing();
-      break;
-    default:
-      NOTREACHED();
-      // For now simply cancel the request.
-      CancelRequestForCounts(counts);
-      break;
-  }
-}
-
-void RequestTrackerImpl::ReevaluateCallbacksForAllCounts() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  if (is_closing_)
-    return;
-
-  for (const auto& tracker_count : counts_) {
-    // Check if the value hasn't changed via a user action.
-    if (tracker_count->ssl_judgment == CertPolicy::UNKNOWN)
-      EvaluateSSLCallbackForCounts(tracker_count.get());
-  }
-}
-
-void RequestTrackerImpl::CancelRequestForCounts(TrackerCounts* counts) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  // Cancel the request.
-  counts->done = true;
-  counts_by_request_.erase(counts->request);
-  counts->ssl_callback.Run(NO);
-  counts->ssl_callback = base::DoNothing();
-  Notify();
-}
-
-PageCounts RequestTrackerImpl::pageCounts() {
-  DCHECK_GE(counts_.size(), estimate_start_index_);
-
-  PageCounts page_counts;
-
-  for (const auto& tracker_count : counts_) {
-    if (tracker_count->done) {
-      uint64_t size = tracker_count->processed;
-      page_counts.finished += 1;
-      page_counts.finished_bytes += size;
-      if (page_counts.largest_byte_size_known < size) {
-        page_counts.largest_byte_size_known = size;
-      }
-    } else {
-      page_counts.unfinished += 1;
-      if (tracker_count->expected_length) {
-        uint64_t size = tracker_count->expected_length;
-        page_counts.unfinished_estimate_bytes_done += tracker_count->processed;
-        page_counts.unfinished_estimated_bytes_left += size;
-        if (page_counts.largest_byte_size_known < size) {
-          page_counts.largest_byte_size_known = size;
-        }
-      } else {
-        page_counts.unfinished_no_estimate += 1;
-        page_counts.unfinished_no_estimate_bytes_done +=
-            tracker_count->processed;
-      }
-    }
-  }
-
-  return page_counts;
-}
-
-float RequestTrackerImpl::EstimatedProgress() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-
-  const PageCounts page_counts = pageCounts();
-
-  // Nothing in progress and the last time was the same.
-  if (!page_counts.unfinished && previous_estimate_ == 0.0f)
-    return -1.0f;
-
-  // First request.
-  if (previous_estimate_ == 0.0f) {
-    // start low.
-    previous_estimate_ = 0.1f;
-    return previous_estimate_;  // Return the just started status.
-  }
-
-  // The very simple case where everything is probably done and dusted.
-  if (!page_counts.unfinished) {
-    // Add 60%, and return. Another task is going to finish this.
-    float bump = (1.0f - previous_estimate_) * 0.6f;
-    previous_estimate_ += bump;
-    return previous_estimate_;
-  }
-
-  // Calculate some ratios.
-  // First the ratio of the finished vs the unfinished counts of resources
-  // loaded.
-  float unfinishedRatio =
-      static_cast<float>(page_counts.finished) /
-      static_cast<float>(page_counts.unfinished + page_counts.finished);
-
-  // The ratio of bytes left vs bytes already downloaded for the resources where
-  // no estimates of final size are known. For this ratio it is assumed the size
-  // of a resource not downloaded yet is the maximum size of all the resources
-  // seen so far.
-  float noEstimateRatio = (!page_counts.unfinished_no_estimate_bytes_done) ?
-      0.0f :
-      static_cast<float>(page_counts.unfinished_no_estimate *
-                         page_counts.largest_byte_size_known) /
-          static_cast<float>(page_counts.finished_bytes +
-                             page_counts.unfinished_no_estimate_bytes_done);
-
-  // The ratio of bytes left vs bytes already downloaded for the resources with
-  // available estimated size.
-  float estimateRatio = (!page_counts.unfinished_estimated_bytes_left) ?
-      noEstimateRatio :
-      static_cast<float>(page_counts.unfinished_estimate_bytes_done) /
-  static_cast<float>(page_counts.unfinished_estimate_bytes_done +
-                     page_counts.unfinished_estimated_bytes_left);
-
-  // Reassemble all of this.
-  float total =
-      0.1f +  // Minimum value.
-      unfinishedRatio * 0.6f +
-      estimateRatio * 0.3f;
-
-  if (previous_estimate_ >= total)
-    return -1.0f;
-
-  // 10% of what's left.
-  float maxBump = (1.0f - previous_estimate_) / 10.0f;
-  // total is greater than previous estimate, need to bump the estimate up.
-  if ((previous_estimate_ + maxBump) > total) {
-    // Less than a 10% bump, bump to the new value.
-    previous_estimate_ = total;
-  } else {
-    // Just bump by 10% toward the total.
-    previous_estimate_ += maxBump;
-  }
-
-  return previous_estimate_;
-}
-
-void RequestTrackerImpl::RecomputeMixedContent(
-    const TrackerCounts* split_position) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  // Check if the mixed content before trimming was correct.
-  if (page_url_.SchemeIsCryptographic() && has_mixed_content_) {
-    bool old_url_has_mixed_content = false;
-    const GURL origin = page_url_.GetOrigin();
-    auto it = counts_.begin();
-    while (it != counts_.end() && it->get() != split_position) {
-      if (!(*it)->url.SchemeIsCryptographic() &&
-          origin == (*it)->site_for_cookies_origin) {
-        old_url_has_mixed_content = true;
-        break;
-      }
-      ++it;
-    }
-    if (!old_url_has_mixed_content) {
-      // We marked the previous page with incorrect data about its mixed
-      // content. Turns out that the elements that triggered that condition
-      // where in fact in a subsequent page. Duh.
-      // Resend a notification for the |page_url_| informing the upper layer
-      // that the mixed content was a red herring.
-      has_mixed_content_ = false;
-    }
-  }
-}
-
-void RequestTrackerImpl::HistoryStateChangeToURL(const GURL& full_url) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  GURL url = GURLByRemovingRefFromGURL(full_url);
-
-  if (is_loading_ &&
-      web::history_state_util::IsHistoryStateChangeValid(url, page_url_)) {
-    page_url_ = url;
-  }
-}
-
-void RequestTrackerImpl::TrimToURL(const GURL& full_url, id user_info) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-
-  GURL url = GURLByRemovingRefFromGURL(full_url);
-
-  // Locate the request with this url, if present.
-  bool new_url_has_mixed_content = false;
-  bool url_scheme_is_secure = url.SchemeIsCryptographic();
-  auto rit = counts_.rbegin();
-  while (rit != counts_.rend() && (*rit)->url != url) {
-    if (url_scheme_is_secure && !(*rit)->url.SchemeIsCryptographic() &&
-        (*rit)->site_for_cookies_origin == url.GetOrigin()) {
-      new_url_has_mixed_content = true;
-    }
-    ++rit;
-  }
-
-  // |split_position| will be set to the count for the passed url if it exists.
-  TrackerCounts* split_position = NULL;
-  if (rit != counts_.rend()) {
-    split_position = rit->get();
-  } else {
-    // The URL was not found, everything will be trimmed. The mixed content
-    // calculation is invalid.
-    new_url_has_mixed_content = false;
-
-    // In the case of a page loaded via a HTML5 manifest there is no page
-    // boundary to be found. However the latest count is a request for a
-    // manifest. This tries to detect this peculiar case.
-    // This is important as if this request for the manifest is on the same
-    // domain as the page itself this will allow retrieval of the SSL
-    // information.
-    if (url_scheme_is_secure && counts_.size()) {
-      TrackerCounts* back = counts_.back().get();
-      const GURL& back_url = back->url;
-      if (back_url.SchemeIsCryptographic() &&
-          back_url.GetOrigin() == url.GetOrigin() && !back->is_subrequest) {
-        split_position = back;
-      }
-    }
-  }
-  RecomputeMixedContent(split_position);
-
-  // Trim up to that element.
-  auto it = counts_.begin();
-  while (it != counts_.end() && it->get() != split_position) {
-    if (!(*it)->done) {
-      // This is for an unfinished request on a previous page. We do not care
-      // about those anymore. Cancel the request.
-      if ((*it)->ssl_judgment == CertPolicy::UNKNOWN)
-        CancelRequestForCounts(it->get());
-      counts_by_request_.erase((*it)->request);
-    }
-    it = counts_.erase(it);
-  }
-
-  has_mixed_content_ = new_url_has_mixed_content;
-  page_url_ = url;
-  user_info_ = user_info;
-  estimate_start_index_ = 0;
-  is_loading_ = true;
-  previous_estimate_ = 0.0f;
-  new_estimate_round_ = true;
-  ReevaluateCallbacksForAllCounts();
-  Notify();
-}
-
-void RequestTrackerImpl::StopPageLoad(const GURL& url, bool load_success) {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-  DCHECK(page_url_ == GURLByRemovingRefFromGURL(url));
-  is_loading_ = false;
-}
-
-#pragma mark Internal utilities for task posting
-
-void RequestTrackerImpl::PostTask(const base::Closure& task,
-                                  web::WebThread::ID thread) {
-  // Absolute sanity test: |thread| is one of {UI, IO}
-  DCHECK(thread == web::WebThread::UI || thread == web::WebThread::IO);
-  // Check that we're on the counterpart thread to the one we're posting to.
-  DCHECK_CURRENTLY_ON(thread == web::WebThread::IO ? web::WebThread::UI
-                                                   : web::WebThread::IO);
-  // Don't post if the tracker is closing and we're on the IO thread.
-  // (there should be no way to call anything from the UI thread if
-  // the tracker is closing).
-  if (is_closing_ && web::WebThread::CurrentlyOn(web::WebThread::IO))
-    return;
-  base::PostTaskWithTraits(FROM_HERE, {thread}, task);
-}
-
-#pragma mark Other internal methods.
-
-NSString* RequestTrackerImpl::UnsafeDescription() {
-  DCHECK_CURRENTLY_ON(web::WebThread::IO);
-
-  NSMutableArray* urls = [NSMutableArray array];
-  for (const auto& tracker_count : counts_)
-    [urls addObject:tracker_count->Description()];
-
-  return [NSString stringWithFormat:@"RequestGroupID %@\n%@\n%@",
-                                    request_group_id_,
-                                    net::NSURLWithGURL(page_url_),
-                                    [urls componentsJoinedByString:@"\n"]];
-}
-
-void RequestTrackerImpl::SetCertificatePolicyCacheForTest(
-    web::CertificatePolicyCache* cache) {
-  policy_cache_ = cache;
-}
-
-}  // namespace web
diff --git a/ios/web/net/request_tracker_impl_unittest.mm b/ios/web/net/request_tracker_impl_unittest.mm
deleted file mode 100644
index 3a1e22c..0000000
--- a/ios/web/net/request_tracker_impl_unittest.mm
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright 2012 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/web/net/request_tracker_impl.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/sys_string_conversions.h"
-#include "ios/web/public/cert_policy.h"
-#include "ios/web/public/certificate_policy_cache.h"
-#include "ios/web/public/ssl_status.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "net/cert/x509_certificate.h"
-#include "net/http/http_response_headers.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_job_factory.h"
-#include "net/url_request/url_request_job_factory_impl.h"
-#include "net/url_request/url_request_test_job.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#include "third_party/ocmock/gtest_support.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface RequestTrackerNotificationReceiverTest : NSObject {
- @public
-  float value_;
-  float max_;
- @private
-  NSString* error_;
-  scoped_refptr<net::HttpResponseHeaders> headers_;
-}
-
-- (NSString*)error;
-- (net::HttpResponseHeaders*)headers;
-@end
-
-@implementation RequestTrackerNotificationReceiverTest
-
-- (id)init {
-  self = [super init];
-  if (self) {
-    value_ = 0.0f;
-    max_ = 0.0f;
-  }
-  return self;
-}
-
-- (NSString*)error {
-  return error_;
-}
-
-- (net::HttpResponseHeaders*)headers {
-  return headers_.get();
-}
-
-@end
-
-namespace {
-
-// Used and incremented each time a tabId is created.
-int g_count = 0;
-
-// URLRequest::Delegate that does nothing.
-class DummyURLRequestDelegate : public net::URLRequest::Delegate {
- public:
-  DummyURLRequestDelegate() {}
-  ~DummyURLRequestDelegate() override {}
-
-  void OnResponseStarted(net::URLRequest* request, int net_error) override {}
-  void OnReadCompleted(net::URLRequest* request, int bytes_read) override {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DummyURLRequestDelegate);
-};
-
-class RequestTrackerTest : public PlatformTest {
- public:
-  RequestTrackerTest()
-      : thread_bundle_(web::TestWebThreadBundle::IO_MAINLOOP) {}
-
-  ~RequestTrackerTest() override {}
-
-  void SetUp() override {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    request_group_id_ = [NSString stringWithFormat:@"test%d", g_count++];
-
-    tracker_ = web::RequestTrackerImpl::CreateTrackerForRequestGroupID(
-        request_group_id_, &browser_state_, browser_state_.GetRequestContext());
-  }
-
-  void TearDown() override {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    tracker_->Close();
-  }
-
-  web::TestWebThreadBundle thread_bundle_;
-
-  scoped_refptr<web::RequestTrackerImpl> tracker_;
-  NSString* request_group_id_;
-  web::TestBrowserState browser_state_;
-  std::vector<std::unique_ptr<net::URLRequestContext>> contexts_;
-  std::vector<std::unique_ptr<net::URLRequest>> requests_;
-  net::URLRequestJobFactoryImpl job_factory_;
-
-  GURL GetURL(size_t i) {
-    std::stringstream ss;
-    ss << "http://www/";
-    ss << i;
-    return GURL(ss.str());
-  }
-
-  GURL GetSecureURL(size_t i) {
-    std::stringstream ss;
-    ss << "https://www/";
-    ss << i;
-    return GURL(ss.str());
-  }
-
-  net::URLRequest* GetRequest(size_t i) {
-    return GetInternalRequest(i, false);
-  }
-
-  net::URLRequest* GetSecureRequest(size_t i) {
-    return GetInternalRequest(i, true);
-  }
-
-  NSString* WaitUntilLoop(bool (^condition)(void)) {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    base::Time maxDate = base::Time::Now() + base::TimeDelta::FromSeconds(10);
-    while (!condition()) {
-      if (base::Time::Now() > maxDate)
-        return @"Time is up, too slow to go";
-      base::RunLoop().RunUntilIdle();
-      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
-    }
-    return nil;
-  }
-
-  void TrimRequest(NSString* tab_id, const GURL& url) {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    tracker_->StartPageLoad(url, nil);
-  }
-
-  void EndPage(NSString* tab_id, const GURL& url) {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    tracker_->FinishPageLoad(url, false);
-    base::RunLoop().RunUntilIdle();
-  }
-
-  net::TestJobInterceptor* AddInterceptorToRequest(size_t i) {
-    // |interceptor| will be deleted from |job_factory_|'s destructor.
-    net::TestJobInterceptor* protocol_handler = new net::TestJobInterceptor();
-    job_factory_.SetProtocolHandler("http", base::WrapUnique(protocol_handler));
-    contexts_[i]->set_job_factory(&job_factory_);
-    return protocol_handler;
-  }
-
- private:
-  net::URLRequest* GetInternalRequest(size_t i, bool secure) {
-    GURL url;
-    if (secure)
-      url = GetSecureURL(requests_.size());
-    else
-      url = GetURL(requests_.size());
-
-    while (i >= requests_.size()) {
-      contexts_.push_back(std::make_unique<net::URLRequestContext>());
-      requests_.push_back(contexts_[i]->CreateRequest(
-          url, net::DEFAULT_PRIORITY, &request_delegate_));
-
-      if (secure) {
-        // Put a valid SSLInfo inside
-        net::HttpResponseInfo* response =
-            const_cast<net::HttpResponseInfo*>(&requests_[i]->response_info());
-
-        response->ssl_info.cert = net::ImportCertFromFile(
-            net::GetTestCertsDirectory(), "ok_cert.pem");
-        response->ssl_info.cert_status = 0;  // No errors.
-
-        EXPECT_TRUE(requests_[i]->ssl_info().is_valid());
-      }
-    }
-    EXPECT_TRUE(!secure == !requests_[i]->url().SchemeIsCryptographic());
-    return requests_[i].get();
-  }
-
-  DummyURLRequestDelegate request_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(RequestTrackerTest);
-};
-
-TEST_F(RequestTrackerTest, OnePage) {
-  // Start a request.
-  tracker_->StartRequest(GetRequest(0));
-  // Start page load.
-  TrimRequest(request_group_id_, GetURL(0));
-
-  // Stop the request.
-  tracker_->StopRequest(GetRequest(0));
-  EndPage(request_group_id_, GetURL(0));
-}
-
-TEST_F(RequestTrackerTest, OneSecurePage) {
-  net::URLRequest* request = GetSecureRequest(0);
-  GURL url = GetSecureURL(0);
-
-  // Start a page.
-  TrimRequest(request_group_id_, url);
-
-  // Start a request.
-  tracker_->StartRequest(request);
-  tracker_->CaptureReceivedBytes(request, 42);
-
-  // Stop the request.
-  tracker_->StopRequest(request);
-
-  EndPage(request_group_id_, url);
-}
-
-TEST_F(RequestTrackerTest, OnePageAndResources) {
-  // Start a page.
-  TrimRequest(request_group_id_, GetURL(0));
-  // Start two requests.
-  tracker_->StartRequest(GetRequest(0));
-  tracker_->StartRequest(GetRequest(1));
-
-  tracker_->StopRequest(GetRequest(0));
-  tracker_->StartRequest(GetRequest(2));
-  tracker_->StopRequest(GetRequest(1));
-  tracker_->StartRequest(GetRequest(3));
-
-  tracker_->StopRequest(GetRequest(2));
-  tracker_->StartRequest(GetRequest(4));
-
-  tracker_->StopRequest(GetRequest(3));
-  tracker_->StopRequest(GetRequest(4));
-  EndPage(request_group_id_, GetURL(0));
-}
-
-TEST_F(RequestTrackerTest, OnePageOneBigImage) {
-  // Start a page.
-  TrimRequest(request_group_id_, GetURL(0));
-  tracker_->StartRequest(GetRequest(0));
-  tracker_->StopRequest(GetRequest(0));
-  tracker_->StartRequest(GetRequest(1));
-
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureExpectedLength(GetRequest(1), 100);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->CaptureReceivedBytes(GetRequest(1), 10);
-  tracker_->StopRequest(GetRequest(1));
-  EndPage(request_group_id_, GetURL(0));
-}
-
-TEST_F(RequestTrackerTest, TwoPagesPostStart) {
-  tracker_->StartRequest(GetRequest(0));
-
-  TrimRequest(request_group_id_, GetURL(0));
-  tracker_->StartRequest(GetRequest(1));
-  tracker_->StartRequest(GetRequest(2));
-
-  tracker_->StopRequest(GetRequest(0));
-  tracker_->StopRequest(GetRequest(1));
-  tracker_->StopRequest(GetRequest(2));
-  EndPage(request_group_id_, GetURL(0));
-
-  tracker_->StartRequest(GetRequest(3));
-
-  TrimRequest(request_group_id_, GetURL(3));
-
-  tracker_->StopRequest(GetRequest(3));
-  EndPage(request_group_id_, GetURL(3));
-}
-
-TEST_F(RequestTrackerTest, TwoPagesPreStart) {
-  tracker_->StartRequest(GetRequest(0));
-
-  TrimRequest(request_group_id_, GetURL(0));
-  tracker_->StartRequest(GetRequest(1));
-  tracker_->StartRequest(GetRequest(2));
-
-  tracker_->StopRequest(GetRequest(0));
-  tracker_->StopRequest(GetRequest(1));
-  tracker_->StopRequest(GetRequest(2));
-  EndPage(request_group_id_, GetURL(0));
-
-  TrimRequest(request_group_id_, GetURL(3));
-  tracker_->StartRequest(GetRequest(3));
-  tracker_->StopRequest(GetRequest(3));
-  EndPage(request_group_id_, GetURL(3));
-}
-
-TEST_F(RequestTrackerTest, TwoPagesNoWait) {
-  tracker_->StartRequest(GetRequest(0));
-
-  TrimRequest(request_group_id_, GetURL(0));
-  tracker_->StartRequest(GetRequest(1));
-  tracker_->StartRequest(GetRequest(2));
-
-  tracker_->StopRequest(GetRequest(0));
-  tracker_->StopRequest(GetRequest(1));
-  tracker_->StopRequest(GetRequest(2));
-
-  TrimRequest(request_group_id_, GetURL(3));
-  tracker_->StartRequest(GetRequest(3));
-
-  tracker_->StopRequest(GetRequest(3));
-
-  EndPage(request_group_id_, GetURL(3));
-}
-
-// Do-nothing mock CertificatePolicyCache. Allows all certs for all hosts.
-class MockCertificatePolicyCache : public web::CertificatePolicyCache {
- public:
-  MockCertificatePolicyCache() {}
-
-  void AllowCertForHost(net::X509Certificate* cert,
-                        const std::string& host,
-                        net::CertStatus error) override {
-  }
-
-  web::CertPolicy::Judgment QueryPolicy(net::X509Certificate* cert,
-                                        const std::string& host,
-                                        net::CertStatus error) override {
-    return web::CertPolicy::Judgment::ALLOWED;
-  }
-
-  void ClearCertificatePolicies() override {
-  }
-
- private:
-  ~MockCertificatePolicyCache() override {}
-};
-
-void TwoStartsSSLCallback(bool* called, bool ok) {
-  *called = true;
-}
-
-// crbug/386180
-TEST_F(RequestTrackerTest, DISABLED_TwoStartsNoEstimate) {
-  net::SSLInfo ssl_info;
-  ssl_info.cert =
-      net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
-  ssl_info.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
-  scoped_refptr<MockCertificatePolicyCache> cache;
-  tracker_->SetCertificatePolicyCacheForTest(cache.get());
-  TrimRequest(request_group_id_, GetSecureURL(0));
-  tracker_->StartRequest(GetSecureRequest(0));
-  tracker_->StartRequest(GetSecureRequest(1));
-  bool request_0_called = false;
-  bool request_1_called = false;
-  tracker_->OnSSLCertificateError(GetSecureRequest(0), ssl_info, true,
-                                  base::Bind(&TwoStartsSSLCallback,
-                                             &request_0_called));
-  tracker_->OnSSLCertificateError(GetSecureRequest(1), ssl_info, true,
-                                  base::Bind(&TwoStartsSSLCallback,
-                                             &request_1_called));
-  EXPECT_TRUE(request_0_called);
-  EXPECT_TRUE(request_1_called);
-}
-
-}  // namespace
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.h b/ios/web_view/internal/signin/ios_web_view_signin_client.h
index 1e683fce..3e95a9dd 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.h
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.h
@@ -41,6 +41,7 @@
   void DoFinalInit() override;
   bool IsFirstRun() const override;
   bool AreSigninCookiesAllowed() override;
+  bool AreSigninCookiesDeletedOnExit() override;
   void AddContentSettingsObserver(
       content_settings::Observer* observer) override;
   void RemoveContentSettingsObserver(
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.mm b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
index 2d73cb00..2e22b4f4 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.mm
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
@@ -68,6 +68,10 @@
   return signin::SettingsAllowSigninCookies(cookie_settings_.get());
 }
 
+bool IOSWebViewSigninClient::AreSigninCookiesDeletedOnExit() {
+  return signin::SettingsDeleteSigninCookiesOnExit(cookie_settings_.get());
+}
+
 void IOSWebViewSigninClient::AddContentSettingsObserver(
     content_settings::Observer* observer) {
   host_content_settings_map_->AddObserver(observer);
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 2e364d0c..307ffda 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -481,9 +481,6 @@
     "PreloadMediaEngagementData", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-const base::Feature kMediaEngagementHTTPSOnly{
-    "MediaEngagementHTTPSOnly", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Enables experimental local learning for media.  Adds reporting only; does not
 // change media behavior.
 const base::Feature kMediaLearningExperiment{"MediaLearningExperiment",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 3bd59ea6..50f3a6e 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -110,7 +110,6 @@
 MEDIA_EXPORT extern const base::Feature kMediaCapabilitiesWithParameters;
 MEDIA_EXPORT extern const base::Feature kMediaCastOverlayButton;
 MEDIA_EXPORT extern const base::Feature kMediaEngagementBypassAutoplayPolicies;
-MEDIA_EXPORT extern const base::Feature kMediaEngagementHTTPSOnly;
 MEDIA_EXPORT extern const base::Feature kMediaLearningExperiment;
 MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC;
 MEDIA_EXPORT extern const base::Feature kNewEncodeCpuLoadEstimator;
diff --git a/mojo/public/cpp/base/big_buffer.cc b/mojo/public/cpp/base/big_buffer.cc
index 5311dd5..6c4eabfa 100644
--- a/mojo/public/cpp/base/big_buffer.cc
+++ b/mojo/public/cpp/base/big_buffer.cc
@@ -112,9 +112,11 @@
     if (buffer.is_valid()) {
       storage_type_ = BigBuffer::StorageType::kSharedMemory;
       shared_memory_.emplace(std::move(buffer), bytes.size());
-      std::copy(bytes.begin(), bytes.end(),
-                static_cast<uint8_t*>(shared_memory_->buffer_mapping_.get()));
-      return;
+      if (shared_memory_->buffer_mapping_) {
+        std::copy(bytes.begin(), bytes.end(),
+                  static_cast<uint8_t*>(shared_memory_->buffer_mapping_.get()));
+        return;
+      }
     }
 
     if (bytes.size() > kMaxFallbackInlineBytes) {
diff --git a/mojo/public/tools/bindings/README.md b/mojo/public/tools/bindings/README.md
index 2969459..4415039 100644
--- a/mojo/public/tools/bindings/README.md
+++ b/mojo/public/tools/bindings/README.md
@@ -558,6 +558,12 @@
 with the `MinVersion` attribute set to a number greater than any previous
 existing versions.
 
+*** note
+**NOTE:** do not change existing fields in versioned structs, as this is
+not backwards-compatible. Instead, rename the old field to make its
+deprecation clear and add a new field with the new version number.
+***
+
 **Ordinal value** refers to the relative positional layout of a struct's fields
 (and an interface's methods) when encoded in a message. Implicitly, ordinal
 numbers are assigned to fields according to lexical position. In the example
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 82aa071..699a618 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -5633,18 +5633,15 @@
 
   if (is_linux || is_mac || is_win || is_fuchsia) {
     deps += [
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/",
       "//third_party/tlslite/",
     ]
     data_deps += [
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/",
       "//third_party/tlslite/",
     ]
     data += [
       "tools/testserver/",
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
     ]
diff --git a/net/base/registry_controlled_domains/registry_controlled_domain_unittest.cc b/net/base/registry_controlled_domains/registry_controlled_domain_unittest.cc
index 1d23d6b..598feda 100644
--- a/net/base/registry_controlled_domains/registry_controlled_domain_unittest.cc
+++ b/net/base/registry_controlled_domains/registry_controlled_domain_unittest.cc
@@ -363,12 +363,22 @@
                              "http://..b.x.com/file.html"));   // x.com
   EXPECT_TRUE(CompareDomains("http://intranet/file.html",
                              "http://intranet/file.html"));    // intranet
+  EXPECT_FALSE(CompareDomains("http://intranet1/file.html",
+                              "http://intranet2/file.html"));  // intranet
+  EXPECT_TRUE(CompareDomains(
+      "http://intranet1.corp.example.com/file.html",
+      "http://intranet2.corp.example.com/file.html"));  // intranet
   EXPECT_TRUE(CompareDomains("http://127.0.0.1/file.html",
                              "http://127.0.0.1/file.html"));   // 127.0.0.1
   EXPECT_FALSE(CompareDomains("http://192.168.0.1/file.html",  // 192.168.0.1
                               "http://127.0.0.1/file.html"));  // 127.0.0.1
   EXPECT_FALSE(CompareDomains("file:///C:/file.html",
                               "file:///C:/file.html"));        // no host
+
+  // The trailing dot means different sites - see also
+  // https://github.com/mikewest/sec-metadata/issues/15.
+  EXPECT_FALSE(
+      CompareDomains("https://foo.example.com", "https://foo.example.com."));
 }
 
 TEST_F(RegistryControlledDomainTest, TestDefaultData) {
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 2a06c55..bbc13ab8 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -811,9 +811,19 @@
   }
 
  protected:
-  // The address of the spawned test server, after calling StartTestServer().
+  // The address of the test server, after calling StartEmbeddedTestServer() or
+  // StartTestServer().
   const AddressList& addr() const { return addr_; }
 
+  // The hostname of the test server, after calling StartEmbeddedTestServer() or
+  // StartTestServer().
+  const HostPortPair& host_port_pair() const { return host_port_pair_; }
+
+  // The EmbeddedTestServer object, after calling StartEmbeddedTestServer().
+  EmbeddedTestServer* embedded_test_server() {
+    return embedded_test_server_.get();
+  }
+
   // The SpawnedTestServer object, after calling StartTestServer().
   const SpawnedTestServer* spawned_test_server() const {
     return spawned_test_server_.get();
@@ -831,11 +841,39 @@
     context_.ct_policy_enforcer = policy_enforcer;
   }
 
-  // Starts the test server with SSL configuration |ssl_options|. Returns true
+  // Starts the embedded test server with the specified parameters. Returns true
   // on success.
+  bool StartEmbeddedTestServer(EmbeddedTestServer::ServerCertificate cert,
+                               const SSLServerConfig& server_config) {
+    spawned_test_server_ = nullptr;
+    embedded_test_server_ =
+        std::make_unique<EmbeddedTestServer>(EmbeddedTestServer::TYPE_HTTPS);
+    RegisterEmbeddedTestServerHandlers(embedded_test_server_.get());
+    embedded_test_server_->SetSSLConfig(cert, server_config);
+    if (!embedded_test_server_->Start()) {
+      LOG(ERROR) << "Could not start EmbeddedTestServer";
+      return false;
+    }
+
+    if (!embedded_test_server_->GetAddressList(&addr_)) {
+      LOG(ERROR) << "Could not get EmbeddedTestServer address list";
+      return false;
+    }
+    host_port_pair_ = embedded_test_server_->host_port_pair();
+    return true;
+  }
+
+  // May be overridden by the subclass to customize the EmbeddedTestServer.
+  virtual void RegisterEmbeddedTestServerHandlers(EmbeddedTestServer* server) {
+    server->AddDefaultHandlers(base::FilePath());
+  }
+
+  // Starts the spawned test server with SSL configuration |ssl_options|.
+  // Returns true on success. Prefer StartEmbeddedTestServer().
   bool StartTestServer(const SpawnedTestServer::SSLOptions& ssl_options) {
-    spawned_test_server_.reset(new SpawnedTestServer(
-        SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath()));
+    embedded_test_server_ = nullptr;
+    spawned_test_server_ = std::make_unique<SpawnedTestServer>(
+        SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
     if (!spawned_test_server_->Start()) {
       LOG(ERROR) << "Could not start SpawnedTestServer";
       return false;
@@ -845,6 +883,7 @@
       LOG(ERROR) << "Could not get SpawnedTestServer address list";
       return false;
     }
+    host_port_pair_ = spawned_test_server_->host_port_pair();
     return true;
   }
 
@@ -890,8 +929,8 @@
 
   bool CreateAndConnectSSLClientSocket(const SSLConfig& ssl_config,
                                        int* result) {
-    return CreateAndConnectSSLClientSocketWithHost(
-        ssl_config, spawned_test_server()->host_port_pair(), result);
+    return CreateAndConnectSSLClientSocketWithHost(ssl_config, host_port_pair(),
+                                                   result);
   }
 
   // Adds the server certificate with provided cert status.
@@ -921,8 +960,10 @@
 
  private:
   std::unique_ptr<SpawnedTestServer> spawned_test_server_;
+  std::unique_ptr<EmbeddedTestServer> embedded_test_server_;
   TestCompletionCallback callback_;
   AddressList addr_;
+  HostPortPair host_port_pair_;
 };
 
 enum ReadIfReadyTransport {
@@ -1278,30 +1319,20 @@
   SSLClientSocketZeroRTTTest() : SSLClientSocketTest() {}
 
   bool StartServer() {
-    test_server_.reset(
-        new EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
     SSLServerConfig server_config;
     server_config.early_data_enabled = true;
     server_config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
-    test_server_->AddDefaultHandlers(base::FilePath());
-    test_server_->RegisterRequestHandler(
-        base::BindRepeating(&HandleZeroRTTRequest));
-    test_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK, server_config);
-    if (!test_server_->Start()) {
-      LOG(ERROR) << "Could not start EmbeddedTestServer";
-      return false;
-    }
+    return StartEmbeddedTestServer(EmbeddedTestServer::CERT_OK, server_config);
+  }
 
-    if (!test_server_->GetAddressList(&address_)) {
-      LOG(ERROR) << "Could not get EmbeddedTestServer address list";
-      return false;
-    }
-    return true;
+  void RegisterEmbeddedTestServerHandlers(EmbeddedTestServer* server) override {
+    SSLClientSocketTest::RegisterEmbeddedTestServerHandlers(server);
+    server->RegisterRequestHandler(base::BindRepeating(&HandleZeroRTTRequest));
   }
 
   void SetServerConfig(SSLServerConfig server_config) {
-    test_server_->ResetSSLConfig(net::EmbeddedTestServer::CERT_OK,
-                                 server_config);
+    embedded_test_server()->ResetSSLConfig(net::EmbeddedTestServer::CERT_OK,
+                                           server_config);
   }
 
   FakeBlockingStreamSocket* MakeClient(bool early_data_enabled) {
@@ -1310,7 +1341,7 @@
     ssl_config.early_data_enabled = early_data_enabled;
 
     real_transport_.reset(
-        new TCPClientSocket(address_, nullptr, nullptr, NetLogSource()));
+        new TCPClientSocket(addr(), nullptr, nullptr, NetLogSource()));
     std::unique_ptr<FakeBlockingStreamSocket> transport(
         new FakeBlockingStreamSocket(std::move(real_transport_)));
     FakeBlockingStreamSocket* raw_transport = transport.get();
@@ -1318,8 +1349,8 @@
     int rv = callback_.GetResult(transport->Connect(callback_.callback()));
     EXPECT_THAT(rv, IsOk());
 
-    ssl_socket_ = CreateSSLClientSocket(
-        std::move(transport), test_server_->host_port_pair(), ssl_config);
+    ssl_socket_ = CreateSSLClientSocket(std::move(transport), host_port_pair(),
+                                        ssl_config);
     EXPECT_FALSE(ssl_socket_->IsConnected());
 
     return raw_transport;
@@ -1371,8 +1402,6 @@
   SSLClientSocket* ssl_socket() { return ssl_socket_.get(); }
 
  private:
-  std::unique_ptr<EmbeddedTestServer> test_server_;
-  AddressList address_;
   TestCompletionCallback callback_;
   std::unique_ptr<StreamSocket> real_transport_;
   std::unique_ptr<SSLClientSocket> ssl_socket_;
diff --git a/ppapi/examples/url_loader/README_chrome_developer.txt b/ppapi/examples/url_loader/README_chrome_developer.txt
index c9a6721..6bab676 100644
--- a/ppapi/examples/url_loader/README_chrome_developer.txt
+++ b/ppapi/examples/url_loader/README_chrome_developer.txt
@@ -5,12 +5,10 @@
 In the "src" directory, start the test server:
 
   On Linux:
-    export PYTHONPATH=third_party/pyftpdlib:third_party/tlslite:third_party
-    python net/tools/testserver/testserver.py --port=1337 --data-dir=ppapi/examples/url_loader
+    vpython net/tools/testserver/testserver.py --port=1337 --data-dir=ppapi/examples/url_loader
 
   On Windows:
-    set PYTHONPATH=third_party\pyftpdlib;third_party\tlslite:third_party
-    python net/tools/testserver/testserver.py --port=1337 --data-dir=ppapi/examples/url_loader
+    vpython net/tools/testserver/testserver.py --port=1337 --data-dir=ppapi/examples/url_loader
 
 Then load the page:
 
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index db04563..b7dbe0e 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -252,6 +252,8 @@
       id = webrtc::kFullDesktopScreenId;
     }
   }
+  LOG(INFO) << "SelectDesktopDisplay " << id << " from '" << select_display.id()
+            << "'";
   video_stream_->SelectSource(id);
   show_display_id_ = id;
 }
@@ -490,6 +492,7 @@
                                        const webrtc::DesktopSize& size,
                                        const webrtc::DesktopVector& dpi) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  LOG(INFO) << "ClientSession::OnVideoSizeChanged";
   webrtc::DesktopVector origin;
   if (show_display_id_ != webrtc::kFullDesktopScreenId) {
     origin = desktop_display_info_.CalcDisplayOffset(show_display_id_);
@@ -497,18 +500,29 @@
   mouse_clamping_filter_.set_output_offset(origin);
   mouse_clamping_filter_.set_output_size(size);
 
+  // Record default DPI in case a display reports 0 for DPI.
+  default_x_dpi_ = dpi.x();
+  default_y_dpi_ = dpi.y();
+
   switch (connection_->session()->config().protocol()) {
     case protocol::SessionConfig::Protocol::ICE:
+      LOG(INFO) << "   ICE input size (pixels): " << size.width() << "x"
+                << size.height() << " @ " << dpi.x() << "," << dpi.y();
       mouse_clamping_filter_.set_input_size(webrtc::DesktopSize(size));
       break;
 
     case protocol::SessionConfig::Protocol::WEBRTC: {
+      LOG(INFO) << "   WebRTC input size (pixels): " << size.width() << "x"
+                << size.height() << " @ " << dpi.x() << "," << dpi.y();
       // When using WebRTC protocol the client sends mouse coordinates in DIPs,
       // while InputInjector expects them in physical pixels.
       // TODO(sergeyu): Fix InputInjector implementations to use DIPs as well.
       webrtc::DesktopSize size_dips =
           DesktopDisplayInfo::CalcSizeDips(size, dpi.x(), dpi.y());
       mouse_clamping_filter_.set_input_size(webrtc::DesktopSize(size_dips));
+      LOG(INFO) << "   DPI: " << dpi.x() << "," << dpi.y();
+      LOG(INFO) << "   WebRTC input size (DIPS): " << size_dips.width() << "x"
+                << size_dips.height();
 
       // Generate and send VideoLayout message.
       protocol::VideoLayout layout;
@@ -520,6 +534,10 @@
       video_track->set_x_dpi(dpi.x());
       video_track->set_y_dpi(dpi.y());
 
+      LOG(INFO) << "  VideoLayout Desktop (DIPS) = 0,0 " << size_dips.width()
+                << "x" << size_dips.height() << " [" << dpi.x() << ","
+                << dpi.y() << "]";
+
       // VideoLayout can be sent only after the control channel is connected.
       // TODO(sergeyu): Change client_stub() implementation to allow queuing
       // while connection is being established.
@@ -535,7 +553,7 @@
 
 void ClientSession::OnDesktopDisplayChanged(
     std::unique_ptr<protocol::VideoLayout> displays) {
-  LOG(INFO) << "OnDesktopDisplayChanged";
+  LOG(INFO) << "ClientSession::OnDesktopDisplayChanged";
   // Scan display list to calculate the full desktop size.
   int min_x = 0;
   int max_x = 0;
@@ -543,9 +561,14 @@
   int max_y = 0;
   int dpi_x = 0;
   int dpi_y = 0;
+  LOG(INFO) << "  Scanning display info...";
   for (int display_id = 0; display_id < displays->video_track_size();
        display_id++) {
     protocol::VideoTrackLayout track = displays->video_track(display_id);
+    LOG(INFO) << "   #" << display_id << " : " << track.position_x() << ","
+              << track.position_y() << " " << track.width() << "x"
+              << track.height() << " [" << track.x_dpi() << "," << track.y_dpi()
+              << "]";
     if (dpi_x == 0)
       dpi_x = track.x_dpi();
     if (dpi_y == 0)
@@ -564,6 +587,12 @@
     }
   }
 
+  // TODO(garykac): Investigate why these DPI values are 0 for some users.
+  if (dpi_x == 0)
+    dpi_x = default_x_dpi_;
+  if (dpi_y == 0)
+    dpi_y = default_y_dpi_;
+
   // Calc desktop scaled geometry (in DIPs)
   // See comment in OnVideoSizeChanged() for details.
   const webrtc::DesktopSize size(max_x - min_x, max_y - min_y);
@@ -608,8 +637,8 @@
 
     protocol::VideoTrackLayout* video_track = layout.add_video_track();
     video_track->CopyFrom(display);
-    LOG(INFO) << "  Display " << display_id << " " << display.position_x()
-              << "," << display.position_y() << display.width() << "x"
+    LOG(INFO) << "  Display " << display_id << " = " << display.position_x()
+              << "," << display.position_y() << " " << display.width() << "x"
               << display.height() << " [" << display.x_dpi() << ","
               << display.y_dpi() << "]";
   }
diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h
index 618d5cd..229ffd531e 100644
--- a/remoting/host/client_session.h
+++ b/remoting/host/client_session.h
@@ -252,6 +252,10 @@
   // Contains the most recently gathered info about the desktop displays;
   DesktopDisplayInfo desktop_display_info_;
 
+  // Default DPI values to use if a display reports 0 for DPI.
+  int default_x_dpi_;
+  int default_y_dpi_;
+
   // The id of the desktop display to show to the user.
   // Default is webrtc::kFullDesktopScreenId which shows all displays.
   webrtc::ScreenId show_display_id_ = webrtc::kFullDesktopScreenId;
diff --git a/remoting/host/desktop_capturer_proxy.cc b/remoting/host/desktop_capturer_proxy.cc
index 3aa5e5f8..3873154 100644
--- a/remoting/host/desktop_capturer_proxy.cc
+++ b/remoting/host/desktop_capturer_proxy.cc
@@ -217,6 +217,7 @@
       desktop_display_info_ = std::move(info);
 
       auto layout = std::make_unique<protocol::VideoLayout>();
+      LOG(INFO) << "DCP::OnFrameCaptured";
       for (auto display : desktop_display_info_->displays()) {
         protocol::VideoTrackLayout* track = layout->add_video_track();
         track->set_position_x(display.x);
@@ -225,6 +226,9 @@
         track->set_height(display.height);
         track->set_x_dpi(display.dpi);
         track->set_y_dpi(display.dpi);
+        LOG(INFO) << "   Display: " << display.x << "," << display.y << " "
+                  << display.width << "x" << display.height << " @ "
+                  << display.dpi;
       }
       client_session_control_->OnDesktopDisplayChanged(std::move(layout));
     }
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index 71c7dc64..6398a6f 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -286,6 +286,13 @@
 
 void DesktopSessionAgent::OnDesktopDisplayChanged(
     std::unique_ptr<protocol::VideoLayout> layout) {
+  LOG(INFO) << "DSA::OnDesktopDisplayChanged";
+  for (int display_id = 0; display_id < layout->video_track_size();
+       display_id++) {
+    protocol::VideoTrackLayout track = layout->video_track(display_id);
+    LOG(INFO) << "   #" << display_id << " : "
+              << " [" << track.x_dpi() << "," << track.y_dpi() << "]";
+  }
   SendToNetwork(std::make_unique<ChromotingDesktopNetworkMsg_DisplayChanged>(
       *layout.get()));
 }
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 598eb29..d6c1683 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -539,6 +539,13 @@
 void DesktopSessionProxy::OnDesktopDisplayChanged(
     const protocol::VideoLayout& displays) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
+  LOG(INFO) << "DSP::OnDesktopDisplayChanged";
+  for (int display_id = 0; display_id < displays.video_track_size();
+       display_id++) {
+    protocol::VideoTrackLayout track = displays.video_track(display_id);
+    LOG(INFO) << "   #" << display_id << " : "
+              << " [" << track.x_dpi() << "," << track.y_dpi() << "]";
+  }
 
   if (client_session_control_) {
     auto layout = std::make_unique<protocol::VideoLayout>();
diff --git a/remoting/protocol/mouse_input_filter.cc b/remoting/protocol/mouse_input_filter.cc
index 9ceb67f..c1de6eb3 100644
--- a/remoting/protocol/mouse_input_filter.cc
+++ b/remoting/protocol/mouse_input_filter.cc
@@ -49,14 +49,20 @@
 
 void MouseInputFilter::set_input_size(const webrtc::DesktopSize& size) {
   input_size_ = webrtc::DesktopSize(size.width() - 1, size.height() - 1);
+  LOG(INFO) << "Setting MouseInputFilter input_size to " << input_size_.width()
+            << "x" << input_size_.height();
 }
 
 void MouseInputFilter::set_output_size(const webrtc::DesktopSize& size) {
   output_size_ = webrtc::DesktopSize(size.width() - 1, size.height() - 1);
+  LOG(INFO) << "Setting MouseInputFilter output_size to "
+            << output_size_.width() << "x" << output_size_.height();
 }
 
 void MouseInputFilter::set_output_offset(const webrtc::DesktopVector& v) {
   output_offset_ = webrtc::DesktopVector(v.x(), v.y());
+  LOG(INFO) << "Setting MouseInputFilter output_offset to "
+            << output_offset_.x() << "," << output_offset_.y();
 }
 
 }  // namespace protocol
diff --git a/sandbox/mac/BUILD.gn b/sandbox/mac/BUILD.gn
index d114782..cbf9488 100644
--- a/sandbox/mac/BUILD.gn
+++ b/sandbox/mac/BUILD.gn
@@ -69,7 +69,6 @@
   sources = [
     "mojom/struct_traits_unittest.cc",
     "sandbox_mac_compiler_unittest.mm",
-    "sandbox_mac_compiler_v2_unittest.mm",
     "sandbox_mac_seatbelt_exec_unittest.cc",
     "seatbelt_extension_unittest.cc",
   ]
diff --git a/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm b/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm
deleted file mode 100644
index 64eae5e..0000000
--- a/sandbox/mac/sandbox_mac_compiler_v2_unittest.mm
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-#import <IOSurface/IOSurface.h>
-
-#include <fcntl.h>
-#include <servers/bootstrap.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/mac/mac_util.h"
-#include "base/process/kill.h"
-#include "base/test/multiprocess_test.h"
-#include "base/test/test_timeouts.h"
-#include "sandbox/mac/sandbox_compiler.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/multiprocess_func_list.h"
-
-namespace sandbox {
-
-// These tests are designed to begin testing the V2 style sandbox rules on the
-// bots, rendering the earliest possible test results on how the rules perform
-// consistently across all test bots and supported OS versions.
-class SandboxMacCompilerV2Test : public base::MultiProcessTest {};
-
-MULTIPROCESS_TEST_MAIN(V2ProfileProcess) {
-  // Note: newlines are not necessary in the profile, but do make it easier to
-  // print the profile out for debugging purposes.
-  std::string profile =
-      "(version 1)\n"
-      "(deny default (with no-log))\n"
-      "(define allowed-dir \"ALLOWED_READ_DIR\")\n"
-      "(define temp-file \"ALLOWED_TEMP_FILE\")\n"
-      "(define is-pre-10_10 \"IS_PRE_10_10\")\n"
-      "(define zone-tab \"ZONE_TAB\")\n"
-      "; Make it easier to drop (literal) once we stop supporting 10.9\n"
-      "(define (path x) (literal x))\n"
-      "(allow file-read-metadata (subpath \"/\"))\n"
-      "(allow file-read* (subpath (param allowed-dir)))\n"
-      "(allow file-read-data (path (param zone-tab)))\n"
-      "(allow file-write* (path (param temp-file)))\n"
-      "(allow ipc-posix-shm-read-data (ipc-posix-name "
-      "\"apple.shm.notification_center\"))\n"
-      "(allow mach-lookup (global-name \"com.apple.system.logger\"))\n"
-      "(if (string=? (param is-pre-10_10) \"TRUE\") (allow sysctl-read))\n"
-      "(if (string=? (param is-pre-10_10) \"FALSE\") (allow sysctl-read "
-      "(sysctl-name \"hw.activecpu\")))\n";
-
-  std::string temp_file_path = "/private/tmp/sf234234wfsfsdfdsf";
-  SandboxCompiler compiler(profile);
-  CHECK(compiler.InsertStringParam("ALLOWED_READ_DIR", "/usr/lib"));
-  CHECK(compiler.InsertStringParam("ALLOWED_TEMP_FILE", temp_file_path));
-  CHECK(compiler.InsertBooleanParam("IS_PRE_10_10",
-                                    !base::mac::IsAtLeastOS10_10()));
-
-  // crbug.com/748517: The zoneinfo folder is a symlink on 10.13.
-  base::FilePath zone_tab_path("/usr/share/zoneinfo/zone.tab");
-  zone_tab_path = base::MakeAbsoluteFilePath(zone_tab_path);
-  CHECK(compiler.InsertStringParam("ZONE_TAB", zone_tab_path.value()));
-
-  std::string error;
-  bool result = compiler.CompileAndApplyProfile(&error);
-  CHECK(result) << error;
-
-  // Now attempt the appropriate resource access.
-  base::FilePath path("/usr/lib/libsandbox.dylib");
-  base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-  CHECK(file.IsValid());
-
-  char buf[4096];
-  CHECK_EQ(static_cast<int>(sizeof(buf)),
-           file.Read(/*offset=*/0, buf, sizeof(buf)));
-  file.Close();  // Protect again other checks accidentally using this file.
-
-  struct stat sb;
-  CHECK_EQ(0, stat("/Applications/TextEdit.app", &sb));
-
-  base::FilePath zone_path("/usr/share/zoneinfo/zone.tab");
-  base::File zone_file(zone_path,
-                       base::File::FLAG_OPEN | base::File::FLAG_READ);
-  CHECK(zone_file.IsValid());
-
-  char zone_buf[2];
-  CHECK_EQ(static_cast<int>(sizeof(zone_buf)),
-           zone_file.Read(/*offset=*/0, zone_buf, sizeof(zone_buf)));
-  zone_file.Close();
-
-  // Make sure we cannot read any files in zoneinfo.
-  base::FilePath zone_dir_path("/usr/share/zoneinfo");
-  base::File zoneinfo(zone_dir_path,
-                      base::File::FLAG_OPEN | base::File::FLAG_READ);
-  CHECK(!zoneinfo.IsValid());
-
-  base::FilePath temp_path(temp_file_path);
-  base::File temp_file(temp_path,
-                       base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE);
-  CHECK(temp_file.IsValid());
-
-  const char msg[] = "I can write this file.";
-  CHECK_EQ(static_cast<int>(sizeof(msg)),
-           temp_file.WriteAtCurrentPos(msg, sizeof(msg)));
-  temp_file.Close();
-
-  int shm_fd = shm_open("apple.shm.notification_center", O_RDONLY, 0644);
-  CHECK_GE(shm_fd, 0);
-
-  // Test mach service access. The port is leaked because the multiprocess
-  // test exits quickly after this look up.
-  mach_port_t service_port;
-  kern_return_t status = bootstrap_look_up(
-      bootstrap_port, "com.apple.system.logger", &service_port);
-  CHECK_EQ(status, BOOTSTRAP_SUCCESS) << bootstrap_strerror(status);
-
-  mach_port_t forbidden_mach;
-  status = bootstrap_look_up(bootstrap_port, "com.apple.cfprefsd.daemon",
-                             &forbidden_mach);
-  CHECK_NE(BOOTSTRAP_SUCCESS, status);
-
-  size_t oldp_len;
-  CHECK_EQ(0, sysctlbyname("hw.activecpu", NULL, &oldp_len, NULL, 0));
-
-  char oldp[oldp_len];
-  CHECK_EQ(0, sysctlbyname("hw.activecpu", oldp, &oldp_len, NULL, 0));
-
-  // sysctl filtering only exists on macOS 10.10+.
-  if (base::mac::IsAtLeastOS10_10()) {
-    size_t ncpu_len;
-    CHECK_NE(0, sysctlbyname("hw.ncpu", NULL, &ncpu_len, NULL, 0));
-  }
-
-  return 0;
-}
-
-TEST_F(SandboxMacCompilerV2Test, V2ProfileTest) {
-  base::Process process = SpawnChild("V2ProfileProcess");
-  ASSERT_TRUE(process.IsValid());
-  int exit_code = 42;
-  EXPECT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
-                                             &exit_code));
-  EXPECT_EQ(exit_code, 0);
-}
-
-}  // namespace sandbox
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 9161d5e3..eb12610 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -127,6 +127,8 @@
     "resource_scheduler_params_manager.h",
     "restricted_cookie_manager.cc",
     "restricted_cookie_manager.h",
+    "sec_fetch_site.cc",
+    "sec_fetch_site.h",
     "session_cleanup_cookie_store.cc",
     "session_cleanup_cookie_store.h",
     "socket_data_pump.cc",
@@ -350,7 +352,6 @@
     data = [
       "//net/tools/testserver/",
       "//services/test/data",
-      "//third_party/pyftpdlib/",
       "//third_party/pywebsocket/src/mod_pywebsocket/",
       "//third_party/tlslite/",
     ]
diff --git a/services/network/OWNERS b/services/network/OWNERS
index c99bfa7a3..51949fa 100644
--- a/services/network/OWNERS
+++ b/services/network/OWNERS
@@ -16,6 +16,9 @@
 per-file cross_origin_read_blocking*=lukasza@chromium.org
 per-file cross_origin_resource_policy*=creis@chromium.org
 per-file cross_origin_resource_policy*=lukasza@chromium.org
+per-file sec_fetch_site*=creis@chromium.org
+per-file sec_fetch_site*=lukasza@chromium.org
+per-file sec_fetch_site*=mkwst@chromium.org
 
 per-file expect_ct_reporter*=estark@chromium.org
 
diff --git a/services/network/initiator_lock_compatibility.cc b/services/network/initiator_lock_compatibility.cc
index 76455f7..0f8de645 100644
--- a/services/network/initiator_lock_compatibility.cc
+++ b/services/network/initiator_lock_compatibility.cc
@@ -26,9 +26,21 @@
   const url::Origin& lock = request_initiator_site_lock.value();
 
   if (!request_initiator.has_value()) {
-    // This should only happen for the browser process (or if NetworkService is
-    // not enabled).
-    DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+      // SECURITY CHECK: Renderer processes should always provide a
+      // |request_initiator|.  Similarly, browser-side features acting on
+      // behalf of a renderer process (like AppCache), should always provide a
+      // |request_initiator|.
+      //
+      // Callers associated with features (e.g. Sec-Fetch-Site) that may handle
+      // browser-initiated requests (e.g. navigations and/or SafeBrowsing
+      // traffic) need to take extra care to avoid calling
+      // VerifyRequestInitiatorLock (and/or GetTrustworthyInitiator) with no
+      // |request_initiator|.  Such features should return early when handling
+      // request with no |request_initiator| but only when the request comes
+      // through a URLLoaderFactory associated with kBrowserProcessId.
+      CHECK(false);
+    }
     return InitiatorLockCompatibility::kNoInitiator;
   }
   const url::Origin& initiator = request_initiator.value();
@@ -42,10 +54,8 @@
   // TODO(lukasza, nasko): https://crbug.com/888079: Return kIncorrectLock if
   // the origins do not match exactly in the previous if statement.  This should
   // be possible to do once we no longer fall back to site_url and have
-  // request_initiator_*origin*_lock instead.  The fallback will go away after:
-  // - We have precursor origins: https://crbug.com/888079
-  // and
-  // - We no longer vend process-wide factory: https://crbug.com/891872
+  // request_initiator_*origin*_lock instead.  In practice, the fallback can go
+  // away after we no longer vend process-wide factory: https://crbug.com/891872
   if (!initiator.opaque() && !lock.opaque() &&
       initiator.scheme() == lock.scheme() &&
       initiator.GetURL().SchemeIsHTTPOrHTTPS() &&
diff --git a/services/network/sec_fetch_site.cc b/services/network/sec_fetch_site.cc
new file mode 100644
index 0000000..58c6b07c
--- /dev/null
+++ b/services/network/sec_fetch_site.cc
@@ -0,0 +1,118 @@
+// 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 "services/network/sec_fetch_site.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/feature_list.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/url_request/url_request.h"
+#include "services/network/initiator_lock_compatibility.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+
+namespace network {
+
+namespace {
+
+bool IsSameSite(const url::Origin& initiator,
+                const url::Origin& target_origin) {
+  return net::registry_controlled_domains::SameDomainOrHost(
+      initiator, target_origin,
+      net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+}
+
+// Possible values of Sec-Fetch-Site header.
+//
+// Note that the order of enum values below is significant - it is important for
+// std::max invocations that kSameOrigin < kSameSite < kCrossSite.
+enum class HeaderValue {
+  kNoOrigin,
+  kSameOrigin,
+  kSameSite,
+  kCrossSite,
+};
+
+HeaderValue CalculateHeaderValue(const GURL& target_url,
+                                 const url::Origin& initiator) {
+  url::Origin target_origin = url::Origin::Create(target_url);
+
+  if (target_origin == initiator)
+    return HeaderValue::kSameOrigin;
+
+  if (IsSameSite(initiator, target_origin))
+    return HeaderValue::kSameSite;
+
+  return HeaderValue::kCrossSite;
+}
+
+HeaderValue CalculateHeaderValue(
+    const net::URLRequest& request,
+    const GURL* pending_redirect_url,
+    const mojom::URLLoaderFactoryParams& factory_params) {
+  // Use `Sec-Fetch-Site: none` for browser-initiated requests with no
+  // initiator origin.
+  if (factory_params.process_id == mojom::kBrowserProcessId &&
+      !request.initiator().has_value()) {
+    return HeaderValue::kNoOrigin;
+  }
+
+  // Otherwise, calculate the |header_value| by comparing the initiator with the
+  // full chain of request URLs.
+  HeaderValue header_value = HeaderValue::kSameOrigin;
+  url::Origin initiator = GetTrustworthyInitiator(
+      factory_params.request_initiator_site_lock, request);
+  for (const GURL& target_url : request.url_chain()) {
+    header_value =
+        std::max(header_value, CalculateHeaderValue(target_url, initiator));
+  }
+  if (pending_redirect_url) {
+    header_value = std::max(
+        header_value, CalculateHeaderValue(*pending_redirect_url, initiator));
+  }
+  return header_value;
+}
+
+const char* GetHeaderString(const HeaderValue& value) {
+  switch (value) {
+    case HeaderValue::kNoOrigin:
+      return "none";
+    case HeaderValue::kSameOrigin:
+      return "same-origin";
+    case HeaderValue::kSameSite:
+      return "same-site";
+    case HeaderValue::kCrossSite:
+      return "cross-site";
+  }
+}
+
+}  // namespace
+
+void SetSecFetchSiteHeader(
+    net::URLRequest* request,
+    const GURL* pending_redirect_url,
+    const mojom::URLLoaderFactoryParams& factory_params) {
+  DCHECK(request);
+  DCHECK_NE(0u, request->url_chain().size());
+  if (!base::FeatureList::IsEnabled(features::kFetchMetadata))
+    return;
+
+  // Only append the header to potentially trustworthy URLs.
+  const GURL& target_url =
+      pending_redirect_url ? *pending_redirect_url : request->url();
+  if (!IsUrlPotentiallyTrustworthy(target_url))
+    return;
+
+  // Set the request header.
+  const char kHeaderName[] = "Sec-Fetch-Site";
+  HeaderValue header_value =
+      CalculateHeaderValue(*request, pending_redirect_url, factory_params);
+  request->SetExtraRequestHeaderByName(
+      kHeaderName, GetHeaderString(header_value), /* overwrite = */ true);
+}
+
+}  // namespace network
diff --git a/services/network/sec_fetch_site.h b/services/network/sec_fetch_site.h
new file mode 100644
index 0000000..61a6a76
--- /dev/null
+++ b/services/network/sec_fetch_site.h
@@ -0,0 +1,38 @@
+// 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 SERVICES_NETWORK_SEC_FETCH_SITE_H_
+#define SERVICES_NETWORK_SEC_FETCH_SITE_H_
+
+#include "base/component_export.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequest;
+}  // namespace net
+
+namespace network {
+
+namespace mojom {
+class URLLoaderFactoryParams;
+}  // namespace mojom
+
+// Sets the right Sec-Fetch-Site request header on |request|, comparing the
+// origins of |request.url_chain()| and |pending_redirect_url| against
+// |request.initiator()|.
+//
+// Note that |pending_redirect_url| is optional - it should be set only when
+// calling this method from net::URLRequest::Delegate::OnReceivedRedirect (in
+// this case |request.url_chain()| won't yet contain the URL being redirected
+// to).
+//
+// Spec: https://mikewest.github.io/sec-metadata/#sec-fetch-site-header
+COMPONENT_EXPORT(NETWORK_SERVICE)
+void SetSecFetchSiteHeader(net::URLRequest* request,
+                           const GURL* pending_redirect_url,
+                           const mojom::URLLoaderFactoryParams& factory_params);
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_SEC_FETCH_SITE_H_
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index df687e6..536d17a 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -48,6 +48,7 @@
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "services/network/resource_scheduler_client.h"
+#include "services/network/sec_fetch_site.h"
 #include "services/network/throttling/scoped_throttling_token.h"
 
 namespace network {
@@ -405,6 +406,8 @@
 
   url_request_->set_initiator(request.request_initiator);
 
+  SetSecFetchSiteHeader(url_request_.get(), nullptr, *factory_params_);
+
   if (request.update_first_party_url_on_redirect) {
     url_request_->set_first_party_url_policy(
         net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
@@ -730,6 +733,9 @@
     return;
   }
 
+  SetSecFetchSiteHeader(url_request_.get(), &redirect_info.new_url,
+                        *factory_params_);
+
   url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
 }
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 9115093b..56dd6b6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -861,6 +861,26 @@
             ]
         }
     ],
+    "AutofillRejectCompanyBirthyear": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillRejectCompanyBirthyear"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillSaveCreditCardUsesStrikeSystemV2": [
         {
             "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 2f1abc9c..7ff6e4e 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -181,7 +181,6 @@
 /pthreads-win32
 /py_trace_event/src
 /pyelftools
-/pyftpdlib/src
 /pylib
 /pymox/src
 /python_24
diff --git a/third_party/blink/public/web/web_text_check_client.h b/third_party/blink/public/web/web_text_check_client.h
index cb8c59f..7d85f0a0 100644
--- a/third_party/blink/public/web/web_text_check_client.h
+++ b/third_party/blink/public/web/web_text_check_client.h
@@ -5,13 +5,14 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_TEXT_CHECK_CLIENT_H_
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_TEXT_CHECK_CLIENT_H_
 
+#include <memory>
+
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/public/web/web_text_checking_completion.h"
 
 namespace blink {
 
-class WebTextCheckingCompletion;
-
 class WebTextCheckClient {
  public:
   // Returns the Chromium setting of whether spell-checking is enabled.
@@ -32,7 +33,7 @@
   // returned by passed completion object.
   virtual void RequestCheckingOfText(
       const WebString& text_to_check,
-      WebTextCheckingCompletion* completion_callback) {}
+      std::unique_ptr<WebTextCheckingCompletion> completion_callback) {}
 
  protected:
   virtual ~WebTextCheckClient() = default;
diff --git a/third_party/blink/public/web/web_text_checking_completion.h b/third_party/blink/public/web/web_text_checking_completion.h
index 521e857..08122a3 100644
--- a/third_party/blink/public/web/web_text_checking_completion.h
+++ b/third_party/blink/public/web/web_text_checking_completion.h
@@ -45,9 +45,7 @@
   virtual void DidFinishCheckingText(
       const WebVector<WebTextCheckingResult>&) = 0;
   virtual void DidCancelCheckingText() {}
-
- protected:
-  ~WebTextCheckingCompletion() = default;
+  virtual ~WebTextCheckingCompletion() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/DEPS b/third_party/blink/renderer/DEPS
index eb3e573..f7983fe 100644
--- a/third_party/blink/renderer/DEPS
+++ b/third_party/blink/renderer/DEPS
@@ -10,6 +10,7 @@
     "+base/feature_list.h",
     "+base/format_macros.h",
     "+base/gtest_prod_util.h",
+    "+base/hash/hash.h",
     "+base/location.h",
     "+base/logging.h",
     "+base/macros.h",
diff --git a/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl b/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl
index 7b4a4578..b5c346e 100644
--- a/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl
@@ -29,7 +29,7 @@
   return element && Is{{tag.interface}}(*element);
 }
 inline bool Is{{tag.interface}}(const Node& node) {
-  return node.Is{{namespace}}Element() && Is{{tag.interface}}(To{{namespace}}Element(node));
+  return node.Is{{namespace}}Element() && Is{{tag.interface}}(To<{{namespace}}Element>(node));
 }
 inline bool Is{{tag.interface}}(const Node* node) {
   return node && Is{{tag.interface}}(*node);
@@ -49,9 +49,23 @@
 // unsafe due to multiple inheritence.
 
 {% for tag in tags|sort if not tag.multipleTagNames and not tag.noTypeHelpers %}
-#define To{{tag.interface}}(x) blink::ToElement<blink::{{tag.interface}}>(x)
-#define To{{tag.interface}}OrNull(x) blink::ToElementOrNull<blink::{{tag.interface}}>(x)
-#define To{{tag.interface}}OrDie(x) blink::ToElementOrDie<blink::{{tag.interface}}>(x)
+template <>
+struct DowncastTraits<{{tag.interface}}> {
+  static bool AllowFrom(const Element& element) {
+    {% if tag.runtimeEnabled %}
+    if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled())
+      return false;
+    {% endif %}
+    return element.HasTagName({{cpp_namespace}}::{{tag|symbol}}Tag);
+  }
+  static bool AllowFrom(const Node& node) {
+    return node.Is{{namespace}}Element() && IsA<{{tag.interface}}>(To<{{namespace}}Element>(node));
+  }
+};
+#define To{{tag.interface}}(x) blink::To<blink::{{tag.interface}}>(x)
+#define To{{tag.interface}}OrNull(x) blink::DynamicTo<blink::{{tag.interface}}>(x)
+#define To{{tag.interface}}OrDie(x) blink::To<blink::{{tag.interface}}>(x)
+
 {% endfor %}
 
 {% if namespace == "HTML" %}
diff --git a/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc b/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc
index 1be8571..7ab0c06 100644
--- a/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc
+++ b/third_party/blink/renderer/core/accessibility/apply_dark_mode.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/core/accessibility/apply_dark_mode.h"
+
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -53,7 +54,8 @@
   dark_mode_settings.grayscale = frame_settings.GetDarkModeGrayscale();
   dark_mode_settings.contrast = frame_settings.GetDarkModeContrast();
   dark_mode_settings.image_policy = frame_settings.GetDarkModeImagePolicy();
-  dark_mode_settings.image_style = frame_settings.GetDarkModeImageStyle();
+  dark_mode_settings.image_grayscale_percent =
+      frame_settings.GetDarkModeImageGrayscale();
   return dark_mode_settings;
 }
 
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 44f138b9..03c555d 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -345,7 +345,7 @@
 
 bool Animation::PreCommit(
     int compositor_group,
-    const base::Optional<CompositorElementIdSet>& composited_element_ids,
+    const PaintArtifactCompositor* paint_artifact_compositor,
     bool start_on_compositor) {
   PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand,
                                     kDoNotSetCompositorPending);
@@ -386,12 +386,12 @@
     compositor_group_ = compositor_group;
     if (start_on_compositor) {
       CompositorAnimations::FailureReasons failure_reasons =
-          CheckCanStartAnimationOnCompositor(composited_element_ids);
+          CheckCanStartAnimationOnCompositor(paint_artifact_compositor);
       RecordCompositorAnimationFailureReasons(failure_reasons);
 
       if (failure_reasons == CompositorAnimations::kNoFailure) {
         CreateCompositorAnimation();
-        StartAnimationOnCompositor(composited_element_ids);
+        StartAnimationOnCompositor(paint_artifact_compositor);
         compositor_state_ = std::make_unique<CompositorState>(*this);
       } else {
         CancelIncompatibleAnimationsOnCompositor();
@@ -952,14 +952,13 @@
 
 CompositorAnimations::FailureReasons
 Animation::CheckCanStartAnimationOnCompositor(
-    const base::Optional<CompositorElementIdSet>& composited_element_ids)
-    const {
+    const PaintArtifactCompositor* paint_artifact_compositor) const {
   CompositorAnimations::FailureReasons reasons =
       CheckCanStartAnimationOnCompositorInternal();
   if (content_ && content_->IsKeyframeEffect()) {
     reasons |= ToKeyframeEffect(content_.Get())
-                   ->CheckCanStartAnimationOnCompositor(composited_element_ids,
-                                                        playback_rate_);
+                   ->CheckCanStartAnimationOnCompositor(
+                       paint_artifact_compositor, playback_rate_);
   }
   return reasons;
 }
@@ -1006,8 +1005,8 @@
 }
 
 void Animation::StartAnimationOnCompositor(
-    const base::Optional<CompositorElementIdSet>& composited_element_ids) {
-  DCHECK_EQ(CheckCanStartAnimationOnCompositor(composited_element_ids),
+    const PaintArtifactCompositor* paint_artifact_compositor) {
+  DCHECK_EQ(CheckCanStartAnimationOnCompositor(paint_artifact_compositor),
             CompositorAnimations::kNoFailure);
 
   bool reversed = playback_rate_ < 0;
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index 323897b..6080686 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -59,6 +59,7 @@
 class CompositorAnimation;
 class Element;
 class ExceptionState;
+class PaintArtifactCompositor;
 class TreeScope;
 
 class CORE_EXPORT Animation final : public EventTargetWithInlineData,
@@ -187,10 +188,9 @@
   bool Outdated() { return outdated_; }
 
   CompositorAnimations::FailureReasons CheckCanStartAnimationOnCompositor(
-      const base::Optional<CompositorElementIdSet>& composited_element_ids)
-      const;
+      const PaintArtifactCompositor* paint_artifact_compositor) const;
   void StartAnimationOnCompositor(
-      const base::Optional<CompositorElementIdSet>& composited_element_ids);
+      const PaintArtifactCompositor* paint_artifact_compositor);
   void CancelAnimationOnCompositor();
   void RestartAnimationOnCompositor();
   void CancelIncompatibleAnimationsOnCompositor();
@@ -209,7 +209,7 @@
   // Returns whether we should continue with the commit for this animation or
   // wait until next commit.
   bool PreCommit(int compositor_group,
-                 const base::Optional<CompositorElementIdSet>&,
+                 const PaintArtifactCompositor*,
                  bool start_on_compositor);
   void PostCommit(double timeline_time);
 
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index 3be7601b..ed31579d 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -140,7 +140,7 @@
     UpdateAllLifecyclePhasesForTest();
 
     document->GetAnimationClock().UpdateTime(base::TimeTicks());
-    document->GetPendingAnimations().Update(base::nullopt, true);
+    document->GetPendingAnimations().Update(nullptr, true);
   }
 
   KeyframeEffectModelBase* MakeEmptyEffectModel() {
@@ -153,13 +153,16 @@
     return KeyframeEffect::Create(nullptr, MakeEmptyEffectModel(), timing);
   }
 
-  bool SimulateFrame(
-      double time,
-      base::Optional<CompositorElementIdSet> composited_element_ids =
-          base::Optional<CompositorElementIdSet>()) {
+  bool SimulateFrame(double time) {
+    const PaintArtifactCompositor* paint_artifact_compositor = nullptr;
+    if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
+        RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
+      paint_artifact_compositor =
+          document->GetFrame()->View()->GetPaintArtifactCompositorForTesting();
+    }
     document->GetAnimationClock().UpdateTime(
         base::TimeTicks() + base::TimeDelta::FromSecondsD(time));
-    document->GetPendingAnimations().Update(composited_element_ids, false);
+    document->GetPendingAnimations().Update(paint_artifact_compositor, false);
     // The timeline does not know about our animation, so we have to explicitly
     // call update().
     return animation->Update(kTimingUpdateForAnimationFrame);
@@ -937,22 +940,16 @@
 
 TEST_F(AnimationAnimationTest, NoCompositeWithoutCompositedElementId) {
   ScopedCompositeAfterPaintForTest enable_cap(true);
+  EnableCompositing();
 
   SetBodyInnerHTML(
-      "<div id='foo' style='position: relative'></div>"
-      "<div id='bar' style='position: relative'></div>");
+      "<div id='foo' style='position: relative; will-change: "
+      "opacity;'>composited</div>"
+      "<div id='bar' style='position: relative'>not composited</div>");
 
   LayoutObject* object_composited = GetLayoutObjectByElementId("foo");
   LayoutObject* object_not_composited = GetLayoutObjectByElementId("bar");
 
-  base::Optional<CompositorElementIdSet> composited_element_ids =
-      CompositorElementIdSet();
-  CompositorElementId expected_compositor_element_id =
-      CompositorElementIdFromUniqueObjectId(
-          ToLayoutBoxModelObject(object_composited)->UniqueId(),
-          CompositorElementIdNamespace::kPrimaryEffect);
-  composited_element_ids->insert(expected_compositor_element_id);
-
   Timing timing;
   timing.iteration_duration = AnimationTimeDelta::FromSecondsD(30);
   KeyframeEffect* keyframe_effect_composited = KeyframeEffect::Create(
@@ -964,14 +961,17 @@
   Animation* animation_not_composited =
       timeline->Play(keyframe_effect_not_composited);
 
-  SimulateFrame(0, composited_element_ids);
+  SimulateFrame(0);
   EXPECT_EQ(animation_composited->CheckCanStartAnimationOnCompositorInternal(),
             CompositorAnimations::kNoFailure);
+  const PaintArtifactCompositor* paint_artifact_compositor =
+      GetDocument().View()->GetPaintArtifactCompositor();
+  ASSERT_TRUE(paint_artifact_compositor);
   EXPECT_EQ(animation_composited->CheckCanStartAnimationOnCompositor(
-                composited_element_ids),
+                paint_artifact_compositor),
             CompositorAnimations::kNoFailure);
   EXPECT_NE(animation_not_composited->CheckCanStartAnimationOnCompositor(
-                composited_element_ids),
+                paint_artifact_compositor),
             CompositorAnimations::kNoFailure);
 }
 
@@ -1006,7 +1006,7 @@
 
   // At this point, a call to PreCommit should bail out and tell us to wait for
   // next commit because there are no resolved start times.
-  EXPECT_FALSE(animation->PreCommit(0, base::nullopt, true));
+  EXPECT_FALSE(animation->PreCommit(0, nullptr, true));
 }
 
 namespace {
@@ -1028,7 +1028,7 @@
   // Initially the animation in this test has no target, so it is invalid.
   {
     HistogramTester histogram;
-    ASSERT_TRUE(animation->PreCommit(0, base::nullopt, true));
+    ASSERT_TRUE(animation->PreCommit(0, nullptr, true));
     histogram.ExpectBucketCount(
         histogram_name,
         GenerateHistogramValue(CompositorAnimations::kInvalidAnimationOrEffect),
@@ -1050,7 +1050,7 @@
   animation->NotifyCompositorStartTime(100);
   {
     HistogramTester histogram;
-    ASSERT_TRUE(animation->PreCommit(0, base::nullopt, true));
+    ASSERT_TRUE(animation->PreCommit(0, nullptr, true));
     histogram.ExpectBucketCount(
         histogram_name,
         GenerateHistogramValue(CompositorAnimations::kInvalidAnimationOrEffect),
@@ -1077,7 +1077,7 @@
   UpdateAllLifecyclePhasesForTest();
   {
     HistogramTester histogram;
-    ASSERT_TRUE(animation->PreCommit(0, base::nullopt, true));
+    ASSERT_TRUE(animation->PreCommit(0, nullptr, true));
     histogram.ExpectBucketCount(
         histogram_name,
         GenerateHistogramValue(CompositorAnimations::kUnsupportedCSSProperty),
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.cc b/third_party/blink/renderer/core/animation/compositor_animations.cc
index effed2cb..eed891d5 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -59,6 +59,7 @@
 #include "third_party/blink/renderer/platform/animation/compositor_transform_animation_curve.h"
 #include "third_party/blink/renderer/platform/animation/compositor_transform_keyframe.h"
 #include "third_party/blink/renderer/platform/geometry/float_box.h"
+#include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 
 namespace blink {
 
@@ -184,14 +185,14 @@
     const Element& target_element,
     const Animation* animation_to_add,
     const EffectModel& effect,
-    const base::Optional<CompositorElementIdSet>& composited_element_ids,
+    const PaintArtifactCompositor* paint_artifact_compositor,
     double animation_playback_rate) {
   FailureReasons reasons = kNoFailure;
   const KeyframeEffectModelBase& keyframe_effect =
       ToKeyframeEffectModelBase(effect);
 
   LayoutObject* layout_object = target_element.GetLayoutObject();
-  if (composited_element_ids) {
+  if (paint_artifact_compositor) {
     // If we are going to check that we can animate these below, we need
     // to have the UniqueID to compute the target ID.  Let's check it
     // once in common in advance.
@@ -294,7 +295,7 @@
         reasons |= kInvalidAnimationOrEffect;
       }
 
-      if (composited_element_ids) {
+      if (paint_artifact_compositor) {
         if (!layout_object || !layout_object->UniqueId())
           continue;
 
@@ -304,7 +305,7 @@
                 CompositorElementNamespaceForProperty(
                     property.GetCSSProperty().PropertyID()));
         DCHECK(target_element_id);
-        if (!composited_element_ids->count(target_element_id))
+        if (!paint_artifact_compositor->HasComposited(target_element_id))
           reasons |= kTargetHasInvalidCompositingState;
       }
     }
@@ -374,11 +375,11 @@
     const Element& target_element,
     const Animation* animation_to_add,
     const EffectModel& effect,
-    const base::Optional<CompositorElementIdSet>& composited_element_ids,
+    const PaintArtifactCompositor* paint_artifact_compositor,
     double animation_playback_rate) {
   FailureReasons reasons = CheckCanStartEffectOnCompositor(
-      timing, target_element, animation_to_add, effect, composited_element_ids,
-      animation_playback_rate);
+      timing, target_element, animation_to_add, effect,
+      paint_artifact_compositor, animation_playback_rate);
   return reasons | CheckCanStartElementOnCompositor(target_element);
 }
 
@@ -433,12 +434,11 @@
     Vector<int>& started_keyframe_model_ids,
     double animation_playback_rate) {
   DCHECK(started_keyframe_model_ids.IsEmpty());
-  // TODO(petermayo): Find and pass the set of valid compositor elements before
+  // TODO(petermayo): Pass the PaintArtifactCompositor before
   // BlinkGenPropertyTrees is always on.
   DCHECK_EQ(
-      CheckCanStartAnimationOnCompositor(
-          timing, element, animation, effect,
-          base::Optional<CompositorElementIdSet>(), animation_playback_rate),
+      CheckCanStartAnimationOnCompositor(timing, element, animation, effect,
+                                         nullptr, animation_playback_rate),
       kNoFailure);
 
   const KeyframeEffectModelBase& keyframe_effect =
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.h b/third_party/blink/renderer/core/animation/compositor_animations.h
index ad768c2b..deedee2 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -46,6 +46,7 @@
 class CompositorAnimation;
 class Element;
 class KeyframeEffectModelBase;
+class PaintArtifactCompositor;
 
 class CORE_EXPORT CompositorAnimations {
   STATIC_ONLY(CompositorAnimations);
@@ -102,7 +103,7 @@
       const Element&,
       const Animation*,
       const EffectModel&,
-      const base::Optional<CompositorElementIdSet>& composited_element_ids,
+      const PaintArtifactCompositor*,
       double animation_playback_rate);
   static void CancelIncompatibleAnimationsOnCompositor(const Element&,
                                                        const Animation&,
@@ -159,7 +160,7 @@
       const Element&,
       const Animation*,
       const EffectModel&,
-      const base::Optional<CompositorElementIdSet>& composited_element_ids,
+      const PaintArtifactCompositor*,
       double animation_playback_rate);
   static FailureReasons CheckCanStartElementOnCompositor(const Element&);
 
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 23be9b9..53e06b53 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -162,18 +162,10 @@
       const Element& element,
       const Animation* animation,
       const EffectModel& effect_model) {
-    base::Optional<CompositorElementIdSet> composited_element_ids;
-
-    if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
-        RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-      const PaintArtifactCompositor* paint_artifact_compositor =
-          GetDocument().View()->GetPaintArtifactCompositor();
-      composited_element_ids = paint_artifact_compositor->RootLayer()
-                                   ->layer_tree_host()
-                                   ->elements_in_property_trees();
-    }
+    const PaintArtifactCompositor* paint_artifact_compositor =
+        GetDocument().View()->GetPaintArtifactCompositor();
     return CompositorAnimations::CheckCanStartEffectOnCompositor(
-        timing, element, animation, effect_model, composited_element_ids, 1);
+        timing, element, animation, effect_model, paint_artifact_compositor, 1);
   }
 
   CompositorAnimations::FailureReasons CheckCanStartElementOnCompositor(
@@ -422,8 +414,7 @@
   void SimulateFrame(double time) {
     GetAnimationClock().UpdateTime(base::TimeTicks() +
                                    base::TimeDelta::FromSecondsD(time));
-    GetPendingAnimations().Update(base::Optional<CompositorElementIdSet>(),
-                                  false);
+    GetPendingAnimations().Update(nullptr, false);
     timeline_->ServiceAnimations(kTimingUpdateForAnimationFrame);
   }
 
diff --git a/third_party/blink/renderer/core/animation/document_animations.cc b/third_party/blink/renderer/core/animation/document_animations.cc
index fdc9167..4376625f 100644
--- a/third_party/blink/renderer/core/animation/document_animations.cc
+++ b/third_party/blink/renderer/core/animation/document_animations.cc
@@ -70,10 +70,10 @@
 void DocumentAnimations::UpdateAnimations(
     Document& document,
     DocumentLifecycle::LifecycleState required_lifecycle_state,
-    const base::Optional<CompositorElementIdSet>& composited_element_ids) {
+    const PaintArtifactCompositor* paint_artifact_compositor) {
   DCHECK(document.Lifecycle().GetState() >= required_lifecycle_state);
 
-  if (document.GetPendingAnimations().Update(composited_element_ids)) {
+  if (document.GetPendingAnimations().Update(paint_artifact_compositor)) {
     DCHECK(document.View());
     document.View()->ScheduleAnimation();
   }
diff --git a/third_party/blink/renderer/core/animation/document_animations.h b/third_party/blink/renderer/core/animation/document_animations.h
index 12f52b2..9fdcfe1 100644
--- a/third_party/blink/renderer/core/animation/document_animations.h
+++ b/third_party/blink/renderer/core/animation/document_animations.h
@@ -34,12 +34,12 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/dom/document_lifecycle.h"
-#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
 
 class Document;
+class PaintArtifactCompositor;
 
 class DocumentAnimations {
   STATIC_ONLY(DocumentAnimations);
@@ -55,7 +55,7 @@
   static void UpdateAnimations(
       Document&,
       DocumentLifecycle::LifecycleState required_lifecycle_state,
-      const base::Optional<CompositorElementIdSet>&);
+      const PaintArtifactCompositor* paint_artifact_compositor);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/document_timeline_test.cc b/third_party/blink/renderer/core/animation/document_timeline_test.cc
index d7b448b..1cbe452 100644
--- a/third_party/blink/renderer/core/animation/document_timeline_test.cc
+++ b/third_party/blink/renderer/core/animation/document_timeline_test.cc
@@ -85,8 +85,7 @@
 
   void UpdateClockAndService(double time) {
     GetAnimationClock().UpdateTime(TimeTicksFromSecondsD(time));
-    GetPendingAnimations().Update(base::Optional<CompositorElementIdSet>(),
-                                  false);
+    GetPendingAnimations().Update(nullptr, false);
     timeline->ServiceAnimations(kTimingUpdateForAnimationFrame);
     timeline->ScheduleNextService();
   }
diff --git a/third_party/blink/renderer/core/animation/effect_stack_test.cc b/third_party/blink/renderer/core/animation/effect_stack_test.cc
index 97a96b4..83731772 100644
--- a/third_party/blink/renderer/core/animation/effect_stack_test.cc
+++ b/third_party/blink/renderer/core/animation/effect_stack_test.cc
@@ -172,8 +172,7 @@
   Play(MakeKeyframeEffect(MakeEffectModel(CSSPropertyID::kFontSize, "1px")), 2);
   Play(MakeKeyframeEffect(MakeEffectModel(CSSPropertyID::kFontSize, "2px")), 6);
   Play(MakeKeyframeEffect(MakeEffectModel(CSSPropertyID::kFontSize, "3px")), 4);
-  GetDocument().GetPendingAnimations().Update(
-      base::Optional<CompositorElementIdSet>());
+  GetDocument().GetPendingAnimations().Update(nullptr);
 
   // Because we will be forcing a naive GC that assumes there are no Oilpan
   // objects on the stack (e.g. passes BlinkGC::kNoHeapPointersOnStack), we have
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc
index 2370bbb6..82c868c 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -217,7 +217,7 @@
 
 CompositorAnimations::FailureReasons
 KeyframeEffect::CheckCanStartAnimationOnCompositor(
-    const base::Optional<CompositorElementIdSet>& composited_element_ids,
+    const PaintArtifactCompositor* paint_artifact_compositor,
     double animation_playback_rate) const {
   CompositorAnimations::FailureReasons reasons =
       CompositorAnimations::kNoFailure;
@@ -242,7 +242,7 @@
 
     reasons |= CompositorAnimations::CheckCanStartAnimationOnCompositor(
         SpecifiedTiming(), *target_, GetAnimation(), *Model(),
-        composited_element_ids, animation_playback_rate);
+        paint_artifact_compositor, animation_playback_rate);
   }
 
   return reasons;
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.h b/third_party/blink/renderer/core/animation/keyframe_effect.h
index 389a7eb3..e04533b 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect.h
+++ b/third_party/blink/renderer/core/animation/keyframe_effect.h
@@ -42,6 +42,7 @@
 class Element;
 class ExceptionState;
 class KeyframeEffectModelBase;
+class PaintArtifactCompositor;
 class SampledEffect;
 class UnrestrictedDoubleOrKeyframeEffectOptions;
 
@@ -104,7 +105,7 @@
   void NotifySampledEffectRemovedFromEffectStack();
 
   CompositorAnimations::FailureReasons CheckCanStartAnimationOnCompositor(
-      const base::Optional<CompositorElementIdSet>& composited_element_ids,
+      const PaintArtifactCompositor*,
       double animation_playback_rate) const;
   // Must only be called once.
   void StartAnimationOnCompositor(int group,
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_test.cc b/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
index cf701ade..cd7c113 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
@@ -368,7 +368,6 @@
 TEST_F(KeyframeEffectTest, CheckCanStartAnimationOnCompositorNoKeyframes) {
   ASSERT_TRUE(element);
 
-  const base::Optional<CompositorElementIdSet> composited_element_ids;
   const double animation_playback_rate = 1;
   Timing timing;
 
@@ -377,7 +376,7 @@
     KeyframeEffect* keyframe_effect =
         KeyframeEffect::Create(element, CreateEmptyEffectModel(), timing);
     EXPECT_TRUE(keyframe_effect->CheckCanStartAnimationOnCompositor(
-                    composited_element_ids, animation_playback_rate) &
+                    nullptr, animation_playback_rate) &
                 CompositorAnimations::kInvalidAnimationOrEffect);
   }
 
@@ -394,13 +393,12 @@
     KeyframeEffect* keyframe_effect =
         KeyframeEffect::Create(element, effect_model, timing);
     EXPECT_TRUE(keyframe_effect->CheckCanStartAnimationOnCompositor(
-                    composited_element_ids, animation_playback_rate) &
+                    nullptr, animation_playback_rate) &
                 CompositorAnimations::kInvalidAnimationOrEffect);
   }
 }
 
 TEST_F(KeyframeEffectTest, CheckCanStartAnimationOnCompositorNoTarget) {
-  const base::Optional<CompositorElementIdSet> composited_element_ids;
   const double animation_playback_rate = 1;
   Timing timing;
 
@@ -422,12 +420,11 @@
   KeyframeEffect* keyframe_effect =
       KeyframeEffect::Create(nullptr, effect_model, timing);
   EXPECT_TRUE(keyframe_effect->CheckCanStartAnimationOnCompositor(
-                  composited_element_ids, animation_playback_rate) &
+                  nullptr, animation_playback_rate) &
               CompositorAnimations::kInvalidAnimationOrEffect);
 }
 
 TEST_F(KeyframeEffectTest, CheckCanStartAnimationOnCompositorBadTarget) {
-  const base::Optional<CompositorElementIdSet> composited_element_ids;
   const double animation_playback_rate = 1;
   Timing timing;
 
@@ -453,7 +450,7 @@
       LengthPoint(Length::Percent(50.0), Length::Auto()));
   ASSERT_TRUE(element->GetComputedStyle()->HasOffset());
   EXPECT_TRUE(keyframe_effect->CheckCanStartAnimationOnCompositor(
-                  composited_element_ids, animation_playback_rate) &
+                  nullptr, animation_playback_rate) &
               CompositorAnimations::kTargetHasCSSOffset);
 
   // If the target has multiple transform properties we can't composite it.
@@ -463,7 +460,7 @@
   element->MutableComputedStyle()->SetScale(
       ScaleTransformOperation::Create(2, 1, TransformOperation::kScaleX));
   EXPECT_TRUE(keyframe_effect->CheckCanStartAnimationOnCompositor(
-                  composited_element_ids, animation_playback_rate) &
+                  nullptr, animation_playback_rate) &
               CompositorAnimations::kTargetHasMultipleTransformProperties);
 }
 
diff --git a/third_party/blink/renderer/core/animation/pending_animations.cc b/third_party/blink/renderer/core/animation/pending_animations.cc
index 491ca011..2bbc247 100644
--- a/third_party/blink/renderer/core/animation/pending_animations.cc
+++ b/third_party/blink/renderer/core/animation/pending_animations.cc
@@ -55,7 +55,7 @@
 }
 
 bool PendingAnimations::Update(
-    const base::Optional<CompositorElementIdSet>& composited_element_ids,
+    const PaintArtifactCompositor* paint_artifact_compositor,
     bool start_on_compositor) {
   HeapVector<Member<Animation>> waiting_for_start_time;
   bool started_synchronized_on_compositor = false;
@@ -71,7 +71,7 @@
     // Animations with a start time do not participate in compositor start-time
     // grouping.
     if (animation->PreCommit(animation->startTime() ? 1 : compositor_group,
-                             composited_element_ids, start_on_compositor)) {
+                             paint_artifact_compositor, start_on_compositor)) {
       if (animation->HasActiveAnimationsOnCompositor() &&
           !had_compositor_animation) {
         started_synchronized_on_compositor = true;
diff --git a/third_party/blink/renderer/core/animation/pending_animations.h b/third_party/blink/renderer/core/animation/pending_animations.h
index 651e38a..86afd946 100644
--- a/third_party/blink/renderer/core/animation/pending_animations.h
+++ b/third_party/blink/renderer/core/animation/pending_animations.h
@@ -43,6 +43,8 @@
 
 namespace blink {
 
+class PaintArtifactCompositor;
+
 // Handles starting animations when they could potentially require
 // interaction with the compositor. This can include both main-thread
 // and compositor thread animations. For example, when the Document
@@ -86,7 +88,7 @@
   //
   // Returns whether we are waiting for an animation to start and should service
   // again on the next frame.
-  bool Update(const base::Optional<CompositorElementIdSet>&,
+  bool Update(const PaintArtifactCompositor* paint_artifact_compositor,
               bool start_on_compositor = true);
   void NotifyCompositorAnimationStarted(double monotonic_animation_start_time,
                                         int compositor_group = 0);
@@ -94,9 +96,7 @@
   void Trace(blink::Visitor*);
 
  private:
-  void TimerFired(TimerBase*) {
-    Update(base::Optional<CompositorElementIdSet>(), false);
-  }
+  void TimerFired(TimerBase*) { Update(nullptr, false); }
   int NextCompositorGroup();
 
   HeapVector<Member<Animation>> pending_;
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.cc b/third_party/blink/renderer/core/css/css_style_sheet.cc
index cc732061..69e5d94 100644
--- a/third_party/blink/renderer/core/css/css_style_sheet.cc
+++ b/third_party/blink/renderer/core/css/css_style_sheet.cc
@@ -617,14 +617,14 @@
     if (IsHTMLStyleElement(owner_node_) || IsSVGStyleElement(owner_node_))
       return true;
     if (IsHTMLLinkElement(owner_node_) &&
-        ToHTMLLinkElement(owner_node_)->IsImport())
+        ToHTMLLinkElement(owner_node_.Get())->IsImport())
       return !IsAlternate();
   }
 
   if (!owner_node_ ||
       owner_node_->getNodeType() == Node::kProcessingInstructionNode ||
       !IsHTMLLinkElement(owner_node_) ||
-      !ToHTMLLinkElement(owner_node_)->IsEnabledViaScript()) {
+      !ToHTMLLinkElement(owner_node_.Get())->IsEnabledViaScript()) {
     if (!title_.IsEmpty() && title_ != current_preferrable_name)
       return false;
   }
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index be64fb79..2f0204a5 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -67,12 +67,26 @@
     return;
   }
   const_cast<Node*>(node)->UpdateDistributionForFlatTreeTraversal();
+
+  // Get the right ancestor view. Only use inclusive ancestors if the node
+  // itself is locked and it prevents self layout. If self layout is not
+  // prevented, we don't need to force the subtree layout, so use exclusive
+  // ancestors in that case.
+  auto ancestor_view = [node] {
+    if (node->IsElementNode()) {
+      auto* context = ToElement(node)->GetDisplayLockContext();
+      if (context && !context->ShouldLayout(DisplayLockContext::kSelf))
+        return FlatTreeTraversal::InclusiveAncestorsOf(*node);
+    }
+    return FlatTreeTraversal::AncestorsOf(*node);
+  }();
+
   // TODO(vmpstr): This is somewhat inefficient, since we would pay the cost
   // of traversing the ancestor chain even for nodes that are not in the
   // locked subtree. We need to figure out if there is a supplementary
   // structure that we can use to quickly identify nodes that are in the
   // locked subtree.
-  for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(*node)) {
+  for (Node& ancestor : ancestor_view) {
     if (!ancestor.IsElementNode())
       continue;
     if (auto* context = ToElement(ancestor).GetDisplayLockContext())
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index b416697..e7adb9c 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1677,7 +1677,7 @@
       title_element_ = MakeGarbageCollected<SVGTitleElement>(*this);
       element->InsertBefore(title_element_.Get(), element->firstChild());
     }
-    if (auto* svg_title = ToSVGTitleElementOrNull(title_element_))
+    if (auto* svg_title = ToSVGTitleElementOrNull(title_element_.Get()))
       svg_title->SetText(title);
   } else if (element && element->IsHTMLElement()) {
     if (!title_element_) {
@@ -1687,7 +1687,7 @@
       title_element_ = MakeGarbageCollected<HTMLTitleElement>(*this);
       head_element->AppendChild(title_element_.Get());
     }
-    if (auto* html_title = ToHTMLTitleElementOrNull(title_element_))
+    if (auto* html_title = ToHTMLTitleElementOrNull(title_element_.Get()))
       html_title->setText(title);
   }
 }
@@ -1712,9 +1712,9 @@
     }
   }
 
-  if (auto* html_title = ToHTMLTitleElementOrNull(title_element_))
+  if (auto* html_title = ToHTMLTitleElementOrNull(title_element_.Get()))
     UpdateTitle(html_title->text());
-  else if (auto* svg_title = ToSVGTitleElementOrNull(title_element_))
+  else if (auto* svg_title = ToSVGTitleElementOrNull(title_element_.Get()))
     UpdateTitle(svg_title->textContent());
 }
 
@@ -6905,7 +6905,7 @@
 HTMLDialogElement* Document::ActiveModalDialog() const {
   for (auto it = top_layer_elements_.rbegin(); it != top_layer_elements_.rend();
        ++it) {
-    if (auto* dialog = ToHTMLDialogElementOrNull(*it))
+    if (auto* dialog = ToHTMLDialogElementOrNull(*it->Get()))
       return dialog;
   }
 
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
index b8e73be4..05bea66 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_check_requester.cc
@@ -61,19 +61,18 @@
       const WebVector<WebTextCheckingResult>& results) override {
     if (request_)
       request_->DidSucceed(ToCoreResults(results));
-    delete this;
+    request_ = nullptr;
   }
 
   void DidCancelCheckingText() override {
     if (request_)
       request_->DidCancel();
-    // TODO(dgozman): use std::unique_ptr.
-    delete this;
+    request_ = nullptr;
   }
 
- private:
-  virtual ~WebTextCheckingCompletionImpl() = default;
+  ~WebTextCheckingCompletionImpl() override = default;
 
+ private:
   // As |WebTextCheckingCompletionImpl| is mananaged outside Blink, it should
   // only keep weak references to Blink objects to prevent memory leaks.
   WeakPersistent<SpellCheckRequest> request_;
@@ -243,7 +242,7 @@
   if (WebTextCheckClient* text_checker_client = GetTextCheckerClient()) {
     text_checker_client->RequestCheckingOfText(
         processing_request_->GetText(),
-        new WebTextCheckingCompletionImpl(request));
+        std::make_unique<WebTextCheckingCompletionImpl>(request));
   }
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
index eea0d56..65462aa 100644
--- a/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
+++ b/third_party/blink/renderer/core/exported/web_document_subresource_filter_test.cc
@@ -115,7 +115,8 @@
 
   void ExpectSubresourceWasLoaded(bool loaded) {
     WebElement web_element = MainFrame()->GetDocument().QuerySelector("img");
-    HTMLImageElement* image_element = ToHTMLImageElement(web_element);
+    HTMLImageElement* image_element =
+        ToHTMLImageElement(web_element.Unwrap<Node>());
     EXPECT_EQ(loaded, !!image_element->naturalWidth());
   }
 
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index e9ee5c32..f7b8c8d 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -6419,8 +6419,9 @@
 
   // WebTextCheckClient:
   bool IsSpellCheckingEnabled() const override { return true; }
-  void RequestCheckingOfText(const WebString&,
-                             WebTextCheckingCompletion* completion) override {
+  void RequestCheckingOfText(
+      const WebString&,
+      std::unique_ptr<WebTextCheckingCompletion> completion) override {
     ++number_of_times_checked_;
     Vector<WebTextCheckingResult> results;
     const int kMisspellingStartOffset = 1;
@@ -6578,9 +6579,10 @@
 
   // WebTextCheckClient:
   bool IsSpellCheckingEnabled() const override { return true; }
-  void RequestCheckingOfText(const WebString&,
-                             WebTextCheckingCompletion* completion) override {
-    completion_ = completion;
+  void RequestCheckingOfText(
+      const WebString&,
+      std::unique_ptr<WebTextCheckingCompletion> completion) override {
+    completion_ = std::move(completion);
   }
 
   void KickNoResults() { Kick(-1, -1, kWebTextDecorationTypeSpelling); }
@@ -6601,10 +6603,10 @@
                                               misspelling_length));
     }
     completion_->DidFinishCheckingText(results);
-    completion_ = nullptr;
+    completion_.reset();
   }
 
-  WebTextCheckingCompletion* completion_;
+  std::unique_ptr<WebTextCheckingCompletion> completion_;
 };
 
 TEST_F(WebFrameTest, SlowSpellcheckMarkerPosition) {
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 83373bf..a90d95be 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -2931,9 +2931,10 @@
   web_view->MainFrameWidget()->HandleInputEvent(WebCoalescedInputEvent(event));
   EXPECT_TRUE(frame->SelectionAsText().IsEmpty());
 
-  HTMLTextAreaElement* text_area_element = ToHTMLTextAreaElement(
-      web_view->MainFrameImpl()->GetDocument().GetElementById(
-          blanklinestextbox));
+  HTMLTextAreaElement* text_area_element =
+      ToHTMLTextAreaElement(static_cast<Node*>(
+          web_view->MainFrameImpl()->GetDocument().GetElementById(
+              blanklinestextbox)));
   text_area_element->setValue("hello");
 
   // Long-press past last word of textbox.
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 2d9d482..c62aad9 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2435,7 +2435,7 @@
       ForAllNonThrottledLocalFrameViews([this](LocalFrameView& frame_view) {
         DocumentAnimations::UpdateAnimations(
             frame_view.GetLayoutView()->GetDocument(),
-            DocumentLifecycle::kPaintClean, animation_element_ids_);
+            DocumentLifecycle::kPaintClean, paint_artifact_compositor_.get());
       });
 
       // Initialize animation properties in the newly created paint property
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5
index 7acc674..b0484ec 100644
--- a/third_party/blink/renderer/core/frame/settings.json5
+++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -913,9 +913,9 @@
       invalidate: "Paint",
     },
     {
-      name: "darkModeImageStyle",
-      initial: "DarkModeImageStyle::kDefault",
-      type: "DarkModeImageStyle",
+      name: "darkModeImageGrayscale",
+      initial: "0.0",
+      type: "float",
       invalidate: "Paint",
     },
     {
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 924a852..0906a3dd 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -138,7 +138,7 @@
   // listItems() might have performance impact.
   if (GetListItems().size() == 0 || !IsHTMLOptionElement(GetListItems()[0]))
     return false;
-  return ToHTMLOptionElement(GetListItems()[0])->value().IsEmpty();
+  return ToHTMLOptionElement(GetListItems()[0].Get())->value().IsEmpty();
 }
 
 String HTMLSelectElement::validationMessage() const {
@@ -456,7 +456,7 @@
   const ListItems& items = GetListItems();
   if (static_cast<wtf_size_t>(list_index) >= items.size())
     return nullptr;
-  return ToHTMLOptionElementOrNull(items[list_index]);
+  return ToHTMLOptionElementOrNull(items[list_index].Get());
 }
 
 // Returns the 1st valid OPTION |skip| items from |listIndex| in direction
@@ -569,7 +569,7 @@
   for (auto& element : GetListItems()) {
     last_on_change_selection_.push_back(
         IsHTMLOptionElement(*element) &&
-        ToHTMLOptionElement(element)->Selected());
+        ToHTMLOptionElement(element.Get())->Selected());
   }
 }
 
@@ -864,7 +864,8 @@
 int HTMLSelectElement::SelectedListIndex() const {
   int index = 0;
   for (const auto& item : GetListItems()) {
-    if (IsHTMLOptionElement(item) && ToHTMLOptionElement(item)->Selected())
+    if (IsHTMLOptionElement(item) &&
+        ToHTMLOptionElement(item.Get())->Selected())
       return index;
     ++index;
   }
@@ -1130,7 +1131,7 @@
   for (wtf_size_t i = 0; i < length; ++i) {
     if (!IsHTMLOptionElement(*items[i]))
       continue;
-    HTMLOptionElement* option = ToHTMLOptionElement(items[i]);
+    HTMLOptionElement* option = ToHTMLOptionElement(items[i].Get());
     if (!option->Selected())
       continue;
     state.Append(option->value());
@@ -1150,7 +1151,7 @@
   for (wtf_size_t i = list_index_start; i < loop_end_index; ++i) {
     if (!IsHTMLOptionElement(items[i]))
       continue;
-    if (ToHTMLOptionElement(items[i])->value() == value)
+    if (ToHTMLOptionElement(items[i].Get())->value() == value)
       return i;
   }
   return kNotFound;
@@ -1171,16 +1172,16 @@
   if (!IsMultiple()) {
     unsigned index = state[1].ToUInt();
     if (index < items_size && IsHTMLOptionElement(items[index]) &&
-        ToHTMLOptionElement(items[index])->value() == state[0]) {
-      ToHTMLOptionElement(items[index])->SetSelectedState(true);
-      ToHTMLOptionElement(items[index])->SetDirty(true);
-      last_on_change_option_ = ToHTMLOptionElement(items[index]);
+        ToHTMLOptionElement(items[index].Get())->value() == state[0]) {
+      ToHTMLOptionElement(items[index].Get())->SetSelectedState(true);
+      ToHTMLOptionElement(items[index].Get())->SetDirty(true);
+      last_on_change_option_ = ToHTMLOptionElement(items[index].Get());
     } else {
       wtf_size_t found_index = SearchOptionsForValue(state[0], 0, items_size);
       if (found_index != kNotFound) {
-        ToHTMLOptionElement(items[found_index])->SetSelectedState(true);
-        ToHTMLOptionElement(items[found_index])->SetDirty(true);
-        last_on_change_option_ = ToHTMLOptionElement(items[found_index]);
+        ToHTMLOptionElement(items[found_index].Get())->SetSelectedState(true);
+        ToHTMLOptionElement(items[found_index].Get())->SetDirty(true);
+        last_on_change_option_ = ToHTMLOptionElement(items[found_index].Get());
       }
     }
   } else {
@@ -1189,9 +1190,9 @@
       const String& value = state[i];
       const unsigned index = state[i + 1].ToUInt();
       if (index < items_size && IsHTMLOptionElement(items[index]) &&
-          ToHTMLOptionElement(items[index])->value() == value) {
-        ToHTMLOptionElement(items[index])->SetSelectedState(true);
-        ToHTMLOptionElement(items[index])->SetDirty(true);
+          ToHTMLOptionElement(items[index].Get())->value() == value) {
+        ToHTMLOptionElement(items[index].Get())->SetSelectedState(true);
+        ToHTMLOptionElement(items[index].Get())->SetDirty(true);
         start_index = index + 1;
       } else {
         wtf_size_t found_index =
@@ -1200,8 +1201,8 @@
           found_index = SearchOptionsForValue(value, 0, start_index);
         if (found_index == kNotFound)
           continue;
-        ToHTMLOptionElement(items[found_index])->SetSelectedState(true);
-        ToHTMLOptionElement(items[found_index])->SetDirty(true);
+        ToHTMLOptionElement(items[found_index].Get())->SetSelectedState(true);
+        ToHTMLOptionElement(items[found_index].Get())->SetDirty(true);
         start_index = found_index + 1;
       }
     }
diff --git a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
index 01b7be2..777c76c 100644
--- a/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
+++ b/third_party/blink/renderer/core/html/forms/slider_thumb_element.cc
@@ -109,48 +109,33 @@
   Element* track_element = input->UserAgentShadowRoot()->getElementById(
       shadow_element_names::SliderTrack());
 
-  if (!input->GetLayoutObject() || !GetLayoutBox() ||
-      !track_element->GetLayoutBox())
+  const LayoutObject* input_object = input->GetLayoutObject();
+  const LayoutBox* thumb_box = GetLayoutBox();
+  const LayoutBox* track_box = track_element->GetLayoutBox();
+  if (!input_object || !thumb_box || !track_box)
     return;
 
-  LayoutPoint offset = LayoutPoint(input->GetLayoutObject()->AbsoluteToLocal(
-      FloatPoint(point), kUseTransforms));
+  PhysicalOffset point_in_track = PhysicalOffset::FromFloatPointRound(
+      track_box->AbsoluteToLocal(FloatPoint(point), kUseTransforms));
   bool is_vertical = HasVerticalAppearance(input);
   bool is_left_to_right_direction =
-      GetLayoutBox()->Style()->IsLeftToRightDirection();
+      thumb_box->StyleRef().IsLeftToRightDirection();
   LayoutUnit track_size;
   LayoutUnit position;
   LayoutUnit current_position;
-  // We need to calculate currentPosition from absolute points becaue the
-  // layoutObject for this node is usually on a layer and layoutBox()->x() and
-  // y() are unusable.
-  // FIXME: This should probably respect transforms.
-  LayoutPoint absolute_thumb_origin =
-      GetLayoutBox()->AbsoluteBoundingBoxRectIgnoringTransforms().Location();
-  LayoutPoint absolute_slider_content_origin =
-      LayoutPoint(input->GetLayoutObject()->LocalToAbsolute());
-  IntRect track_bounding_box =
-      track_element->GetLayoutObject()
-          ->AbsoluteBoundingBoxRectIgnoringTransforms();
-  IntRect input_bounding_box =
-      input->GetLayoutObject()->AbsoluteBoundingBoxRectIgnoringTransforms();
+  LayoutSize thumb_offset = thumb_box->OffsetFromAncestor(input_object) -
+                            track_box->OffsetFromAncestor(input_object);
   if (is_vertical) {
-    track_size = track_element->GetLayoutBox()->ContentHeight() -
-                 GetLayoutBox()->Size().Height();
-    position = offset.Y() - GetLayoutBox()->Size().Height() / 2 -
-               track_bounding_box.Y() + input_bounding_box.Y() -
-               GetLayoutBox()->MarginBottom();
-    current_position =
-        absolute_thumb_origin.Y() - absolute_slider_content_origin.Y();
+    track_size = track_box->ContentHeight() - thumb_box->Size().Height();
+    position = point_in_track.top - thumb_box->Size().Height() / 2 -
+               thumb_box->MarginBottom();
+    current_position = thumb_offset.Height();
   } else {
-    track_size = track_element->GetLayoutBox()->ContentWidth() -
-                 GetLayoutBox()->Size().Width();
-    position = offset.X() - GetLayoutBox()->Size().Width() / 2 -
-               track_bounding_box.X() + input_bounding_box.X();
-    position -= is_left_to_right_direction ? GetLayoutBox()->MarginLeft()
-                                           : GetLayoutBox()->MarginRight();
-    current_position =
-        absolute_thumb_origin.X() - absolute_slider_content_origin.X();
+    track_size = track_box->ContentWidth() - thumb_box->Size().Width();
+    position = point_in_track.left - thumb_box->Size().Width() / 2;
+    position -= is_left_to_right_direction ? thumb_box->MarginLeft()
+                                           : thumb_box->MarginRight();
+    current_position = thumb_offset.Width();
   }
   position = std::min(position, track_size).ClampNegativeToZero();
   const Decimal ratio =
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc
index af1e7a5..de95358 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -175,7 +175,7 @@
 
 HTMLAreaElement* HitTestResult::ImageAreaForImage() const {
   DCHECK(inner_node_);
-  HTMLImageElement* image_element = ToHTMLImageElementOrNull(inner_node_);
+  HTMLImageElement* image_element = ToHTMLImageElementOrNull(inner_node_.Get());
   if (!image_element && inner_node_->IsInShadowTree()) {
     if (inner_node_->ContainingShadowRoot()->IsUserAgent()) {
       image_element = ToHTMLImageElementOrNull(inner_node_->OwnerShadowHost());
@@ -491,9 +491,9 @@
     return nullptr;
 
   HTMLImageElement* image_map_image_element = nullptr;
-  if (auto* area = ToHTMLAreaElementOrNull(inner_node_))
+  if (auto* area = ToHTMLAreaElementOrNull(inner_node_.Get()))
     image_map_image_element = area->ImageElement();
-  else if (auto* map = ToHTMLMapElementOrNull(inner_node_))
+  else if (auto* map = ToHTMLMapElementOrNull(inner_node_.Get()))
     image_map_image_element = map->ImageElement();
 
   if (!image_map_image_element)
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 9f00ea9..8ad71f2 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -2607,29 +2607,6 @@
     AddLayoutOverflowFromFloats();
 }
 
-void LayoutBlockFlow::AbsoluteRects(
-    Vector<IntRect>& rects,
-    const LayoutPoint& accumulated_offset) const {
-  if (!IsAnonymousBlockContinuation()) {
-    LayoutBlock::AbsoluteRects(rects, accumulated_offset);
-    return;
-  }
-  // For blocks inside inlines, we go ahead and include margins so that we run
-  // right up to the inline boxes above and below us (thus getting merged with
-  // them to form a single irregular shape).
-  // FIXME: This is wrong for vertical writing-modes.
-  // https://bugs.webkit.org/show_bug.cgi?id=46781
-  LayoutRect rect(accumulated_offset, Size());
-  rect.Expand(CollapsedMarginBoxLogicalOutsets());
-  rects.push_back(PixelSnappedIntRect(rect));
-  Continuation()->AbsoluteRects(
-      rects,
-      accumulated_offset -
-          ToLayoutSize(
-              Location() +
-              InlineElementContinuation()->ContainingBlock()->Location()));
-}
-
 void LayoutBlockFlow::AbsoluteQuads(Vector<FloatQuad>& quads,
                                     MapCoordinatesFlags mode) const {
   if (!IsAnonymousBlockContinuation()) {
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index efaa1a2..3ba755ba8 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -483,8 +483,6 @@
 
   void UpdateBlockChildDirtyBitsBeforeLayout(bool relayout_children,
                                              LayoutBox&);
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const override;
   void AbsoluteQuads(Vector<FloatQuad>&,
                      MapCoordinatesFlags mode = 0) const override;
   void AbsoluteQuadsForSelf(Vector<FloatQuad>& quads,
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 2ac65f7..b36cd7d87 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -750,11 +750,6 @@
   margin_box_outsets_.SetLeft(box.left);
 }
 
-void LayoutBox::AbsoluteRects(Vector<IntRect>& rects,
-                              const LayoutPoint& accumulated_offset) const {
-  rects.push_back(PixelSnappedIntRect(accumulated_offset, Size()));
-}
-
 void LayoutBox::AbsoluteQuads(Vector<FloatQuad>& quads,
                               MapCoordinatesFlags mode) const {
   if (LayoutFlowThread* flow_thread = FlowThreadContainingBlock()) {
@@ -1814,14 +1809,15 @@
     LayoutBox* child_box = ToLayoutBox(child);
     if (!IsCandidateForOpaquenessTest(*child_box))
       continue;
-    LayoutPoint child_location = child_box->Location();
+    LayoutPoint child_location = child_box->PhysicalLocation();
     if (child_box->IsInFlowPositioned())
       child_location.Move(child_box->OffsetForInFlowPosition());
     LayoutRect child_local_rect = local_rect;
     child_local_rect.MoveBy(-child_location);
     if (child_local_rect.Y() < 0 || child_local_rect.X() < 0) {
       // If there is unobscured area above/left of a static positioned box then
-      // the rect is probably not covered.
+      // the rect is probably not covered. This can cause false-negative in
+      // non-horizontal-tb writing mode but is allowed.
       if (!child_box->IsPositioned())
         return false;
       continue;
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 2b8e30d..17cec0f 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -725,8 +725,6 @@
                              CollapsedMarginAfter(), LayoutUnit());
   }
 
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const override;
   void AbsoluteQuads(Vector<FloatQuad>&,
                      MapCoordinatesFlags mode = 0) const override;
   FloatRect LocalBoundingBoxRectForAccessibility() const final;
@@ -1795,6 +1793,7 @@
   // LayoutBoxUtils is used for the LayoutNG code querying protected methods on
   // this class, e.g. determining the static-position of OOF elements.
   friend class LayoutBoxUtils;
+  friend class LayoutBoxTest;
 
  private:
   LogicalToPhysicalSetter<LayoutUnit, LayoutBox> LogicalMarginToPhysicalSetter(
diff --git a/third_party/blink/renderer/core/layout/layout_box_test.cc b/third_party/blink/renderer/core/layout/layout_box_test.cc
index 5593215..cbbd092 100644
--- a/third_party/blink/renderer/core/layout/layout_box_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_test.cc
@@ -25,11 +25,16 @@
   LayoutBox* GetLayoutBoxByElementId(const char* id) const {
     return ToLayoutBox(GetLayoutObjectByElementId(id));
   }
+
+  bool ForegroundIsKnownToBeOpaqueInRect(const LayoutBox& box,
+                                         const LayoutRect& rect) {
+    return box.ForegroundIsKnownToBeOpaqueInRect(rect, 10);
+  }
 };
 
 INSTANTIATE_TEST_SUITE_P(All, LayoutBoxTest, testing::Bool());
 
-TEST_P(LayoutBoxTest, BackgroundObscuredInRect) {
+TEST_P(LayoutBoxTest, BackgroundIsKnownToBeObscured) {
   SetBodyInnerHTML(R"HTML(
     <style>.column { width: 295.4px; padding-left: 10.4px; }
     .white-background { background: red; position: relative; overflow:
@@ -111,6 +116,75 @@
   EXPECT_FALSE(parent->BackgroundIsKnownToBeObscured());
 }
 
+TEST_P(LayoutBoxTest, ForegroundIsKnownToBeOpaqueInRect) {
+  SetBodyInnerHTML(R"HTML(
+    <div id="target" style="width: 30px; height: 30px">
+      <div style="width: 10px; height: 10px; background: blue"></div>
+      <div>
+        <div style="width: 10px; height: 10px; opacity: 0.5; background: red">
+        </div>
+        <div style="width: 10px; height: 10px; background: green;
+                    position: relative; left: 20px">
+      </div>
+    </div>
+  )HTML");
+
+  auto& target = *GetLayoutBoxByElementId("target");
+  // Covered by the first child which is opaque.
+  EXPECT_TRUE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 0, 10, 10)));
+  // Covered by the first child of the second child is translucent.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 10, 10, 10)));
+  // Covered by the second child of the second child which is opaque.
+  EXPECT_TRUE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(20, 20, 10, 10)));
+  // Not covered by any child.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 20, 10, 10)));
+  // Partly covered by opaque children.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 0, 30, 30)));
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 0, 10, 30)));
+}
+
+TEST_P(LayoutBoxTest, ForegroundIsKnownToBeOpaqueInRectVerticalRL) {
+  SetBodyInnerHTML(R"HTML(
+    <div id="target"
+         style="width: 30px; height: 30px; writing-mode: vertical-rl">
+      <div style="width: 10px; height: 10px; background: blue"></div>
+      <div>
+        <div style="width: 10px; height: 10px; opacity: 0.5; background: red">
+        </div>
+        <div style="width: 10px; height: 10px; background: green;
+                    position: relative; top: 20px">
+      </div>
+    </div>
+  )HTML");
+
+  auto& target = *GetLayoutBoxByElementId("target");
+  // Covered by the first child which is opaque.
+  EXPECT_TRUE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(20, 0, 10, 10)));
+  // Covered by the first child of the second child is translucent.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(10, 0, 10, 10)));
+  // Covered by the second child of the second child which is opaque.
+  // However, the algorithm is optimized for horizontal-tb writing mode and has
+  // false-negative (which is allowed) in this case.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 20, 10, 10)));
+  // Not covered by any child.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 0, 10, 10)));
+  // Partly covered by opaque children.
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(0, 0, 30, 30)));
+  EXPECT_FALSE(
+      ForegroundIsKnownToBeOpaqueInRect(target, LayoutRect(20, 0, 30, 10)));
+}
+
 TEST_P(LayoutBoxTest, BackgroundRect) {
   SetBodyInnerHTML(R"HTML(
     <style>div { position: absolute; width: 100px; height: 100px; padding:
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 34ab8e22..6d4ed3a8 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -928,50 +928,6 @@
 
 namespace {
 
-class AbsoluteRectsGeneratorContext {
- public:
-  AbsoluteRectsGeneratorContext(Vector<IntRect>& rects,
-                                const LayoutPoint& accumulated_offset)
-      : rects_(rects), accumulated_offset_(accumulated_offset) {}
-
-  void operator()(const LayoutRect& rect) {
-    IntRect int_rect = EnclosingIntRect(rect);
-    int_rect.Move(accumulated_offset_.X().ToInt(),
-                  accumulated_offset_.Y().ToInt());
-    rects_.push_back(int_rect);
-  }
-
- private:
-  Vector<IntRect>& rects_;
-  const LayoutPoint& accumulated_offset_;
-};
-
-}  // unnamed namespace
-
-void LayoutInline::AbsoluteRects(Vector<IntRect>& rects,
-                                 const LayoutPoint& accumulated_offset) const {
-  AbsoluteRectsGeneratorContext context(rects, accumulated_offset);
-  GenerateLineBoxRects(context);
-  if (rects.IsEmpty())
-    context(LayoutRect());
-
-  if (const LayoutBoxModelObject* continuation = Continuation()) {
-    if (continuation->IsBox()) {
-      const LayoutBox* box = ToLayoutBox(continuation);
-      continuation->AbsoluteRects(
-          rects,
-          ToLayoutPoint(accumulated_offset - ContainingBlock()->Location() +
-                        box->LocationOffset()));
-    } else {
-      continuation->AbsoluteRects(
-          rects,
-          ToLayoutPoint(accumulated_offset - ContainingBlock()->Location()));
-    }
-  }
-}
-
-namespace {
-
 class AbsoluteQuadsGeneratorContext {
  public:
   AbsoluteQuadsGeneratorContext(const LayoutInline* layout_object,
diff --git a/third_party/blink/renderer/core/layout/layout_inline.h b/third_party/blink/renderer/core/layout/layout_inline.h
index 42ea9e7b..7ece9fa 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.h
+++ b/third_party/blink/renderer/core/layout/layout_inline.h
@@ -148,8 +148,6 @@
   LayoutUnit MarginTop() const final;
   LayoutUnit MarginBottom() const final;
 
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const final;
   FloatRect LocalBoundingBoxRectForAccessibility() const final;
 
   LayoutRect PhysicalLinesBoundingBox() const;
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 2b9682c9..8b0d0bc9 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1278,21 +1278,6 @@
   return result;
 }
 
-IntRect LayoutObject::AbsoluteBoundingBoxRectIgnoringTransforms() const {
-  FloatPoint abs_pos = LocalToAbsolute();
-  Vector<IntRect> rects;
-  AbsoluteRects(rects, FlooredLayoutPoint(abs_pos));
-
-  wtf_size_t n = rects.size();
-  if (!n)
-    return IntRect();
-
-  IntRect result = rects[0];
-  for (wtf_size_t i = 1; i < n; ++i)
-    result.Unite(rects[i]);
-  return result;
-}
-
 LayoutRect LayoutObject::AbsoluteBoundingBoxRectHandlingEmptyInline() const {
   return EnclosingLayoutRect(AbsoluteBoundingBoxFloatRect());
 }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 537ddf4..92847cf5 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1572,15 +1572,11 @@
   // not be on the containing block chain of |this|.
   LayoutSize OffsetFromAncestor(const LayoutObject*) const;
 
-  virtual void AbsoluteRects(Vector<IntRect>&, const LayoutPoint&) const {}
-
   FloatRect AbsoluteBoundingBoxFloatRect(MapCoordinatesFlags = 0) const;
   // This returns an IntRect enclosing this object. If this object has an
   // integral size and the position has fractional values, the resultant
   // IntRect can be larger than the integral size.
   IntRect AbsoluteBoundingBoxRect(MapCoordinatesFlags = 0) const;
-  // FIXME: This function should go away eventually
-  IntRect AbsoluteBoundingBoxRectIgnoringTransforms() const;
 
   // These two functions also handle inlines without content for which the
   // location of the result rect (which may be empty) should be the absolute
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index b9cc67b..49880f891 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -373,39 +373,6 @@
   return plain_text_builder.ToString();
 }
 
-void LayoutText::AbsoluteRects(Vector<IntRect>& rects,
-                               const LayoutPoint& accumulated_offset) const {
-  if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
-    auto fragments = NGPaintFragment::InlineFragmentsFor(this);
-    if (fragments.IsInLayoutNGInlineFormattingContext()) {
-      Vector<LayoutRect, 32> layout_rects;
-      for (const NGPaintFragment* fragment : fragments) {
-        layout_rects.push_back(
-            LayoutRect(fragment->InlineOffsetToContainerBox().ToLayoutPoint(),
-                       fragment->Size().ToLayoutSize()));
-      }
-      // |rect| is in flipped block physical coordinate, but LayoutNG is in
-      // physical coordinate. Flip if needed.
-      if (UNLIKELY(HasFlippedBlocksWritingMode())) {
-        LayoutBlock* block = ContainingBlock();
-        DCHECK(block);
-        for (LayoutRect& rect : layout_rects)
-          block->FlipForWritingMode(rect);
-      }
-      for (LayoutRect& rect : layout_rects) {
-        rect.MoveBy(accumulated_offset);
-        rects.push_back(EnclosingIntRect(rect));
-      }
-      return;
-    }
-  }
-
-  for (InlineTextBox* box : TextBoxes()) {
-    rects.push_back(EnclosingIntRect(LayoutRect(
-        LayoutPoint(accumulated_offset) + box->Location(), box->Size())));
-  }
-}
-
 static FloatRect LocalQuadForTextBox(InlineTextBox* box,
                                      unsigned start,
                                      unsigned end) {
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h
index 320eea2..04888513 100644
--- a/third_party/blink/renderer/core/layout/layout_text.h
+++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -112,9 +112,6 @@
   void DirtyOrDeleteLineBoxesIfNeeded(bool full_layout);
   void DirtyLineBoxes();
 
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const final;
-
   void AbsoluteQuads(Vector<FloatQuad>&,
                      MapCoordinatesFlags mode = 0) const final;
   void AbsoluteQuadsForRange(Vector<FloatQuad>&,
diff --git a/third_party/blink/renderer/core/layout/layout_text_test.cc b/third_party/blink/renderer/core/layout/layout_text_test.cc
index 89a85bd..239703d 100644
--- a/third_party/blink/renderer/core/layout/layout_text_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_test.cc
@@ -549,10 +549,11 @@
   EXPECT_TRUE(GetBasicText()->IsAfterNonCollapsedCharacter(1));
 }
 
-TEST_P(ParameterizedLayoutTextTest, AbsoluteRects) {
+TEST_P(ParameterizedLayoutTextTest, AbsoluteQuads) {
   LoadAhem();
   SetBodyInnerHTML(R"HTML(
     <style>
+    body { margin: 0 }
     div {
       font: 10px/1 Ahem;
       width: 5em;
@@ -561,16 +562,17 @@
     <div>012<span id=target>345 67</span></div>
   )HTML");
   LayoutText* layout_text = GetLayoutTextById("target");
-  Vector<IntRect> rects;
-  layout_text->AbsoluteRects(rects, {LayoutUnit(100), LayoutUnit(200)});
-  EXPECT_THAT(rects, testing::ElementsAre(IntRect(130, 200, 30, 10),
-                                          IntRect(100, 210, 20, 10)));
+  Vector<FloatQuad> quads;
+  layout_text->AbsoluteQuads(quads);
+  EXPECT_THAT(quads, testing::ElementsAre(FloatRect(30, 0, 30, 10),
+                                          FloatRect(0, 10, 20, 10)));
 }
 
-TEST_P(ParameterizedLayoutTextTest, AbsoluteRectsVRL) {
+TEST_P(ParameterizedLayoutTextTest, AbsoluteQuadsVRL) {
   LoadAhem();
   SetBodyInnerHTML(R"HTML(
     <style>
+    body { margin: 0 }
     div {
       font: 10px/1 Ahem;
       width: 10em;
@@ -581,10 +583,10 @@
     <div>012<span id=target>345 67</span></div>
   )HTML");
   LayoutText* layout_text = GetLayoutTextById("target");
-  Vector<IntRect> rects;
-  layout_text->AbsoluteRects(rects, {LayoutUnit(100), LayoutUnit(200)});
-  EXPECT_THAT(rects, testing::ElementsAre(IntRect(100, 230, 10, 30),
-                                          IntRect(110, 200, 10, 20)));
+  Vector<FloatQuad> quads;
+  layout_text->AbsoluteQuads(quads);
+  EXPECT_THAT(quads, testing::ElementsAre(FloatRect(90, 30, 10, 30),
+                                          FloatRect(80, 0, 10, 20)));
 }
 
 TEST_P(ParameterizedLayoutTextTest, PhysicalLinesBoundingBox) {
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index f8cbabd..ad1560e 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -558,12 +558,6 @@
   return HasOverflowClip() ? LayoutSize(ScrolledContentOffset()) : LayoutSize();
 }
 
-void LayoutView::AbsoluteRects(Vector<IntRect>& rects,
-                               const LayoutPoint& accumulated_offset) const {
-  rects.push_back(
-      PixelSnappedIntRect(accumulated_offset, LayoutSize(Layer()->Size())));
-}
-
 void LayoutView::AbsoluteQuads(Vector<FloatQuad>& quads,
                                MapCoordinatesFlags mode) const {
   quads.push_back(LocalToAbsoluteQuad(
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h
index 379b2cd..d7ff0e72 100644
--- a/third_party/blink/renderer/core/layout/layout_view.h
+++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -148,8 +148,6 @@
 
   void CommitPendingSelection();
 
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const override;
   void AbsoluteQuads(Vector<FloatQuad>&,
                      MapCoordinatesFlags mode = 0) const override;
 
diff --git a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
index d751a2e9..bb4763cb 100644
--- a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
+++ b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -384,6 +384,11 @@
   // a single leading white-space as potential breaking opportunities.
   current_start_offset_ = current_.Offset();
   has_former_opportunity_ = false;
+
+  if (curr_ws_ == EWhiteSpace::kBreakSpaces) {
+    layout_text_info_.line_break_iterator_.SetBreakSpace(
+        BreakSpaceType::kAfterEverySpace);
+  }
 }
 
 inline void BreakingContext::Increment() {
@@ -860,6 +865,8 @@
 
   LazyLineBreakIterator break_iterator(
       text.GetText(), style.LocaleForLineBreakIterator(), line_break_type);
+  if (curr_ws_ == EWhiteSpace::kBreakSpaces)
+    break_iterator.SetBreakSpace(BreakSpaceType::kAfterEverySpace);
   float x_pos_to_break = width_.AvailableWidth() - width_.CurrentWidth();
   if (x_pos_to_break <= LayoutUnit::Epsilon()) {
     // There were no space left. Skip computing how many characters can fit.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 4bc793c..316199d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -647,9 +647,11 @@
 
   if (container_builder_.BfcBlockOffset()) {
     // Do not collapse margins between the last in-flow child and bottom margin
-    // of its parent if the parent has height != auto.
-    if (!Style().LogicalHeight().IsAuto()) {
-      // TODO(layout-ng): handle LogicalMinHeight, LogicalMaxHeight.
+    // of its parent if:
+    //  - The parent has block-size != auto.
+    //  - The block-size differs from the intrinsic size.
+    if (!Style().LogicalHeight().IsAuto() ||
+        border_box_size.block_size != intrinsic_block_size_) {
       end_margin_strut = NGMarginStrut();
     }
   }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
index f8917ff5..adb03882 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
@@ -40,12 +40,6 @@
   return To<SVGElement>(LayoutObject::GetNode());
 }
 
-void LayoutSVGBlock::AbsoluteRects(Vector<IntRect>&, const LayoutPoint&) const {
-  // This code path should never be taken for SVG, as we're assuming
-  // useTransforms=true everywhere, absoluteQuads should be used.
-  NOTREACHED();
-}
-
 void LayoutSVGBlock::WillBeDestroyed() {
   SVGResourcesCache::ClientDestroyed(*this);
   SVGResources::ClearClipPathFilterMask(*GetElement(), Style());
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_block.h b/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
index 31caffe..1e401b3 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
@@ -78,9 +78,6 @@
 
   LayoutRect VisualRectInDocument(VisualRectFlags) const final;
 
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const final;
-
   void UpdateFromStyle() final;
 
   bool NodeAtPoint(HitTestResult&,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
index 8bd8cc9..18b4687 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
@@ -73,14 +73,6 @@
                                                   geometry_map);
 }
 
-void LayoutSVGModelObject::AbsoluteRects(
-    Vector<IntRect>& rects,
-    const LayoutPoint& accumulated_offset) const {
-  IntRect rect = EnclosingIntRect(StrokeBoundingBox());
-  rect.MoveBy(RoundedIntPoint(accumulated_offset));
-  rects.push_back(rect);
-}
-
 void LayoutSVGModelObject::AbsoluteQuads(Vector<FloatQuad>& quads,
                                          MapCoordinatesFlags mode) const {
   quads.push_back(LocalToAbsoluteQuad(StrokeBoundingBox(), mode));
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
index 8cbd42e1..87033daf 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h
@@ -54,8 +54,6 @@
     return local_visual_rect_;
   }
 
-  void AbsoluteRects(Vector<IntRect>&,
-                     const LayoutPoint& accumulated_offset) const final;
   void AbsoluteQuads(Vector<FloatQuad>&,
                      MapCoordinatesFlags mode = 0) const override;
   FloatRect LocalBoundingBoxRectForAccessibility() const final;
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 1cb2e74..b4f070f 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -786,7 +786,7 @@
   // crbug.com/930281
   if (CheckForUnoptimizedImagePolicy(element_->GetDocument(), image_content_) &&
       IsHTMLImageElement(element_))
-    ToHTMLImageElement(element_)->SetImagePolicyViolated();
+    ToHTMLImageElement(element_.Get())->SetImagePolicyViolated();
 
   DispatchDecodeRequestsIfComplete();
 
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index f2aca10..4833043 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -262,10 +262,9 @@
     // composited elements (see LocalFrameView::UpdateLifecyclePhasesInternal,
     // during kPaintClean).
     if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
-      base::Optional<CompositorElementIdSet> composited_element_ids;
       DocumentAnimations::UpdateAnimations(layout_view_.GetDocument(),
                                            DocumentLifecycle::kCompositingClean,
-                                           composited_element_ids);
+                                           nullptr);
     }
 
     layout_view_.GetFrameView()
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 4191340..9a8810b0 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2679,6 +2679,22 @@
       *this, nullptr, kMaybeIncludeTransformForAncestorLayer);
 }
 
+bool PaintLayer::ShouldApplyTransformToBoundingBox(
+    const PaintLayer& composited_layer,
+    CalculateBoundsOptions options) const {
+  if (!Transform())
+    return false;
+  if (options == kIncludeTransformsAndCompositedChildLayers)
+    return true;
+  if (PaintsWithTransform(kGlobalPaintNormalPhase)) {
+    if (this != &composited_layer)
+      return true;
+    if (options == kMaybeIncludeTransformForAncestorLayer)
+      return true;
+  }
+  return false;
+}
+
 LayoutRect PaintLayer::BoundingBoxForCompositingInternal(
     const PaintLayer& composited_layer,
     const PaintLayer* stacking_parent,
@@ -2723,10 +2739,7 @@
   if (PaintsWithFilters())
     result = MapLayoutRectForFilter(result);
 
-  if (Transform() && (options == kIncludeTransformsAndCompositedChildLayers ||
-                      ((PaintsWithTransform(kGlobalPaintNormalPhase) &&
-                        (this != &composited_layer ||
-                         options == kMaybeIncludeTransformForAncestorLayer)))))
+  if (ShouldApplyTransformToBoundingBox(composited_layer, options))
     result = Transform()->MapRect(result);
 
   if (ShouldFragmentCompositedBounds(&composited_layer)) {
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index e66f77a..60f58fa 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -1232,6 +1232,8 @@
       const PaintLayer& composited_layer,
       const PaintLayer* stacking_parent,
       CalculateBoundsOptions) const;
+  bool ShouldApplyTransformToBoundingBox(const PaintLayer& composited_layer,
+                                         CalculateBoundsOptions) const;
 
   bool NeedsFilterReferenceBox() const;
 
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc
index 20ed79b6..62da6a3 100644
--- a/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -393,16 +393,8 @@
       input->UserAgentShadowRoot()
           ->getElementById(shadow_element_names::SliderTrack())
           ->GetLayoutObject();
-  // We can ignoring transforms because transform is handled by the graphics
-  // context.
   if (track_layout_object)
-    track_bounds =
-        track_layout_object->AbsoluteBoundingBoxRectIgnoringTransforms();
-  IntRect slider_bounds = o.AbsoluteBoundingBoxRectIgnoringTransforms();
-
-  // Make position relative to the transformed ancestor element.
-  track_bounds.SetX(track_bounds.X() - slider_bounds.X() + rect.X());
-  track_bounds.SetY(track_bounds.Y() - slider_bounds.Y() + rect.Y());
+    track_bounds = track_layout_object->FirstFragment().VisualRect();
 
   if (is_horizontal) {
     tick_rect.SetWidth(floor(tick_size.Width() * zoom_factor));
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index 581c58a1..036caf7 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -661,10 +661,9 @@
     // update animations directly without worrying about including
     // PaintArtifactCompositor analysis of whether animations should be
     // composited.
-    base::Optional<CompositorElementIdSet> composited_element_ids;
     DocumentAnimations::UpdateAnimations(
         frame_view->GetLayoutView()->GetDocument(),
-        DocumentLifecycle::kLayoutClean, composited_element_ids);
+        DocumentLifecycle::kLayoutClean, nullptr);
   }
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_length_context.cc b/third_party/blink/renderer/core/svg/svg_length_context.cc
index 06d9526..1374945a 100644
--- a/third_party/blink/renderer/core/svg/svg_length_context.cc
+++ b/third_party/blink/renderer/core/svg/svg_length_context.cc
@@ -450,7 +450,7 @@
 
   // Root <svg> element lengths are resolved against the top level viewport.
   if (context_->IsOutermostSVGSVGElement()) {
-    viewport_size = ToSVGSVGElement(context_)->CurrentViewportSize();
+    viewport_size = ToSVGSVGElement(context_.Get())->CurrentViewportSize();
     return true;
   }
 
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 2eb7cdc..4bab4aa 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -922,8 +922,7 @@
   LayoutObject* layout_object = element->GetLayoutObject();
   if (!layout_object)
     return DOMRectReadOnly::Create(0, 0, 0, 0);
-  return DOMRectReadOnly::FromIntRect(
-      layout_object->AbsoluteBoundingBoxRectIgnoringTransforms());
+  return DOMRectReadOnly::FromIntRect(layout_object->AbsoluteBoundingBoxRect());
 }
 
 void Internals::setMarker(Document* document,
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 2868adb..ed2ec56 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -1402,7 +1402,7 @@
   if (!node_ || !IsHTMLAnchorElement(node_) || !GetDocument())
     return AXObject::InPageLinkTarget();
 
-  HTMLAnchorElement* anchor = ToHTMLAnchorElement(node_);
+  HTMLAnchorElement* anchor = ToHTMLAnchorElement(node_.Get());
   DCHECK(anchor);
   KURL link_url = anchor->Href();
   if (!link_url.IsValid())
@@ -1468,7 +1468,7 @@
   if (!node_ || RoleValue() != ax::mojom::Role::kRadioButton)
     return radio_buttons;
 
-  if (auto* node_radio_button = ToHTMLInputElementOrNull(node_)) {
+  if (auto* node_radio_button = ToHTMLInputElementOrNull(node_.Get())) {
     HeapVector<Member<HTMLInputElement>> html_radio_buttons =
         FindAllRadioButtonsWithSameName(node_radio_button);
     for (HTMLInputElement* radio_button : html_radio_buttons) {
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index ef968b4..b6ac9b0 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -552,8 +552,7 @@
 
   double playback_rate = 1;
   CompositorAnimations::FailureReasons failure_reasons =
-      GetEffect()->CheckCanStartAnimationOnCompositor(
-          base::Optional<CompositorElementIdSet>(), playback_rate);
+      GetEffect()->CheckCanStartAnimationOnCompositor(nullptr, playback_rate);
 
   if (failure_reasons != CompositorAnimations::kNoFailure)
     return false;
diff --git a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
index bfe6538..7084f24a 100644
--- a/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
+++ b/third_party/blink/renderer/modules/remoteplayback/remote_playback.cc
@@ -352,7 +352,8 @@
     DispatchEvent(*Event::Create(event_type_names::kConnecting));
     if (media_element_->IsHTMLVideoElement()) {
       // TODO(xjz): Pass the remote device name.
-      ToHTMLVideoElement(media_element_)->MediaRemotingStarted(WebString());
+      ToHTMLVideoElement(media_element_.Get())
+          ->MediaRemotingStarted(WebString());
     }
     media_element_->FlingingStarted();
   } else if (state_ == mojom::blink::PresentationConnectionState::CONNECTED) {
@@ -360,7 +361,7 @@
   } else if (state_ == mojom::blink::PresentationConnectionState::CLOSED) {
     DispatchEvent(*Event::Create(event_type_names::kDisconnect));
     if (media_element_->IsHTMLVideoElement()) {
-      ToHTMLVideoElement(media_element_)
+      ToHTMLVideoElement(media_element_.Get())
           ->MediaRemotingStopped(WebLocalizedString::kMediaRemotingStopNoText);
     }
     CleanupConnections();
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.cc b/third_party/blink/renderer/modules/xr/xr_input_source.cc
index d4fa34f..353fce01 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.cc
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.cc
@@ -13,99 +13,6 @@
 
 namespace blink {
 
-namespace {
-
-// TODO(https://crbug.com/962712): Switch to use typemapping instead.
-XRInputSource::TargetRayMode MojomToBlinkTargetRayMode(
-    device::mojom::XRTargetRayMode target_ray_mode) {
-  switch (target_ray_mode) {
-    case device::mojom::XRTargetRayMode::GAZING:
-      return XRInputSource::TargetRayMode::kGaze;
-    case device::mojom::XRTargetRayMode::POINTING:
-      return XRInputSource::TargetRayMode::kTrackedPointer;
-    case device::mojom::XRTargetRayMode::TAPPING:
-      return XRInputSource::TargetRayMode::kScreen;
-  }
-
-  NOTREACHED();
-}
-
-// TODO(https://crbug.com/962712): Switch to use typemapping instead.
-XRInputSource::Handedness MojomToBlinkHandedness(
-    device::mojom::XRHandedness handedness) {
-  switch (handedness) {
-    case device::mojom::XRHandedness::NONE:
-      return XRInputSource::Handedness::kHandNone;
-    case device::mojom::XRHandedness::LEFT:
-      return XRInputSource::Handedness::kHandLeft;
-    case device::mojom::XRHandedness::RIGHT:
-      return XRInputSource::Handedness::kHandRight;
-  }
-
-  NOTREACHED();
-}
-}  //  anonymous namespace
-
-XRInputSource* XRInputSource::CreateOrUpdateFrom(
-    XRInputSource* other,
-    XRSession* session,
-    const device::mojom::blink::XRInputSourceStatePtr& state) {
-  if (!state)
-    return other;
-
-  XRInputSource* updated_source = other;
-  if (other && other->InvalidatesSameObject(state)) {
-    updated_source = MakeGarbageCollected<XRInputSource>(*other);
-
-    // Need to explicitly override any of the properties that could cause us to
-    // recreate the object.
-    // TODO(https://crbug.com/962724): Simplify this creation pattern
-    if (state->gamepad) {
-      updated_source->gamepad_ = MakeGarbageCollected<Gamepad>(
-          updated_source, 0, updated_source->base_timestamp_, TimeTicks::Now());
-    } else {
-      updated_source->gamepad_ = nullptr;
-    }
-  } else if (!other) {
-    updated_source = MakeGarbageCollected<XRInputSource>(session, state);
-  }
-
-  if (state->gamepad) {
-    updated_source->UpdateGamepad(*(state->gamepad));
-  }
-
-  // Update the input source's description if this state update includes them.
-  if (state->description) {
-    const device::mojom::blink::XRInputSourceDescriptionPtr& desc =
-        state->description;
-
-    updated_source->SetTargetRayMode(
-        MojomToBlinkTargetRayMode(desc->target_ray_mode));
-    updated_source->SetHandedness(MojomToBlinkHandedness(desc->handedness));
-    updated_source->SetEmulatedPosition(desc->emulated_position);
-
-    if (desc->pointer_offset && desc->pointer_offset->matrix.has_value()) {
-      const WTF::Vector<float>& m = desc->pointer_offset->matrix.value();
-      std::unique_ptr<TransformationMatrix> pointer_matrix =
-          std::make_unique<TransformationMatrix>(
-              m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
-              m[11], m[12], m[13], m[14], m[15]);
-      updated_source->SetPointerTransformMatrix(std::move(pointer_matrix));
-    }
-  }
-
-  if (state->grip && state->grip->matrix.has_value()) {
-    const Vector<float>& m = state->grip->matrix.value();
-    std::unique_ptr<TransformationMatrix> grip_matrix =
-        std::make_unique<TransformationMatrix>(
-            m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
-            m[11], m[12], m[13], m[14], m[15]);
-    updated_source->SetBasePoseMatrix(std::move(grip_matrix));
-  }
-
-  return updated_source;
-}
-
 XRInputSource::XRInputSource(XRSession* session, uint32_t source_id)
     : session_(session),
       source_id_(source_id),
@@ -116,39 +23,6 @@
   SetHandedness(kHandNone);
 }
 
-XRInputSource::XRInputSource(
-    XRSession* session,
-    const device::mojom::blink::XRInputSourceStatePtr& state)
-    : XRInputSource(session, state->source_id) {
-  if (state->gamepad) {
-    gamepad_ = MakeGarbageCollected<Gamepad>(this, 0, base_timestamp_,
-                                             TimeTicks::Now());
-  }
-}
-
-// Deep copy because of the unique_ptrs
-XRInputSource::XRInputSource(const XRInputSource& other)
-    : active_frame_id(other.active_frame_id),
-      primary_input_pressed(other.primary_input_pressed),
-      selection_cancelled(other.selection_cancelled),
-      session_(other.session_),
-      source_id_(other.source_id_),
-      target_ray_space_(other.target_ray_space_),
-      grip_space_(other.grip_space_),
-      gamepad_(other.gamepad_),
-      emulated_position_(other.emulated_position_),
-      base_timestamp_(other.base_timestamp_) {
-  // Since these setters also set strings, for convenience, setting them via
-  // their existing setters.
-  SetTargetRayMode(other.target_ray_mode_);
-  SetHandedness(other.handedness_);
-
-  base_pose_matrix_ =
-      std::make_unique<TransformationMatrix>(*(other.base_pose_matrix_.get()));
-  pointer_transform_matrix_ = std::make_unique<TransformationMatrix>(
-      *(other.pointer_transform_matrix_.get()));
-}
-
 XRSpace* XRInputSource::gripSpace() const {
   if (target_ray_mode_ == kTrackedPointer) {
     return grip_space_;
@@ -165,20 +39,6 @@
   return gamepad_;
 }
 
-bool XRInputSource::InvalidatesSameObject(
-    const device::mojom::blink::XRInputSourceStatePtr& state) {
-  if ((state->gamepad && !gamepad_) || (!state->gamepad && gamepad_)) {
-    return true;
-  }
-
-  return false;
-}
-
-void XRInputSource::UpdateGamepad(const device::Gamepad& gamepad) {
-  DCHECK(gamepad_);
-  gamepad_->UpdateFromDeviceState(gamepad);
-}
-
 void XRInputSource::SetTargetRayMode(TargetRayMode target_ray_mode) {
   if (target_ray_mode_ == target_ray_mode)
     return;
@@ -238,6 +98,23 @@
   pointer_transform_matrix_ = std::move(pointer_transform_matrix);
 }
 
+// TODO(https://crbug.com/955101): Should Gamepad objects be updated in-place,
+// or should a new object be created on every call?
+void XRInputSource::SetGamepad(const base::Optional<device::Gamepad> gamepad) {
+  if (gamepad) {
+    if (!gamepad_) {
+      // TODO(https://crbug.com/955104): Is the Gamepad object creation time the
+      // correct time floor?
+      gamepad_ = MakeGarbageCollected<Gamepad>(this, 0, base_timestamp_,
+                                               TimeTicks::Now());
+    }
+
+    gamepad_->UpdateFromDeviceState(*gamepad);
+  } else {
+    gamepad_ = nullptr;
+  }
+}
+
 void XRInputSource::Trace(blink::Visitor* visitor) {
   visitor->Trace(session_);
   visitor->Trace(target_ray_space_);
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.h b/third_party/blink/renderer/modules/xr/xr_input_source.h
index f1b545e2..4f096eb 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.h
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.h
@@ -5,7 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_
 
-#include "device/vr/public/mojom/vr_service.mojom-blink.h"
 #include "third_party/blink/renderer/modules/gamepad/gamepad.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -35,18 +34,9 @@
     kHandLeft = 1,
     kHandRight = 2
   };
-
   enum TargetRayMode { kGaze = 1, kTrackedPointer = 2, kScreen = 3 };
 
-  static XRInputSource* CreateOrUpdateFrom(
-      XRInputSource* other /* may be null, input */,
-      XRSession* session,
-      const device::mojom::blink::XRInputSourceStatePtr& state);
-
   XRInputSource(XRSession*, uint32_t source_id);
-  XRInputSource(XRSession*,
-                const device::mojom::blink::XRInputSourceStatePtr& state);
-  XRInputSource(const XRInputSource& other);
   ~XRInputSource() override = default;
 
   XRSession* session() const { return session_; }
@@ -61,7 +51,11 @@
   uint32_t source_id() const { return source_id_; }
 
   void SetTargetRayMode(TargetRayMode);
+  void SetHandedness(Handedness);
+  void SetEmulatedPosition(bool emulated_position);
+  void SetBasePoseMatrix(std::unique_ptr<TransformationMatrix>);
   void SetPointerTransformMatrix(std::unique_ptr<TransformationMatrix>);
+  void SetGamepad(const base::Optional<device::Gamepad>);
 
   // Gamepad::Client
   GamepadHapticActuator* GetVibrationActuatorForGamepad(
@@ -82,17 +76,6 @@
   friend class XRGripSpace;
   friend class XRTargetRaySpace;
 
-  void SetHandedness(Handedness);
-  void SetEmulatedPosition(bool emulated_position);
-  void SetBasePoseMatrix(std::unique_ptr<TransformationMatrix>);
-
-  // Use to check if the updates that would/should be made by a given
-  // XRInputSourceState would invalidate any SameObject properties guaranteed
-  // by the idl, and thus require the xr_input_source to be recreated.
-  bool InvalidatesSameObject(
-      const device::mojom::blink::XRInputSourceStatePtr& state);
-  void UpdateGamepad(const device::Gamepad& gamepad);
-
   const Member<XRSession> session_;
   const uint32_t source_id_;
   Member<XRTargetRaySpace> target_ray_space_;
@@ -107,12 +90,10 @@
 
   bool emulated_position_ = false;
 
-  // TODO(crbug.com/945947): Revisit use of std::unique_ptr.
   std::unique_ptr<TransformationMatrix> base_pose_matrix_;
 
   // This is the transform to apply to the base_pose_matrix_ to get the pointer
   // matrix. In most cases it should be static.
-  // TODO(crbug.com/945947): Revisit use of std::unique_ptr.
   std::unique_ptr<TransformationMatrix> pointer_transform_matrix_;
 
   // gamepad_ uses this to get relative timestamps.
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.idl b/third_party/blink/renderer/modules/xr/xr_input_source.idl
index 9b347a8..ad23e109 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -23,5 +23,7 @@
   readonly attribute XRTargetRayMode targetRayMode;
   [SameObject] readonly attribute XRSpace targetRaySpace;
   [SameObject] readonly attribute XRSpace? gripSpace;
-  [SameObject] readonly attribute Gamepad? gamepad;
+
+  // TODO(https://crbug.com/955101): This should be tagged [SameObject].
+  readonly attribute Gamepad? gamepad;
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index 97bb889..a737206 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -762,34 +762,28 @@
     int16_t frame_id,
     const WTF::Vector<device::mojom::blink::XRInputSourceStatePtr>&
         input_states) {
-  bool input_sources_changed = false;
+  bool devices_changed = false;
 
   // Update any input sources with new state information. Any updated input
   // sources are marked as active.
   for (const auto& input_state : input_states) {
-    XRInputSource* stored_input_source =
-        input_sources_.at(input_state->source_id);
-    XRInputSource* input_source = XRInputSource::CreateOrUpdateFrom(
-        stored_input_source, this, input_state);
-
-    // Using pointer equality to determine if the pointer needs to be set.
-    if (stored_input_source != input_source) {
+    XRInputSource* input_source = input_sources_.at(input_state->source_id);
+    if (!input_source) {
+      input_source =
+          MakeGarbageCollected<XRInputSource>(this, input_state->source_id);
       input_sources_.Set(input_state->source_id, input_source);
-      input_sources_changed = true;
+      devices_changed = true;
     }
-
     input_source->active_frame_id = frame_id;
-    UpdateSelectState(input_source, input_state);
+    UpdateInputSourceState(input_source, input_state);
   }
 
-  // Remove any input sources that are inactive.  Note that this is done in
-  // two passes because HeapHashMap makes no guarantees about iterators on
-  // removal.
+  // Remove any input sources that are inactive..
   std::vector<uint32_t> inactive_sources;
   for (const auto& input_source : input_sources_.Values()) {
     if (input_source->active_frame_id != frame_id) {
       inactive_sources.push_back(input_source->source_id());
-      input_sources_changed = true;
+      devices_changed = true;
     }
   }
 
@@ -799,7 +793,7 @@
     }
   }
 
-  if (input_sources_changed) {
+  if (devices_changed) {
     DispatchEvent(
         *XRSessionEvent::Create(event_type_names::kInputsourceschange, this));
   }
@@ -875,12 +869,47 @@
   }
 }
 
-void XRSession::UpdateSelectState(
+void XRSession::UpdateInputSourceState(
     XRInputSource* input_source,
     const device::mojom::blink::XRInputSourceStatePtr& state) {
   if (!input_source || !state)
     return;
 
+  input_source->SetGamepad(state->gamepad);
+
+  // Update the input source's description if this state update
+  // includes them.
+  if (state->description) {
+    const device::mojom::blink::XRInputSourceDescriptionPtr& desc =
+        state->description;
+
+    input_source->SetTargetRayMode(
+        static_cast<XRInputSource::TargetRayMode>(desc->target_ray_mode));
+
+    input_source->SetHandedness(
+        static_cast<XRInputSource::Handedness>(desc->handedness));
+
+    input_source->SetEmulatedPosition(desc->emulated_position);
+
+    if (desc->pointer_offset && desc->pointer_offset->matrix.has_value()) {
+      const WTF::Vector<float>& m = desc->pointer_offset->matrix.value();
+      std::unique_ptr<TransformationMatrix> pointer_matrix =
+          std::make_unique<TransformationMatrix>(
+              m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
+              m[11], m[12], m[13], m[14], m[15]);
+      input_source->SetPointerTransformMatrix(std::move(pointer_matrix));
+    }
+  }
+
+  if (state->grip && state->grip->matrix.has_value()) {
+    const Vector<float>& m = state->grip->matrix.value();
+    std::unique_ptr<TransformationMatrix> grip_matrix =
+        std::make_unique<TransformationMatrix>(
+            m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10],
+            m[11], m[12], m[13], m[14], m[15]);
+    input_source->SetBasePoseMatrix(std::move(grip_matrix));
+  }
+
   // Handle state change of the primary input, which may fire events
   if (state->primary_input_clicked)
     OnSelect(input_source);
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h
index 129a63a7..c7f533e 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -192,8 +192,9 @@
   void UpdateCanvasDimensions(Element*);
   void ApplyPendingRenderState();
 
-  void UpdateSelectState(XRInputSource*,
-                         const device::mojom::blink::XRInputSourceStatePtr&);
+  void UpdateInputSourceState(
+      XRInputSource*,
+      const device::mojom::blink::XRInputSourceStatePtr&);
   XRInputSourceEvent* CreateInputSourceEvent(const AtomicString&,
                                              XRInputSource*);
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index aa6110b..a5397e5 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -708,7 +708,6 @@
     "fonts/shaping/harfbuzz_shaper.h",
     "fonts/shaping/run_segmenter.cc",
     "fonts/shaping/run_segmenter.h",
-    "fonts/shaping/shape_cache.cc",
     "fonts/shaping/shape_cache.h",
     "fonts/shaping/shape_result.cc",
     "fonts/shaping/shape_result.h",
@@ -1478,11 +1477,6 @@
     "//ui/gfx/geometry",
   ]
 
-  # This is faster on armv7, untested on other CPUs (e.g. mips, power, etc).
-  # TODO(cavalcantii): add next xxhash.
-  defines = [ "USE_FUNCTION_CITYHASH" ]
-  deps += [ "//third_party/smhasher:cityhash" ]
-
   if (is_mac) {
     sources -= [
       "fonts/skia/font_cache_skia.cc",
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc
deleted file mode 100644
index 3c486fe..0000000
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2012, 2017 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_cache.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_hasher.h"
-#if defined(USE_FUNCTION_CITYHASH)
-#include "third_party/smhasher/src/City.h"
-#endif
-
-namespace blink {
-
-void ShapeCache::SmallStringKey::HashString() {
-// TODO(cavalcanti): next add xxhash.
-#if defined(USE_FUNCTION_CITYHASH)
-  hash_ = static_cast<unsigned>(
-      CityHash64((const char*)characters_, length_ * sizeof(UChar)));
-#endif
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
index 44e55bc..7d5819d 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h
@@ -27,6 +27,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_CACHE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_CACHE_H_
 
+#include "base/containers/span.h"
+#include "base/hash/hash.h"
 #include "base/memory/weak_ptr.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/text/text_run.h"
@@ -50,8 +52,6 @@
   class SmallStringKey {
     DISALLOW_NEW();
 
-    void HashString();
-
    public:
     static unsigned Capacity() { return kCapacity; }
 
@@ -72,7 +72,8 @@
         characters_[i] = characters[i];
       }
 
-      HashString();
+      hash_ = static_cast<unsigned>(base::FastHash(
+          base::as_bytes(base::make_span(characters_, length_))));
     }
 
     SmallStringKey(base::span<const UChar> characters, TextDirection direction)
@@ -80,7 +81,8 @@
           direction_(static_cast<unsigned>(direction)) {
       DCHECK(characters.size() <= kCapacity);
       memcpy(characters_, characters.data(), characters.size_bytes());
-      HashString();
+      hash_ = static_cast<unsigned>(base::FastHash(
+          base::as_bytes(base::make_span(characters_, length_))));
     }
 
     const UChar* Characters() const { return characters_; }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
index 5eabcdc0..02023eb5 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
@@ -1212,13 +1212,14 @@
   std::unique_ptr<Canvas2DLayerBridge> bridge =
       MakeBridge(IntSize(300, 300), Canvas2DLayerBridge::kEnableAcceleration,
                  color_params);
+  gfx::ColorSpace expected_color_space = gfx::ColorSpace::CreateSRGB();
   std::vector<cc::DrawImage> images = {
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)),
                     SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
-                    SkMatrix::I(), 0u),
+                    SkMatrix::I(), 0u, expected_color_space),
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)),
                     SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
-                    0u)};
+                    0u, expected_color_space)};
 
   bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
   bridge->Canvas()->drawImageRect(
@@ -1238,10 +1239,10 @@
   std::vector<cc::DrawImage> images = {
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)),
                     SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
-                    SkMatrix::I(), 0u),
+                    SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace()),
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)),
                     SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
-                    0u)};
+                    0u, color_params.GetStorageGfxColorSpace())};
 
   bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
   bridge->Canvas()->drawImageRect(
@@ -1264,13 +1265,13 @@
   std::vector<cc::DrawImage> images = {
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)),
                     SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
-                    SkMatrix::I(), 0u),
+                    SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace()),
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)),
                     SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
-                    0u),
+                    0u, color_params.GetStorageGfxColorSpace()),
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)),
                     SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
-                    0u)};
+                    0u, color_params.GetStorageGfxColorSpace())};
 
   // First 2 images are budgeted, they should remain locked after the op.
   bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
@@ -1297,9 +1298,10 @@
                  color_params);
   bridge->DisableDeferral(DisableDeferralReason::kDisableDeferralReasonUnknown);
 
-  auto image = cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)),
-                             SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
-                             SkMatrix::I(), 0u);
+  auto image =
+      cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)),
+                    SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
+                    SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace());
   bridge->Canvas()->drawImage(image.paint_image(), 0u, 0u, nullptr);
   EXPECT_EQ(image_decode_cache_.num_locked_images(), 1);
 
@@ -1320,10 +1322,10 @@
   std::vector<cc::DrawImage> images = {
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(10, 10)),
                     SkIRect::MakeWH(10, 10), kNone_SkFilterQuality,
-                    SkMatrix::I(), 0u),
+                    SkMatrix::I(), 0u, color_params.GetStorageGfxColorSpace()),
       cc::DrawImage(cc::CreateDiscardablePaintImage(gfx::Size(20, 20)),
                     SkIRect::MakeWH(5, 5), kNone_SkFilterQuality, SkMatrix::I(),
-                    0u)};
+                    0u, color_params.GetStorageGfxColorSpace())};
   bridge->Canvas()->drawImage(images[0].paint_image(), 0u, 0u, nullptr);
 
   // Lose the context and ensure that the image provider is not used.
diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params.cc b/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
index 992508d..153a0e0 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_color_params.cc
@@ -118,14 +118,9 @@
 }
 
 sk_sp<SkColorSpace> CanvasColorParams::GetSkColorSpace() const {
-  return CanvasColorSpaceToSkColorSpace(color_space_);
-}
-
-sk_sp<SkColorSpace> CanvasColorParams::CanvasColorSpaceToSkColorSpace(
-    CanvasColorSpace color_space) {
   skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB;
   skcms_TransferFunction transferFn = SkNamedTransferFn::kSRGB;
-  switch (color_space) {
+  switch (color_space_) {
     case kSRGBCanvasColorSpace:
       break;
     case kLinearRGBCanvasColorSpace:
diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params.h b/third_party/blink/renderer/platform/graphics/canvas_color_params.h
index 175a2b8..3073b10 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_color_params.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_color_params.h
@@ -79,8 +79,6 @@
   // Return the color space of the underlying data for the canvas.
   gfx::ColorSpace GetStorageGfxColorSpace() const;
   sk_sp<SkColorSpace> GetSkColorSpace() const;
-  static sk_sp<SkColorSpace> CanvasColorSpaceToSkColorSpace(
-      CanvasColorSpace color_space);
   SkAlphaType GetSkAlphaType() const;
   const SkSurfaceProps* GetSkSurfaceProps() const;
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index 9c150be..71ca357 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -828,6 +828,7 @@
  public:
   CanvasImageProvider(cc::ImageDecodeCache* cache_n32,
                       cc::ImageDecodeCache* cache_f16,
+                      const gfx::ColorSpace& target_color_space,
                       SkColorType target_color_type,
                       bool is_hardware_decode_cache);
   ~CanvasImageProvider() override = default;
@@ -856,17 +857,19 @@
 CanvasResourceProvider::CanvasImageProvider::CanvasImageProvider(
     cc::ImageDecodeCache* cache_n32,
     cc::ImageDecodeCache* cache_f16,
+    const gfx::ColorSpace& target_color_space,
     SkColorType canvas_color_type,
     bool is_hardware_decode_cache)
     : is_hardware_decode_cache_(is_hardware_decode_cache),
       playback_image_provider_n32_(cache_n32,
+                                   target_color_space,
                                    cc::PlaybackImageProvider::Settings()),
       weak_factory_(this) {
   // If the image provider may require to decode to half float instead of
   // uint8, create a f16 PlaybackImageProvider with the passed cache.
   if (canvas_color_type == kRGBA_F16_SkColorType) {
     DCHECK(cache_f16);
-    playback_image_provider_f16_.emplace(cache_f16,
+    playback_image_provider_f16_.emplace(cache_f16, target_color_space,
                                          cc::PlaybackImageProvider::Settings());
   }
 }
@@ -977,8 +980,8 @@
   if (ColorParams().PixelFormat() == kF16CanvasPixelFormat)
     cache_f16 = ImageDecodeCacheF16();
   canvas_image_provider_ = std::make_unique<CanvasImageProvider>(
-      ImageDecodeCacheRGBA8(), cache_f16, color_params_.GetSkColorType(),
-      use_hardware_decode_cache());
+      ImageDecodeCacheRGBA8(), cache_f16, gfx::ColorSpace::CreateSRGB(),
+      color_params_.GetSkColorType(), use_hardware_decode_cache());
 
   cc::SkiaPaintCanvas::ContextFlushes context_flushes;
   if (IsAccelerated() &&
@@ -1109,26 +1112,24 @@
 }
 
 cc::ImageDecodeCache* CanvasResourceProvider::ImageDecodeCacheRGBA8() {
-  auto color_space = kSRGBCanvasColorSpace;
 
   if (use_hardware_decode_cache()) {
     return context_provider_wrapper_->ContextProvider()->ImageDecodeCache(
-        kN32_SkColorType,
-        blink::CanvasColorParams::CanvasColorSpaceToSkColorSpace(color_space));
+        kN32_SkColorType, ColorParams().GetSkColorSpace());
   }
 
-  return Image::SharedCCDecodeCache(color_space, kRGBA8CanvasPixelFormat);
+  return Image::SharedCCDecodeCache(ColorParams().ColorSpace(),
+                                    kRGBA8CanvasPixelFormat);
 }
 
 cc::ImageDecodeCache* CanvasResourceProvider::ImageDecodeCacheF16() {
-  auto color_space = kSRGBCanvasColorSpace;
 
   if (use_hardware_decode_cache()) {
     return context_provider_wrapper_->ContextProvider()->ImageDecodeCache(
-        kRGBA_F16_SkColorType,
-        blink::CanvasColorParams::CanvasColorSpaceToSkColorSpace(color_space));
+        kRGBA_F16_SkColorType, ColorParams().GetSkColorSpace());
   }
-  return Image::SharedCCDecodeCache(color_space, kF16CanvasPixelFormat);
+  return Image::SharedCCDecodeCache(ColorParams().ColorSpace(),
+                                    kF16CanvasPixelFormat);
 }
 
 void CanvasResourceProvider::RecycleResource(
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 03fc947..99dfa46 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -305,6 +305,16 @@
       HitTestRect::BuildRegion(touch_action_rects_in_layer_space));
 }
 
+bool PaintArtifactCompositor::HasComposited(
+    CompositorElementId element_id) const {
+  // |Update| sets the LayerTreeHost's |elements_in_property_trees_| to the
+  // elements composited by PaintArtifactCompositor. Look up whether the
+  // given |element_id| has been created.
+  DCHECK(!NeedsUpdate()) << "This should only be called after an update";
+  return root_layer_->layer_tree_host()->elements_in_property_trees().count(
+      element_id);
+}
+
 bool PaintArtifactCompositor::PropertyTreeStateChanged(
     const PropertyTreeState& state) const {
   const auto& root = PropertyTreeState::Root();
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index 2beac678d..f5eb03e5 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -190,6 +190,10 @@
   bool NeedsUpdate() const { return needs_update_; }
   void ClearNeedsUpdateForTesting() { needs_update_ = false; }
 
+  // Returns true if a property tree node associated with |element_id| exists
+  // on any of the PropertyTrees constructed by |Update|.
+  bool HasComposited(CompositorElementId element_id) const;
+
  private:
   // A pending layer is a collection of paint chunks that will end up in
   // the same cc::Layer.
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
index 3b3a669..afeb90c 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter.cc
@@ -3,11 +3,11 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
 #include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/effects/SkColorMatrix.h"
 #include "third_party/skia/include/effects/SkHighContrastFilter.h"
 #include "third_party/skia/include/effects/SkTableColorFilter.h"
 
 namespace blink {
-
 namespace {
 
 bool ShouldApplyToImage(const DarkModeSettings& settings,
@@ -23,6 +23,16 @@
   }
 }
 
+// |grayscale_percent| should be between 0.0 and 1.0.
+sk_sp<SkColorFilter> MakeGrayscaleFilter(float grayscale_percent) {
+  DCHECK_GE(grayscale_percent, 0.0f);
+  DCHECK_LE(grayscale_percent, 1.0f);
+
+  SkColorMatrix grayscale_matrix;
+  grayscale_matrix.setSaturation(1.0f - grayscale_percent);
+  return SkColorFilters::Matrix(grayscale_matrix);
+}
+
 }  // namespace
 
 DarkModeFilter::DarkModeFilter()
@@ -69,23 +79,10 @@
   config.fContrast = settings_.contrast;
   default_filter_ = SkHighContrastFilter::Make(config);
 
-  SkHighContrastConfig image_config = config;
-  switch (settings_.image_style) {
-    case DarkModeImageStyle::kGrayscale:
-      image_config.fGrayscale = true;
-      image_config.fInvertStyle = SkHighContrastConfig::InvertStyle::kNoInvert;
-      image_filter_ = SkHighContrastFilter::Make(image_config);
-      break;
-    case DarkModeImageStyle::kGrayscaleAndInvert:
-      DCHECK_NE(image_config.fInvertStyle,
-                SkHighContrastConfig::InvertStyle::kNoInvert);
-      image_config.fGrayscale = true;
-      image_filter_ = SkHighContrastFilter::Make(image_config);
-      break;
-    case DarkModeImageStyle::kDefault:
-      image_filter_.reset(nullptr);
-      break;
-  }
+  if (settings_.image_grayscale_percent > 0.0f)
+    image_filter_ = MakeGrayscaleFilter(settings_.image_grayscale_percent);
+  else
+    image_filter_.reset(nullptr);
 }
 
 Color DarkModeFilter::ApplyIfNeeded(const Color& color) {
@@ -98,8 +95,8 @@
 }
 
 // TODO(gilmanmh): Investigate making |image| a const reference. This code
-// relies on Image::ShouldApplyDarkModeFilter(), which is not const. If it could
-// be made const, then |image| could also be const.
+// relies on Image::ShouldApplyDarkModeFilter(), which is not const. If it
+// could be made const, then |image| could also be const.
 void DarkModeFilter::ApplyToImageFlagsIfNeeded(const FloatRect& src_rect,
                                                Image* image,
                                                cc::PaintFlags* flags) {
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
index 0c7c2360..91fa0c1 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_settings.h
@@ -26,16 +26,6 @@
   kFilterSmart,
 };
 
-// For images that should have a filter applied, which filter should be used?
-enum class DarkModeImageStyle {
-  // Invert images the same way as other elements.
-  kDefault,
-  // Apply grayscale to images that would be inverted, but don't invert them.
-  kGrayscale,
-  // Apply grayscale to images as well as inverting them.
-  kGrayscaleAndInvert
-};
-
 enum class DarkModePagePolicy {
   // Apply dark-mode filter to all frames, regardless of content.
   kFilterAll,
@@ -46,9 +36,9 @@
 struct DarkModeSettings {
   DarkMode mode = DarkMode::kOff;
   bool grayscale = false;
-  float contrast = 0.0;  // Valid range from -1.0 to 1.0
+  float image_grayscale_percent = 0.0;  // Valid range from 0.0 to 1.0
+  float contrast = 0.0;                 // Valid range from -1.0 to 1.0
   DarkModeImagePolicy image_policy = DarkModeImagePolicy::kFilterAll;
-  DarkModeImageStyle image_style = DarkModeImageStyle::kDefault;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index dee6f73a..6d4844d 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -75,9 +75,7 @@
     if (!decode_caches_[index]) {
       decode_caches_[index] = std::make_unique<cc::SoftwareImageDecodeCache>(
           CanvasColorParams::PixelFormatToSkColorType(pixel_format),
-          locked_memory_limit_bytes_, PaintImage::kDefaultGeneratorClientId,
-          blink::CanvasColorParams::CanvasColorSpaceToSkColorSpace(
-              color_space));
+          locked_memory_limit_bytes_, PaintImage::kDefaultGeneratorClientId);
     }
     return decode_caches_[index].get();
   }
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h
index 8f2ae61..0684133f 100644
--- a/third_party/blink/renderer/platform/heap/heap.h
+++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -523,10 +523,9 @@
                 "T needs to be a garbage collected object");
   void* memory = T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value);
   HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
-  header->MarkIsInConstruction();
   // Placement new as regular operator new() is deleted.
   T* object = ::new (memory) T(std::forward<Args>(args)...);
-  header->UnmarkIsInConstruction();
+  header->MarkFullyConstructed();
   return object;
 }
 
@@ -545,10 +544,9 @@
   void* memory = T::AllocateObject(sizeof(T) + additional_bytes.value,
                                    IsEagerlyFinalizedType<T>::value);
   HeapObjectHeader* header = HeapObjectHeader::FromPayload(memory);
-  header->MarkIsInConstruction();
   // Placement new as regular operator new() is deleted.
   T* object = ::new (memory) T(std::forward<Args>(args)...);
-  header->UnmarkIsInConstruction();
+  header->MarkFullyConstructed();
   return object;
 }
 
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
index 04159a8e..16d23f61 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -75,7 +75,7 @@
     uint32_t gc_info_index = GCInfoTrait<HeapVectorBacking<T>>::Index();
     NormalPageArena* arena = static_cast<NormalPageArena*>(
         state->Heap().VectorBackingArena(gc_info_index));
-    return reinterpret_cast<T*>(arena->AllocateObject(
+    return MarkAsConstructed<T>(arena->AllocateObject(
         ThreadHeap::AllocationSizeFromSize(size), gc_info_index));
   }
   template <typename T>
@@ -86,7 +86,7 @@
     uint32_t gc_info_index = GCInfoTrait<HeapVectorBacking<T>>::Index();
     NormalPageArena* arena = static_cast<NormalPageArena*>(
         state->Heap().ExpandedVectorBackingArena(gc_info_index));
-    return reinterpret_cast<T*>(arena->AllocateObject(
+    return MarkAsConstructed<T>(arena->AllocateObject(
         ThreadHeap::AllocationSizeFromSize(size), gc_info_index));
   }
   static void FreeVectorBacking(void*);
@@ -100,7 +100,7 @@
     ThreadState* state =
         ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
     const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(HeapVectorBacking<T>);
-    return reinterpret_cast<T*>(state->Heap().AllocateOnArenaIndex(
+    return MarkAsConstructed<T>(state->Heap().AllocateOnArenaIndex(
         state, size, BlinkGC::kInlineVectorArenaIndex, gc_info_index,
         type_name));
   }
@@ -118,7 +118,7 @@
         ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
     const char* type_name =
         WTF_HEAP_PROFILER_TYPE_NAME(HeapHashTableBacking<HashTable>);
-    return reinterpret_cast<T*>(state->Heap().AllocateOnArenaIndex(
+    return MarkAsConstructed<T>(state->Heap().AllocateOnArenaIndex(
         state, size, BlinkGC::kHashTableArenaIndex, gc_info_index, type_name));
   }
   template <typename T, typename HashTable>
@@ -148,7 +148,7 @@
 
   template <typename Return, typename Metadata>
   static Return Malloc(size_t size, const char* type_name) {
-    return reinterpret_cast<Return>(ThreadHeap::Allocate<Metadata>(
+    return MarkAsConstructed<Return>(ThreadHeap::Allocate<Metadata>(
         size, IsEagerlyFinalizedType<Metadata>::value));
   }
 
@@ -298,6 +298,13 @@
   }
 
  private:
+  template <typename T>
+  static T* MarkAsConstructed(Address address) {
+    HeapObjectHeader::FromPayload(reinterpret_cast<void*>(address))
+        ->MarkFullyConstructed();
+    return reinterpret_cast<T*>(address);
+  }
+
   static void BackingFree(void*);
   static bool BackingExpand(void*, size_t);
   static bool BackingShrink(void*,
diff --git a/third_party/blink/renderer/platform/heap/heap_page.h b/third_party/blink/renderer/platform/heap/heap_page.h
index d0fffbf3..de64181 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.h
+++ b/third_party/blink/renderer/platform/heap/heap_page.h
@@ -149,7 +149,7 @@
 //
 // | random magic value (32 bits) | Only present on 64-bit platforms.
 // | gc_info_index (14 bits)      |
-// | in construction (1 bit)      |
+// | in construction (1 bit)      | true: bit not set; false bit set
 // | size (14 bits)               | Actually 17 bits because sizes are aligned.
 // | wrapper mark bit (1 bit)     |
 // | unused (1 bit)               |
@@ -227,9 +227,8 @@
   void Unmark();
   bool TryMark();
 
-  void MarkIsInConstruction();
-  void UnmarkIsInConstruction();
   bool IsInConstruction() const;
+  void MarkFullyConstructed();
 
   // The payload starts directly after the HeapObjectHeader, and the payload
   // size does not include the sizeof(HeapObjectHeader).
@@ -931,17 +930,12 @@
 }
 
 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::IsInConstruction() const {
-  return encoded_ & kHeaderIsInConstructionMask;
+  return (encoded_ & kHeaderIsInConstructionMask) == 0;
 }
 
-NO_SANITIZE_ADDRESS inline void HeapObjectHeader::MarkIsInConstruction() {
-  DCHECK(!IsInConstruction());
-  encoded_ = encoded_ | kHeaderIsInConstructionMask;
-}
-
-NO_SANITIZE_ADDRESS inline void HeapObjectHeader::UnmarkIsInConstruction() {
+NO_SANITIZE_ADDRESS inline void HeapObjectHeader::MarkFullyConstructed() {
   DCHECK(IsInConstruction());
-  encoded_ = encoded_ & ~kHeaderIsInConstructionMask;
+  encoded_ |= kHeaderIsInConstructionMask;
 }
 
 NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::IsValid() const {
@@ -1127,9 +1121,9 @@
   magic_ = GetMagic();
 #endif
 
-  DCHECK(gc_info_index < GCInfoTable::kMaxIndex);
+  DCHECK_LT(gc_info_index, GCInfoTable::kMaxIndex);
   DCHECK_LT(size, kNonLargeObjectPageSizeMax);
-  DCHECK(!(size & kAllocationMask));
+  DCHECK_EQ(0u, size & kAllocationMask);
   encoded_ =
       static_cast<uint32_t>((gc_info_index << kHeaderGCInfoIndexShift) | size);
   if (header_location == kNormalPage) {
@@ -1140,6 +1134,7 @@
   } else {
     DCHECK(PageFromObject(this)->IsLargeObjectPage());
   }
+  DCHECK(IsInConstruction());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
index 4ee0a09..1b5c03b 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
@@ -1388,4 +1388,13 @@
   ASSERT_FALSE(decoder->Failed());
 }
 
+TEST(AnimatedPNGTests, TrnsMeansAlpha) {
+  const char* png_file =
+      "/images/resources/"
+      "png-animated-idat-part-of-animation.png";
+  auto decoder = CreatePNGDecoderWithPngData(png_file);
+  auto* frame = decoder->DecodeFrameBufferAtIndex(0);
+  ASSERT_TRUE(frame->HasAlpha());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
index 14cdea9..dfe6bdf 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.cc
@@ -547,7 +547,7 @@
     new_frame_.start_offset = 0;
   }
 
-  // Process APNG chunks manually, pass other chunks to libpng.
+  // Process some chunks manually, and pass some to libpng.
   for (png_uint_32 length = 0; reader.size() >= read_offset_ + 8;
        // This call will not overflow since it was already checked below, after
        // calculating chunk_end_offset.
@@ -630,13 +630,24 @@
     } else if (IsChunk(chunk, "fdAT")) {
       ignore_animation_ = true;
     } else {
-      png_process_data(png_, info_, const_cast<png_byte*>(chunk), 8);
-      ProcessData(reader, read_offset_ + 8, length + 4);
-      if (IsChunk(chunk, "IHDR")) {
-        parsed_ihdr_ = true;
-        ihdr_offset_ = read_offset_;
-        width_ = png_get_image_width(png_, info_);
-        height_ = png_get_image_height(png_, info_);
+      bool ihdr = IsChunk(chunk, "IHDR");
+      auto is_necessary = [](const png_byte* chunk) {
+        for (const char* tag :
+             {"PLTE", "IEND", "tRNS", "cHRM", "iCCP", "sRGB", "gAMA"}) {
+          if (IsChunk(chunk, tag))
+            return true;
+        }
+        return false;
+      };
+      if (ihdr || is_necessary(chunk)) {
+        png_process_data(png_, info_, const_cast<png_byte*>(chunk), 8);
+        ProcessData(reader, read_offset_ + 8, length + 4);
+        if (ihdr) {
+          parsed_ihdr_ = true;
+          ihdr_offset_ = read_offset_;
+          width_ = png_get_image_width(png_, info_);
+          height_ = png_get_image_height(png_, info_);
+        }
       }
     }
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 761a021..def6f6bb 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -314,22 +314,6 @@
     // We'll handle adding these headers to navigations outside of Blink.
     if (strncmp(destination_value, "document", 8) != 0 &&
         request.GetRequestContext() != mojom::RequestContextType::INTERNAL) {
-      const char* site_value = "cross-site";
-      if (url_origin->IsSameSchemeHostPort(
-              fetch_client_settings_object.GetSecurityOrigin())) {
-        site_value = "same-origin";
-      } else {
-        OriginAccessEntry access_entry(
-            request.Url().Protocol(), request.Url().Host(),
-            network::mojom::CorsOriginAccessMatchMode::
-                kAllowRegistrableDomains);
-        if (access_entry.MatchesOrigin(
-                *fetch_client_settings_object.GetSecurityOrigin()) ==
-            network::cors::OriginAccessEntry::kMatchesOrigin) {
-          site_value = "same-site";
-        }
-      }
-
       if (blink::RuntimeEnabledFeatures::FetchMetadataDestinationEnabled()) {
         request.SetHttpHeaderField("Sec-Fetch-Dest", destination_value);
       }
@@ -337,8 +321,11 @@
       request.SetHttpHeaderField(
           "Sec-Fetch-Mode",
           FetchRequestModeToString(request.GetFetchRequestMode()));
-      request.SetHttpHeaderField("Sec-Fetch-Site", site_value);
-      // We don't set `Sec-Fetch-User` for subresource requests.
+
+      // Note that the `Sec-Fetch-User` header is always false (and therefore
+      // omitted) for subresource requests. Likewise, note that we rely on
+      // Blink's embedder to set `Sec-Fetch-Site`, as we don't want to trust the
+      // renderer to assert its own origin.
     }
   }
 }
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.cc b/third_party/blink/renderer/platform/text/text_break_iterator.cc
index ee66cba4..f69be5c3 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -337,12 +337,8 @@
       case BreakSpaceType::kAfterEverySpace:
         if (is_last_space)
           return i;
-        if (is_space) {
-          // Might be allowed to break before the first space after a word.
-          if (lineBreakType == LineBreakType::kBreakAll)
-            return i;
+        if (is_space)
           continue;
-        }
         break;
     }
 
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 16571be9b..0dfea7d 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -510,7 +510,6 @@
             'third_party/blink/renderer/modules/device_orientation/',
             'third_party/blink/renderer/modules/gamepad/',
             'third_party/blink/renderer/modules/sensor/',
-            'third_party/blink/renderer/modules/xr/',
         ],
         'allowed': [
             'base::subtle::Atomic32',
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index aaa8798..3ab0caca 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -37,6 +37,8 @@
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/no-clearance-adjoining-opposite-float.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/no-clearance-due-to-large-margin-after-left-right.html [ Pass ]
 crbug.com/877946 external/wpt/css/CSS2/linebox/anonymous-inline-inherit-001.html [ Pass ]
+crbug.com/769039 external/wpt/css/CSS2/normal-flow/max-height-separates-margin.html [ Pass ]
+crbug.com/769039 external/wpt/css/CSS2/normal-flow/min-height-separates-margin.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/text/white-space-bidirectionality-001.xht [ Pass ]
 crbug.com/859233 external/wpt/css/css-break/hit-test-inline-fragmentation-with-border-radius.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-004.html [ Pass ]
@@ -62,9 +64,6 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2b.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/vert-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Pass ]
 
-crbug.com/952254 external/wpt/css/css-text/word-break/word-break-break-all-017.html [ Failure ]
-crbug.com/952254 external/wpt/css/css-text/word-break/word-break-break-all-022.html [ Failure ]
-
 # New failures are appended below by the script.
 crbug.com/591099 css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ]
 crbug.com/591099 css3/filters/effect-drop-shadow-hw.html [ Pass ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index c34d0c1..00e274b5 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -313,6 +313,8 @@
 
 # LayoutNG fixes this
 crbug.com/408895 external/wpt/css/CSS2/floats/overhanging-float-paint-order.html [ Failure ]
+crbug.com/769039 external/wpt/css/CSS2/normal-flow/max-height-separates-margin.html [ Failure ]
+crbug.com/769039 external/wpt/css/CSS2/normal-flow/min-height-separates-margin.html [ Failure ]
 
 # ====== Paint team owned tests to here ======
 
@@ -1913,10 +1915,6 @@
 crbug.com/6122 external/wpt/css/css-text/text-transform/text-transform-shaping-002.html [ Failure ]
 crbug.com/6122 external/wpt/css/css-text/text-transform/text-transform-shaping-003.html [ Failure ]
 
-crbug.com/952254 external/wpt/css/css-text/white-space/break-spaces-008.html [ Failure ]
-crbug.com/952254 external/wpt/css/css-text/white-space/break-spaces-before-first-char-004.html [ Failure ]
-crbug.com/952254 external/wpt/css/css-text/white-space/break-spaces-before-first-char-005.html [ Failure ]
-
 # These are added to W3CImportExpectations as Skip, remove when next import is done.
 crbug.com/666657 external/wpt/css/css-text/hanging-punctuation [ Skip ]
 
@@ -5576,7 +5574,13 @@
 crbug.com/937170 [ Linux Win7 ] external/wpt/IndexedDB/interleaved-cursors-large.html [ Pass Timeout ]
 crbug.com/937991 [ Win7 Release ] http/tests/devtools/cache-storage/cache-data.js [ Pass Timeout ]
 
+# These video tests seem to take a screenshot too early.
+crbug.com/963141 [ Mac Win ] media/video-object-fit.html [ Pass Failure ]
+crbug.com/963141 [ Mac Win ] media/video-object-fit-change.html [ Pass Failure ]
+crbug.com/963141 [ Mac Win ] media/controls/video-overlay-cast-light-rendering.html [ Pass Failure ]
+
 # Disable tests in order to land
 # https://webrtc-review.googlesource.com/c/src/+/135948
 crbug.com/943975 external/wpt/webrtc/RTCDataChannel-send.html [ Pass Failure ]
 crbug.com/943975 external/wpt/webrtc/RTCSctpTransport-maxMessageSize.html [ Pass Failure ]
+crbug.com/943975 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCSctpTransport-maxMessageSize.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/max-height-separates-margin.html b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/max-height-separates-margin.html
new file mode 100644
index 0000000..b14ed54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/max-height-separates-margin.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#collapsing-margins">
+<p>Test passes if there is a filled green square.</p>
+<div style="width:100px; max-height:50px; background: green;">
+  <div style="width:100px; height:51px; background:green; margin-bottom:10px;"></div>
+</div>
+<div style="width: 100px; height: 50px; background: green;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/min-height-separates-margin.html b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/min-height-separates-margin.html
new file mode 100644
index 0000000..1e14492
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/normal-flow/min-height-separates-margin.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#collapsing-margins">
+<p>Test passes if there is a filled green square.</p>
+<div style="width:100px; min-height:50px; background: green;">
+  <div style="width:100px; height:49px; background:green; margin-bottom:10px;"></div>
+</div>
+<div style="width: 100px; height: 50px; background: green;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-010.html
new file mode 100644
index 0000000..ec7904f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/break-spaces-010.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text Test: white-space: break-spaces</title>
+<link rel="author" title="Javier Fernandez" href="mailto:jfernandez@igalia.com" />
+<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-break-spaces">
+<meta name="flags" content="ahem">
+<link rel="match" href="reference/white-space-break-spaces-005-ref.html">
+<meta name="assert" content="break-spaces only allows breaking after a white space, hence, a preserved white space may overflow.">
+<style>
+div {
+  font: 25px/1 Ahem;
+}
+.fail {
+  position: absolute;
+  color: red;
+  z-index: -1;
+}
+span { color: green; }
+.test {
+  color: green;
+  width: 4ch;
+
+  white-space: break-spaces;
+}
+</style>
+
+<p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
+<div class="fail">XXXX<br><span>X</span>XX<span>X<br>XXXX<br>XXXX</span></div>
+<div class="test">XXXX  XX</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-017.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-017.html
index 6cf3be6b..88d7c6d0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-017.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-017.html
@@ -30,5 +30,5 @@
 }
 </style>
 <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p>
-<div class="red">X<br>XX X<br>X X <br>XX X</div>
+<div class="red">X X <br>X X <br>X X <br>XX X</div>
 <div class="test">X XX XX X XX X</div>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub-expected.txt
deleted file mode 100644
index 769c078..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Same-Origin -> Cross-Site -> Same-Origin redirect assert_equals: site expected "cross-site" but got "same-origin"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub-expected.txt
deleted file mode 100644
index 8455937..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Same-Origin -> Same-Site -> Same-Origin redirect assert_equals: site expected "same-site" but got "same-origin"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub-expected.txt
deleted file mode 100644
index 4723beb..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Same-Origin -> Same-Origin redirect
-FAIL Same-Origin -> Same-Site redirect assert_equals: site expected "same-site" but got "same-origin"
-FAIL Same-Origin -> Cross-Site redirect assert_equals: site expected "cross-site" but got "same-origin"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub-expected.txt
deleted file mode 100644
index 638af52..0000000
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Same-Site -> Same-Origin redirect
-PASS Same-Site -> Same-Site redirect
-FAIL Same-Site -> Cross-Site redirect assert_equals: site expected "cross-site" but got "same-site"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html
new file mode 100644
index 0000000..1e07e43
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_child_parent.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Click targets the nearest common ancestor</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/resources/testdriver.js"></script>
+    <script src="/resources/testdriver-actions.js"></script>
+    <script src="/resources/testdriver-vendor.js"></script>
+    <style>
+    div {
+      padding: 10px;
+      margin: 5px;
+    }
+    a {
+      background: grey;
+    }
+    </style>
+  </head>
+  <body id='body'>
+    <h1>Click targeting when targets of down and up are child and parents</h1>
+    This test verifies that click event always goes to the first common ancestor of down and up event targets.
+
+    <ul>
+      <li>Press down the primary button on link 1 and move onto green container and release.</li>
+      <li>Press down the primary button on red container and move onto link 2 and release.</li>
+      <li>Click done.</li>
+    </ul>
+
+    <div id="link_container1" style="background: green">
+      <a id="link1" href="#">link1</a>
+    </div>
+
+    <div id="link_container2" style="background: red">
+      <a id="link2" href="#">link2</a>
+    </div>
+    <button id="done">Done</button>
+    <script>
+    var test_click_target = async_test("Click targets the nearest common ancestor");
+
+    // Prevent drag to avoid interfering with the click.
+    document.addEventListener('dragstart', (e) => e.preventDefault());
+
+    var events = [];
+    var nodes = ['link_container1', 'link1', 'link_container2', 'link2', 'body'];
+
+    for (var i = 0; i < nodes.length; i++) {
+     ['mousedown', 'mouseup', 'click'].forEach((eventName) => {
+       document.getElementById(nodes[i]).addEventListener(eventName, (e) => {
+         if (e.eventPhase == Event.AT_TARGET)
+           events.push(e.type + '@' + e.target.id);
+        });
+      });
+    }
+    document.getElementById('done').addEventListener('click', () => {
+      test_click_target.step(() => {
+        assert_equals (events.join(','),
+        "mousedown@link1,mouseup@link_container1,click@link_container1,mousedown@link_container2,mouseup@link2,click@link_container2",
+        "Click should be sent to the nearest common ancestor");
+      });
+      test_click_target.done();
+    });
+
+    // Inject mouse events.
+    var actions = new test_driver.Actions();
+    actions.pointerMove(0, 0, {origin: document.getElementById('link1')})
+           .pointerDown()
+           .pointerMove(0, 0, {origin: document.getElementById('link_container1')})
+           .pointerUp()
+           .pointerMove(0, 0, {origin: document.getElementById('link_container2')})
+           .pointerDown()
+           .pointerMove(0, 0, {origin: document.getElementById('link2')})
+           .pointerUp()
+           .pointerMove(0, 0, {origin: document.getElementById('done')})
+           .pointerDown()
+           .pointerUp()
+           .send();
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target.html b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/uievents/click/click_event_target.html
rename to third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html
index ffe5dba..0306b6f 100644
--- a/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target.html
+++ b/third_party/blink/web_tests/external/wpt/uievents/click/click_event_target_siblings.html
@@ -16,35 +16,36 @@
     </style>
   </head>
   <body id='body'>
-    <h1>Click targeting when targets of down and up are different</h1>
+    <h1>Click targeting when targets of down and up are sibling elements</h1>
+    This test verifies that click event always goes to the first common ancestor of down and up event targets.
 
     <ul>
       <li>Press down the primary button on red div and move to blue box and release.</li>
       <li>Press down the primary button on button b1 and move to button b2 and release.</li>
+      <li>Press down the primary button on input i1 and move to input i2 and release.</li>
       <li>Press down the primary button on link 1 and move to link 2 and release.</li>
       <li>Click done.</li>
     </ul>
 
     <div id="div_container" style="background: green">
-      <div id="red_div" style="background: red">
-      </div>
-      <div id="blue_div" style="background: blue">
-      </div>
+      <div id="red_div" style="background: red"></div>
+      <div id="blue_div" style="background: blue"></div>
     </div>
 
     <div id="button_container" style="background: green">
-      <button id="button1"> b1
-      </button>
-      <button id="button2"> b2
-      </button>
+      <button id="button1">b1</button>
+      <button id="button2">b2</button>
+    </div>
+
+    <div id="input_container" style="background: green">
+      <input id="input1" value="i1">
+      <input id="input2" value="i2">
     </div>
 
     <div id="link_container" style="background: green">
-      <a id="link1" href="#">link1
-      </a>
+      <a id="link1" href="#">link1</a>
       <br/>
-      <a id="link2" href="#">link2
-      </a>
+      <a id="link2" href="#">link2</a>
     </div>
 
     <button id="done">Done</button>
@@ -55,7 +56,7 @@
     document.addEventListener('dragstart', (e) => e.preventDefault());
 
     var events = [];
-    var nodes = ['div_container', 'red_div', 'blue_div', 'button_container', 'button1', 'button2', 'link_container', 'link1', 'link2', 'body'];
+    var nodes = ['div_container', 'red_div', 'blue_div', 'button_container', 'button1', 'button2', 'input_container', 'input1', 'input2', 'link_container', 'link1', 'link2', 'body'];
 
     for (var i = 0; i < nodes.length; i++) {
      ['mousedown', 'mouseup', 'click'].forEach((eventName) => {
diff --git a/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/compositing/lots-of-img-layers-expected.png b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/compositing/lots-of-img-layers-expected.png
new file mode 100644
index 0000000..35b2d50
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/compositing/lots-of-img-layers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/css3/filters/effect-blur-hw-expected.png b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/css3/filters/effect-blur-hw-expected.png
new file mode 100644
index 0000000..a17d776
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/css3/filters/effect-blur-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/media/video-layer-crash-expected.png b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/media/video-layer-crash-expected.png
new file mode 100644
index 0000000..113a9590
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/media/video-layer-crash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/transforms/3d/point-mapping/3d-point-mapping-deep-expected.png b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/transforms/3d/point-mapping/3d-point-mapping-deep-expected.png
new file mode 100644
index 0000000..c4c382b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/transforms/3d/point-mapping/3d-point-mapping-deep-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
new file mode 100644
index 0000000..954d825
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-features=UseSkiaRenderer/virtual/exotic-color-space/images/color-profile-layer-filter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index c594217..8f969c3 100644
--- a/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index e87fea8b..087a773 100644
--- a/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
index fa67736..4d7bdf3 100644
--- a/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
+++ b/third_party/blink/web_tests/platform/win/fast/forms/datalist/input-appearance-range-with-datalist-zoomed-expected.png
Binary files differ
diff --git a/third_party/pyftpdlib/BUILD.gn b/third_party/pyftpdlib/BUILD.gn
deleted file mode 100644
index 7301572..0000000
--- a/third_party/pyftpdlib/BUILD.gn
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2015 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.
-
-# pyftpdlib is a Python program. Depend on this to get the data deps necessary
-# to run it in the test environment.
-group("pyftpdlib") {
-  # For now, depend on the entire directory.
-  data = [
-    "//third_party/pyftpdlib/",
-  ]
-}
diff --git a/third_party/pyftpdlib/README.chromium b/third_party/pyftpdlib/README.chromium
deleted file mode 100644
index 2520861..0000000
--- a/third_party/pyftpdlib/README.chromium
+++ /dev/null
@@ -1,16 +0,0 @@
-Name: Python FTP server library
-Short Name: pyftpdlib
-URL: https://github.com/giampaolo/pyftpdlib
-Version: 0.7.0-updates
-Revision: 2be6d65e31c7ee6320d059f581f05ae8d89d7e45 
-License: MIT
-License File: NOT_SHIPPED
-Security Critical: no
-
-Description:
-Python FTP server library provides an high-level portable interface to easily
-write asynchronous FTP servers with Python.  Based on asyncore framework
-pyftpdlib is currently the most complete RFC-959 FTP server implementation
-available for Python programming language.
-
-Learn more by visiting: http://pythonhosted.org/pyftpdlib/faqs.html
diff --git a/tools/android/asan/third_party/BUILD.gn b/tools/android/asan/third_party/BUILD.gn
index ecb998b..172db265 100644
--- a/tools/android/asan/third_party/BUILD.gn
+++ b/tools/android/asan/third_party/BUILD.gn
@@ -10,32 +10,41 @@
   executable = "with_asan.py"
   wrapper_script = "$root_out_dir/bin/run_with_asan"
 
+  _lib_archs = []
+
   if (target_cpu == "arm") {
-    _lib_arch = "arm"
+    _lib_archs += [ "arm" ]
   } else if (target_cpu == "arm64") {
-    _lib_arch = "aarch64"
+    _lib_archs += [
+      "arm",
+      "aarch64",
+    ]
   } else if (target_cpu == "x86") {
-    _lib_arch = "i686"
+    _lib_archs += [ "i686" ]
   } else {
     assert(false, "No ASAN library available for $target_cpu")
   }
 
   _adb_path = "${android_sdk_root}/platform-tools/adb"
-  _lib_path = "${clang_base_path}/lib/clang/${clang_version}/lib/linux/libclang_rt.asan-${_lib_arch}-android.so"
+  _lib_dir = "${clang_base_path}/lib/clang/${clang_version}/lib/linux"
+  _lib_paths = []
+  foreach(_lib_arch, _lib_archs) {
+    _lib_paths += [ "${_lib_dir}/libclang_rt.asan-${_lib_arch}-android.so" ]
+  }
   data = [
     "asan_device_setup.sh",
     "with_asan.py",
     _adb_path,
-    _lib_path,
   ]
+  data += _lib_paths
 
-  _rebased_lib_path = rebase_path(_lib_path, root_build_dir)
   _rebased_adb_path = rebase_path(_adb_path, root_build_dir)
+  _rebased_lib_dir_path = rebase_path(_lib_dir, root_build_dir)
 
   executable_args = [
     "--adb",
     "@WrappedPath(${_rebased_adb_path})",
     "--lib",
-    "@WrappedPath(${_rebased_lib_path})",
+    "@WrappedPath(${_rebased_lib_dir_path})",
   ]
 }
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 731daa7..9a89927 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -949,14 +949,20 @@
     """
     infobar_histogram_name = 'Previews.InfoBarAction.%s' % preview_type
     android_histogram_name = 'Previews.OmniboxAction.%s' % preview_type
+    testing_histogram_name = 'Previews.PreviewShown.%s' % preview_type
 
     infobar_histogram = test_driver.GetBrowserHistogram(
       infobar_histogram_name, 5)
     android_histogram = test_driver.GetBrowserHistogram(
       android_histogram_name, 5)
+    testing_histogram = test_driver.GetBrowserHistogram(
+      testing_histogram_name, 5)
 
-    count = (infobar_histogram.get('count', 0)
-             + android_histogram.get('count', 0))
+    count = sum([
+      infobar_histogram.get('count', 0),
+      android_histogram.get('count', 0),
+      testing_histogram.get('count', 0),
+    ])
     return count > 0
 
   def assertPreviewShownViaHistogram(self, test_driver, preview_type):
diff --git a/tools/grit/grit/node/misc_unittest.py b/tools/grit/grit/node/misc_unittest.py
index 9ee8ed57..30df9fe 100755
--- a/tools/grit/grit/node/misc_unittest.py
+++ b/tools/grit/grit/node/misc_unittest.py
@@ -25,10 +25,13 @@
 
 
 @contextlib.contextmanager
+# Returns the name of the new temporary file containing |content|, which must be
+# deleted by the caller.
 def _MakeTempPredeterminedIdsFile(content):
-  with tempfile.NamedTemporaryFile() as f:
+  with tempfile.NamedTemporaryFile(delete=False) as f:
     f.write(content)
     f.flush()
+    f.close()
     yield f.name
 
 
@@ -83,11 +86,13 @@
         </release>
       </grit>''' % chrome_html_path
 
-    grd = grd_reader.Parse(StringIO.StringIO(xml), util.PathFromRoot('grit/testdata'))
+    grd = grd_reader.Parse(StringIO.StringIO(xml),
+                           util.PathFromRoot('grit/testdata'))
     expected = ['chrome_html.html', 'default_100_percent/a.png',
                 'default_100_percent/b.png', 'included_sample.html',
                 'special_100_percent/a.png']
-    actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for path in grd.GetInputFiles()]
+    actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for
+              path in grd.GetInputFiles()]
     # Convert path separator for Windows paths.
     actual = [path.replace('\\', '/') for path in actual]
     self.assertEquals(expected, actual)
@@ -112,7 +117,8 @@
 
     grd = grd_reader.Parse(StringIO.StringIO(xml), util.PathFromRoot('grit/testdata'))
     expected = ['chrome_html.html', 'included_sample.html']
-    actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for path in grd.GetInputFiles()]
+    actual = [os.path.relpath(path, util.PathFromRoot('grit/testdata')) for
+              path in grd.GetInputFiles()]
     # Convert path separator for Windows paths.
     actual = [path.replace('\\', '/') for path in actual]
     self.assertEquals(expected, actual)
@@ -177,6 +183,7 @@
       self.assertEqual(('#define IDS_B 102\n'
                         '#define IDS_GREETING 10000\n'
                         '#define IDS_A 101\n'), ''.join(output))
+      os.remove(ids_file)
 
   def testPredeterminedIdsOverlap(self):
     with _MakeTempPredeterminedIdsFile('ID_LOGO 10000') as ids_file:
@@ -193,6 +200,7 @@
               Bongo!
             </message>
           </messages>''', predetermined_ids_file=ids_file)
+      os.remove(ids_file)
 
 
 class IfNodeUnittest(unittest.TestCase):
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6eca4e3..6e8cae7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -46612,6 +46612,9 @@
 </enum>
 
 <enum name="PreviewsInfoBarAction">
+  <obsolete>
+    Removed in M76.
+  </obsolete>
   <int value="0" label="Infobar shown"/>
   <int value="1" label="Infobar 'Load original' clicked"/>
   <int value="2" label="Infobar dismissed by user"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 07a1345..e03954c 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -62428,6 +62428,19 @@
   </summary>
 </histogram>
 
+<histogram name="Navigation.Home.IsChromeInternal" enum="Boolean"
+    expires_after="2020-05-08">
+  <owner>mpearson@chromium.org</owner>
+  <owner>amaralp@chromium.org</owner>
+  <summary>
+    Emitted every time a user uses a Home button to go to their home page.
+    Records whether the page is chrome-internal (most likely the New Tab Page or
+    about:blank) or not (most likely an actual web site). For the purpose of
+    this histogram, about:, chrome: and chrome-native: are considered
+    chrome-internal; everything else is not.
+  </summary>
+</histogram>
+
 <histogram name="Navigation.Intercept.Ignored" enum="Boolean">
   <owner>csharrison@chromium.org</owner>
   <summary>
@@ -98222,6 +98235,9 @@
 </histogram>
 
 <histogram name="Previews.InfoBarAction" enum="PreviewsInfoBarAction">
+  <obsolete>
+    Removed in M76.
+  </obsolete>
   <owner>bengr@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index e3b220d..df4cc3b1 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -1,13 +1,13 @@
 AUTOGENERATED FILE DO NOT EDIT
 See https://bit.ly/update-benchmarks-info to make changes
 Benchmark name,Individual owners,Component,Documentation,Tags
-UNSCHEDULED_blink_perf.display_locking,vmpstr@chromium.org,Blink>Paint,https://bit.ly/blink-perf-benchmarks,
 angle_perftests,"jmadill@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU>ANGLE,,
 base_perftests,"skyostil@chromium.org, gab@chromium.org",Internals>SequenceManager,https://chromium.googlesource.com/chromium/src/+/HEAD/base/README.md#performance-testing,
 blink_perf.accessibility,dmazzoni@chromium.org,Blink>Accessibility,https://bit.ly/blink-perf-benchmarks,
 blink_perf.bindings,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org",Blink>Bindings,https://bit.ly/blink-perf-benchmarks,
 blink_perf.canvas,"aaronhk@chromium.org, fserb@chromium.org",Blink>Canvas,https://bit.ly/blink-perf-benchmarks,
 blink_perf.css,"futhark@chromium.org, andruud@chromium.org",Blink>CSS,https://bit.ly/blink-perf-benchmarks,
+blink_perf.display_locking,vmpstr@chromium.org,Blink>Paint,https://bit.ly/blink-perf-benchmarks,
 blink_perf.dom,hayato@chromium.org,Blink>DOM,https://bit.ly/blink-perf-benchmarks,
 blink_perf.events,hayato@chromium.org,Blink>DOM,https://bit.ly/blink-perf-benchmarks,
 blink_perf.image_decoder,cblume@chromium.org,Internals>Images>Codecs,https://bit.ly/blink-perf-benchmarks,
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 90022e953..e708e83a 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -566,7 +566,7 @@
 
   @classmethod
   def Name(cls):
-    return 'UNSCHEDULED_blink_perf.display_locking'
+    return 'blink_perf.display_locking'
 
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs(['--enable-blink-features=DisplayLocking'])
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 47b51a7a..1634f172 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -91,10 +91,18 @@
     return ('https://ci.chromium.org/p/chrome/builders/luci.chrome.ci/%s' %
              urllib.quote(self._name))
 
-
 _OFFICIAL_BENCHMARK_NAMES = frozenset(
     [b.Name() for b in _OFFICIAL_BENCHMARKS])
+_DL_BENCHMARK_NAMES = frozenset(['blink_perf.display_locking'])
+_OFFICIAL_EXCEPT_DISPLAY_LOCKING = _OFFICIAL_BENCHMARK_NAMES - frozenset([
+    'blink_perf.display_locking'])
 
+_LINUX_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_MAC_HIGH_END_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_MAC_LOW_END_BENCHMARK_NAMES = _OFFICIAL_BENCHMARK_NAMES
+_WIN_10_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_WIN_7_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_WIN_7_GPU_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
 _ANDROID_GO_BENCHMARK_NAMES = frozenset([
     'memory.top_10_mobile',
     'system_health.memory_mobile',
@@ -105,7 +113,13 @@
     'v8.browsing_mobile',
     'speedometer',
     'speedometer2'])
-
+_ANDROID_GO_WEBVIEW_BENCHMARK_NAMES = _ANDROID_GO_BENCHMARK_NAMES
+_ANDROID_NEXUS_5_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_ANDROID_NEXUS_5X_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_ANDROID_NEXUS_5X_WEBVIEW_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_ANDROID_NEXUS_6_WEBVIEW_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_ANDROID_PIXEL2_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
+_ANDROID_PIXEL2_WEBVIEW_BENCHMARK_NAMES = _OFFICIAL_EXCEPT_DISPLAY_LOCKING
 _ANDROID_NEXUS5X_FYI_BENCHMARK_NAMES = frozenset([
     'heap_profiling.mobile.disabled',
     'heap_profiling.mobile.native',
@@ -114,69 +128,59 @@
 # Linux
 LINUX = PerfPlatform(
     'linux-perf', 'Ubuntu-14.04, 8 core, NVIDIA Quadro P400',
-    _OFFICIAL_BENCHMARK_NAMES, num_shards=26)
+    _LINUX_BENCHMARK_NAMES, num_shards=26)
 
 # Mac
 MAC_HIGH_END = PerfPlatform(
     'mac-10_13_laptop_high_end-perf',
     'MacBook Pro, Core i7 2.8 GHz, 16GB RAM, 256GB SSD, Radeon 55',
-    _OFFICIAL_BENCHMARK_NAMES, num_shards=26)
-
+    _MAC_HIGH_END_BENCHMARK_NAMES, num_shards=26)
 MAC_LOW_END = PerfPlatform(
     'mac-10_12_laptop_low_end-perf',
     'MacBook Air, Core i5 1.8 GHz, 8GB RAM, 128GB SSD, HD Graphics',
-    _OFFICIAL_BENCHMARK_NAMES, num_shards=26)
+    _MAC_LOW_END_BENCHMARK_NAMES, num_shards=26)
 
 # Win
 WIN_10 = PerfPlatform(
     'win-10-perf',
     'Windows Intel HD 630 towers, Core i7-7700 3.6 GHz, 16GB RAM,'
-    ' Intel Kaby Lake HD Graphics 630', _OFFICIAL_BENCHMARK_NAMES,
+    ' Intel Kaby Lake HD Graphics 630', _WIN_10_BENCHMARK_NAMES,
     num_shards=26)
-
 WIN_7 = PerfPlatform(
-    'Win 7 Perf', 'N/A', _OFFICIAL_BENCHMARK_NAMES,
+    'Win 7 Perf', 'N/A', _WIN_7_BENCHMARK_NAMES,
     num_shards=5)
-
 WIN_7_GPU = PerfPlatform(
-    'Win 7 Nvidia GPU Perf', 'N/A', _OFFICIAL_BENCHMARK_NAMES,
+    'Win 7 Nvidia GPU Perf', 'N/A', _WIN_7_GPU_BENCHMARK_NAMES,
     num_shards=5)
 
 # Android
 ANDROID_GO = PerfPlatform(
     'android-go-perf', 'Android O (gobo)', _ANDROID_GO_BENCHMARK_NAMES,
     num_shards=19)
-
 ANDROID_GO_WEBVIEW = PerfPlatform(
     'android-go_webview-perf', 'Android OPM1.171019.021 (gobo)',
-    _ANDROID_GO_BENCHMARK_NAMES, num_shards=25)
-
+    _ANDROID_GO_WEBVIEW_BENCHMARK_NAMES, num_shards=25)
 ANDROID_NEXUS_5 = PerfPlatform(
-    'Android Nexus5 Perf', 'Android KOT49H', _OFFICIAL_BENCHMARK_NAMES,
+    'Android Nexus5 Perf', 'Android KOT49H', _ANDROID_NEXUS_5_BENCHMARK_NAMES,
     num_shards=16)
-
 ANDROID_NEXUS_5X = PerfPlatform(
-    'android-nexus5x-perf', 'Android MMB29Q', _OFFICIAL_BENCHMARK_NAMES,
-    num_shards=16)
-
+    'android-nexus5x-perf', 'Android MMB29Q',
+    _ANDROID_NEXUS_5X_BENCHMARK_NAMES, num_shards=16)
 ANDROID_NEXUS_5X_WEBVIEW = PerfPlatform(
     'Android Nexus5X WebView Perf', 'Android AOSP MOB30K',
-    _OFFICIAL_BENCHMARK_NAMES, num_shards=16)
-
+    _ANDROID_NEXUS_5X_WEBVIEW_BENCHMARK_NAMES, num_shards=16)
 ANDROID_NEXUS_6_WEBVIEW = PerfPlatform(
     'Android Nexus6 WebView Perf', 'Android AOSP MOB30K',
-    _OFFICIAL_BENCHMARK_NAMES,
+    _ANDROID_NEXUS_6_WEBVIEW_BENCHMARK_NAMES,
     num_shards=12)  # Reduced from 16 per crbug.com/891848.
 
 # FYI bots
 ANDROID_PIXEL2 = PerfPlatform(
     'android-pixel2-perf', 'Android OPM1.171019.021',
-    _OFFICIAL_BENCHMARK_NAMES, num_shards=7, is_fyi=True)
-
+    _ANDROID_PIXEL2_BENCHMARK_NAMES, num_shards=7, is_fyi=True)
 ANDROID_PIXEL2_WEBVIEW = PerfPlatform(
     'android-pixel2_webview-perf', 'Android OPM1.171019.021',
-    _OFFICIAL_BENCHMARK_NAMES, num_shards=7, is_fyi=True)
-
+    _ANDROID_PIXEL2_WEBVIEW_BENCHMARK_NAMES, num_shards=7, is_fyi=True)
 ANDROID_NEXUS5X_PERF_FYI =  PerfPlatform(
     'android-nexus5x-perf-fyi', 'Android MMB29Q',
     _ANDROID_NEXUS5X_FYI_BENCHMARK_NAMES,
diff --git a/tools/perf/core/shard_maps/android-nexus5x-perf_map.json b/tools/perf/core/shard_maps/android-nexus5x-perf_map.json
index cb55967..3876b8b 100644
--- a/tools/perf/core/shard_maps/android-nexus5x-perf_map.json
+++ b/tools/perf/core/shard_maps/android-nexus5x-perf_map.json
@@ -7,7 +7,8 @@
             "blink_perf.css": {},
             "blink_perf.dom": {
                 "end": 1
-            }
+            },
+            "blink_perf.display_locking": {}
         }
     },
     "1": {
@@ -189,4 +190,4 @@
         "shard #14": 5554.0,
         "shard #15": 5740.0
     }
-}
\ No newline at end of file
+}
diff --git a/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json b/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json
index 60c4ac1..8add746 100644
--- a/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json
+++ b/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json
@@ -4,7 +4,8 @@
             "blink_perf.accessibility": {},
             "blink_perf.bindings": {},
             "blink_perf.canvas": {},
-            "blink_perf.css": {}
+            "blink_perf.css": {},
+            "blink_perf.display_locking": {}
         }
     },
     "1": {
@@ -276,4 +277,4 @@
         "shard #24": 2318.0,
         "shard #25": 2330.0
     }
-}
\ No newline at end of file
+}
diff --git a/ui/aura/event_injector.cc b/ui/aura/event_injector.cc
index 4fdfc171..6598c5f8 100644
--- a/ui/aura/event_injector.cc
+++ b/ui/aura/event_injector.cc
@@ -6,12 +6,6 @@
 
 #include <utility>
 
-#include "base/bind.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/ws/public/mojom/constants.mojom.h"
-#include "ui/aura/env.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/events/event.h"
@@ -19,89 +13,25 @@
 
 namespace aura {
 
-namespace {
+EventInjector::EventInjector() = default;
 
-void RunCallback(base::OnceClosure callback, bool processed) {
-  if (!callback)
-    return;
-
-  std::move(callback).Run();
-}
-
-// Updates the location of |event| to be relative to the display |host| is
-// on. It is assumed at the time this is called the location of the event is
-// relative to |host|.
-void ConvertHostLocationToDisplayLocation(WindowTreeHost* host,
-                                          ui::LocatedEvent* event) {
-  WindowTreeHostMus* host_mus = WindowTreeHostMus::ForWindow(host->window());
-  DCHECK(host_mus);
-  // WindowTreeHostMus's bounds are in screen coordinates, convert to display
-  // relative.
-  gfx::PointF location =
-      gfx::PointF(host_mus->bounds_in_dip().origin() -
-                  host_mus->GetDisplay().bounds().origin().OffsetFromOrigin());
-  // And then add the event location.
-  location += event->root_location_f().OffsetFromOrigin();
-  event->set_root_location_f(location);
-  event->set_location_f(location);
-}
-
-}  // namespace
-
-EventInjector::EventInjector() {}
-
-EventInjector::~EventInjector() {
-  // |event_injector_| should not be waiting for responses. Otherwise, the
-  // pending callback would not happen because the mojo channel is closed.
-  DCHECK(!has_pending_callback_ || !event_injector_.IsExpectingResponse());
-}
+EventInjector::~EventInjector() = default;
 
 ui::EventDispatchDetails EventInjector::Inject(WindowTreeHost* host,
-                                               ui::Event* event,
-                                               base::OnceClosure callback) {
+                                               ui::Event* event) {
   DCHECK(host);
-  Env* env = host->window()->env();
-  DCHECK(env);
   DCHECK(event);
 
-  if (env->mode() == Env::Mode::LOCAL) {
-    if (event->IsLocatedEvent()) {
-      ui::LocatedEvent* located_event = event->AsLocatedEvent();
-      // Transforming the coordinate to the root will apply the screen scale
-      // factor to the event's location and also the screen rotation degree.
-      located_event->UpdateForRootTransform(
-          host->GetRootTransform(),
-          host->GetRootTransformForLocalEventCoordinates());
-    }
-
-    ui::EventDispatchDetails details =
-        host->event_sink()->OnEventFromSource(event);
-    RunCallback(std::move(callback), /*processed=*/true);
-    return details;
-  }
-
-  has_pending_callback_ |= !callback.is_null();
-
   if (event->IsLocatedEvent()) {
-    // The window-service expects events coming in to have a location matching
-    // the root location.
-    event->AsLocatedEvent()->set_root_location_f(
-        event->AsLocatedEvent()->location_f());
-
-    // Convert the location to be display relative. This is *not* needed in the
-    // classic case as the WindowTreeHost and the display are the same.
-    ConvertHostLocationToDisplayLocation(host, event->AsLocatedEvent());
+    ui::LocatedEvent* located_event = event->AsLocatedEvent();
+    // Transforming the coordinate to the root will apply the screen scale
+    // factor to the event's location and also the screen rotation degree.
+    located_event->UpdateForRootTransform(
+        host->GetRootTransform(),
+        host->GetRootTransformForLocalEventCoordinates());
   }
 
-  if (!event_injector_) {
-    env->window_tree_client_->connector()->BindInterface(
-        ws::mojom::kServiceName, &event_injector_);
-  }
-
-  event_injector_->InjectEvent(
-      host->GetDisplayId(), ui::Event::Clone(*event),
-      base::BindOnce(&RunCallback, std::move(callback)));
-  return ui::EventDispatchDetails();
+  return host->event_sink()->OnEventFromSource(event);
 }
 
 }  // namespace aura
diff --git a/ui/aura/event_injector.h b/ui/aura/event_injector.h
index 725bfcf..98f2929 100644
--- a/ui/aura/event_injector.h
+++ b/ui/aura/event_injector.h
@@ -5,8 +5,7 @@
 #ifndef UI_AURA_EVENT_INJECTOR_H_
 #define UI_AURA_EVENT_INJECTOR_H_
 
-#include "base/callback.h"
-#include "services/ws/public/mojom/event_injector.mojom.h"
+#include "base/macros.h"
 #include "ui/aura/aura_export.h"
 
 namespace ui {
@@ -18,28 +17,17 @@
 
 class WindowTreeHost;
 
-// Used to inject events into the system. In LOCAL mode, it directly injects
-// events into the WindowTreeHost, but in MUS mode, it injects events into the
-// window-service (over the mojom API).
+// Used to inject events as if they came from the OS.
 class AURA_EXPORT EventInjector {
  public:
   EventInjector();
   ~EventInjector();
 
-  // Inject |event| to |host|. |callback| is optional that gets invoked after
-  // the event is processed by |host|. In LOCAL mode,  |callback| is invoked
-  // synchronously. In MUS mode, it is invoked after a response is received
-  // from the window service (via mojo). If |event| is a LocatedEvent, then
-  // coordinates are relative to host and in DIPs.
-  ui::EventDispatchDetails Inject(
-      WindowTreeHost* host,
-      ui::Event* event,
-      base::OnceClosure callback = base::OnceClosure());
+  // Inject |event| to |host|. If |event| is a LocatedEvent, then coordinates
+  // are relative to host and in DIPs.
+  ui::EventDispatchDetails Inject(WindowTreeHost* host, ui::Event* event);
 
  private:
-  ws::mojom::EventInjectorPtr event_injector_;
-  bool has_pending_callback_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(EventInjector);
 };
 
diff --git a/ui/aura/test/ui_controls_factory_ozone.cc b/ui/aura/test/ui_controls_factory_ozone.cc
index c729b40a..130aaf07 100644
--- a/ui/aura/test/ui_controls_factory_ozone.cc
+++ b/ui/aura/test/ui_controls_factory_ozone.cc
@@ -6,22 +6,15 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/ws/public/mojom/constants.mojom.h"
-#include "services/ws/public/mojom/event_injector.mojom.h"
 #include "ui/aura/env.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/test/aura_test_utils.h"
 #include "ui/aura/test/env_test_helper.h"
-#include "ui/aura/test/mus/window_tree_client_test_api.h"
 #include "ui/aura/test/ui_controls_factory_aura.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/test/ui_controls_aura.h"
 #include "ui/display/display.h"
-#include "ui/display/display_observer.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/test/events_test_utils.h"
@@ -31,16 +24,11 @@
 namespace test {
 namespace {
 
-class UIControlsOzone : public ui_controls::UIControlsAura,
-                        display::DisplayObserver {
+class UIControlsOzone : public ui_controls::UIControlsAura {
  public:
   UIControlsOzone(WindowTreeHost* host) : host_(host) {
-    MaybeInitializeEventInjector();
-    display::Screen::GetScreen()->AddObserver(this);
   }
-  ~UIControlsOzone() override {
-    display::Screen::GetScreen()->RemoveObserver(this);
-  }
+  ~UIControlsOzone() override = default;
 
  private:
   // ui_controls::UIControlsAura:
@@ -134,9 +122,6 @@
     int64_t display_id = display::kInvalidDisplayId;
     if (!ScreenDIPToHostPixels(&host_location, &display_id))
       return false;
-    last_mouse_location_ = host_location;
-    last_mouse_display_id_ = display_id;
-
     ui::EventType event_type;
 
     if (button_down_mask_)
@@ -159,17 +144,10 @@
                                      int button_state,
                                      base::OnceClosure closure,
                                      int accelerator_state) override {
-    gfx::PointF host_location;
+    gfx::PointF host_location(host_->window()->env()->last_mouse_location());
     int64_t display_id = display::kInvalidDisplayId;
-    if (last_mouse_location_.has_value()) {
-      host_location = last_mouse_location_.value();
-      display_id = last_mouse_display_id_;
-    } else {
-      host_location =
-          gfx::PointF(host_->window()->env()->last_mouse_location());
-      if (!ScreenDIPToHostPixels(&host_location, &display_id))
-        return false;
-    }
+    if (!ScreenDIPToHostPixels(&host_location, &display_id))
+      return false;
 
     int changed_button_flag = 0;
 
@@ -253,40 +231,9 @@
   }
 #endif
 
-  // display::DisplayObserver:
-  void OnDisplayRemoved(const display::Display& old_display) override {
-    if (last_mouse_display_id_ == old_display.id()) {
-      last_mouse_display_id_ = display::kInvalidDisplayId;
-      last_mouse_location_.reset();
-    }
-  }
-
   void SendEventToSink(ui::Event* event,
                        int64_t display_id,
                        base::OnceClosure closure) {
-    if (event_injector_) {
-      auto event_to_inject = ui::Event::Clone(*event);
-
-      if (event_to_inject->IsLocatedEvent()) {
-        // EventInjector expects coordinates relative to host and in DIPs.
-        display::Display display;
-        CHECK(display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id,
-                                                                    &display));
-
-        ui::LocatedEvent* located_event = event_to_inject->AsLocatedEvent();
-        gfx::PointF location_in_host_dip = gfx::ScalePoint(
-            located_event->location_f(), 1 / display.device_scale_factor(),
-            1 / display.device_scale_factor());
-        located_event->set_location_f(location_in_host_dip);
-        located_event->set_root_location_f(location_in_host_dip);
-      }
-
-      event_injector_->InjectEvent(
-          display_id, std::move(event_to_inject),
-          base::BindOnce(&OnWindowServiceProcessedEvent, std::move(closure)));
-      return;
-    }
-
     // Post the task before processing the event. This is necessary in case
     // processing the event results in a nested message loop.
     if (closure) {
@@ -373,18 +320,6 @@
     SendEventToSink(&touch_event, display_id, std::move(closure));
   }
 
-  // Initializes EventInjector when Mus. Otherwise do nothing.
-  void MaybeInitializeEventInjector() {
-    if (host_->window()->env()->mode() != Env::Mode::MUS)
-      return;
-
-    DCHECK(aura::test::EnvTestHelper().GetWindowTreeClient());
-    aura::test::EnvTestHelper()
-        .GetWindowTreeClient()
-        ->connector()
-        ->BindInterface(ws::mojom::kServiceName, &event_injector_);
-  }
-
   bool ScreenDIPToHostPixels(gfx::PointF* location, int64_t* display_id) {
     // The location needs to be in display's coordinate.
     display::Display display =
@@ -401,17 +336,6 @@
   }
 
   WindowTreeHost* host_;
-  ws::mojom::EventInjectorPtr event_injector_;
-
-  // The mouse location for the last SendMouseEventsNotifyWhenDone call. This is
-  // used rather than Env::last_mouse_location() as Env::last_mouse_location()
-  // is updated asynchronously with mus.
-  base::Optional<gfx::PointF> last_mouse_location_;
-
-  // The display ID where the last SendMouseEventsNotifyWhenDone occurred. This
-  // is used along with |last_mouse_location_| to send the mouse event to the
-  // event injector. Not used when Mus is not enabled.
-  int64_t last_mouse_display_id_ = display::kInvalidDisplayId;
 
   // Mask of the mouse buttons currently down. This is static as it needs to
   // track the state globally for all displays. A UIControlsOzone instance is
@@ -430,20 +354,5 @@
   return new UIControlsOzone(host);
 }
 
-void OnWindowServiceProcessedEvent(base::OnceClosure closure, bool result) {
-  DCHECK(result);
-  if (closure) {
-    // There can be several mojo calls are queued in the window tree client,
-    // which may change the order of the operations unexpectedly. Do not call
-    // WaitForAllChangesToComplete() here, since some in-flight changes might
-    // not be resolved by just waiting (like window-dragging will not finish
-    // until it's cancelled or the mouse or touch is released).
-    // See also: https://crbug.com/916177
-    WindowTreeClientTestApi(EnvTestHelper().GetWindowTreeClient())
-        .FlushForTesting();
-    std::move(closure).Run();
-  }
-}
-
 }  // namespace test
 }  // namespace aura
diff --git a/ui/chromeos/search_box/search_box_view_base.cc b/ui/chromeos/search_box/search_box_view_base.cc
index 27e90e43..90d059a 100644
--- a/ui/chromeos/search_box/search_box_view_base.cc
+++ b/ui/chromeos/search_box/search_box_view_base.cc
@@ -100,8 +100,8 @@
     SetInkDropMode(InkDropMode::ON);
 
     SetPreferredSize({kButtonSizeDip, kButtonSizeDip});
-    SetImageAlignment(HorizontalAlignment::ALIGN_CENTER,
-                      VerticalAlignment::ALIGN_MIDDLE);
+    SetImageHorizontalAlignment(ALIGN_CENTER);
+    SetImageVerticalAlignment(ALIGN_MIDDLE);
   }
   ~SearchBoxImageButton() override {}
 
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index 7f2b094..3ec895cb 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -382,8 +382,8 @@
   layout->SetFlexForView(textfield_, 1);
 
   button_->SetBorder(views::CreateEmptyBorder(kInputReplyButtonPadding));
-  button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                             views::ImageButton::ALIGN_MIDDLE);
+  button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   OnAfterUserAction(textfield_);
   AddChildView(button_);
 }
diff --git a/ui/native_theme/native_theme_dark_aura.cc b/ui/native_theme/native_theme_dark_aura.cc
index ba8aeac..e97ba31f 100644
--- a/ui/native_theme/native_theme_dark_aura.cc
+++ b/ui/native_theme/native_theme_dark_aura.cc
@@ -64,7 +64,7 @@
 
     // FocusableBorder
     case kColorId_FocusedBorderColor:
-      return gfx::kGoogleBlue300;
+      return SkColorSetA(gfx::kGoogleBlue300, 0x66);
 
     // Alert icons
     case kColorId_AlertSeverityLow:
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index 80bd0e2..38be79d4 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -12,6 +12,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/scoped_canvas.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
 #include "ui/views/painter.h"
 #include "ui/views/widget/widget.h"
 
@@ -28,11 +29,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ImageButton, public:
 
-ImageButton::ImageButton(ButtonListener* listener)
-    : Button(listener),
-      h_alignment_(ALIGN_LEFT),
-      v_alignment_(ALIGN_TOP),
-      draw_image_mirrored_(false) {
+ImageButton::ImageButton(ButtonListener* listener) : Button(listener) {
   // By default, we request that the gfx::Canvas passed to our View::OnPaint()
   // implementation is flipped horizontally so that the button's images are
   // mirrored when the UI directionality is right-to-left.
@@ -74,11 +71,27 @@
      *image, *mask);
 }
 
-void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
-                                    VerticalAlignment v_align) {
-  h_alignment_ = h_align;
-  v_alignment_ = v_align;
-  SchedulePaint();
+ImageButton::HorizontalAlignment ImageButton::GetImageHorizontalAlignment()
+    const {
+  return h_alignment_;
+}
+
+ImageButton::VerticalAlignment ImageButton::GetImageVerticalAlignment() const {
+  return v_alignment_;
+}
+
+void ImageButton::SetImageHorizontalAlignment(HorizontalAlignment h_alignment) {
+  if (GetImageHorizontalAlignment() == h_alignment)
+    return;
+  h_alignment_ = h_alignment;
+  OnPropertyChanged(&h_alignment_, kPropertyEffectsPaint);
+}
+
+void ImageButton::SetImageVerticalAlignment(VerticalAlignment v_alignment) {
+  if (GetImageVerticalAlignment() == v_alignment)
+    return;
+  v_alignment_ = v_alignment;
+  OnPropertyChanged(&v_alignment_, kPropertyEffectsPaint);
 }
 
 void ImageButton::SetBackgroundImageAlignment(HorizontalAlignment h_align,
@@ -88,12 +101,15 @@
   SchedulePaint();
 }
 
-void ImageButton::SetMinimumImageSize(const gfx::Size& size) {
-  if (minimum_image_size_ == size)
-    return;
+gfx::Size ImageButton::GetMinimumImageSize() const {
+  return minimum_image_size_;
+}
 
+void ImageButton::SetMinimumImageSize(const gfx::Size& size) {
+  if (GetMinimumImageSize() == size)
+    return;
   minimum_image_size_ = size;
-  PreferredSizeChanged();
+  OnPropertyChanged(&minimum_image_size_, kPropertyEffectsPreferredSizeChanged);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -110,7 +126,7 @@
                      images_[STATE_NORMAL].height());
   }
 
-  size.SetToMax(minimum_image_size_);
+  size.SetToMax(GetMinimumImageSize());
 
   gfx::Insets insets = GetInsets();
   size.Enlarge(insets.width(), insets.height());
@@ -147,17 +163,17 @@
       // If the background image alignment was not set, use the image
       // alignment.
       HorizontalAlignment h_alignment =
-          h_background_alignment_.value_or(h_alignment_);
+          h_background_alignment_.value_or(GetImageHorizontalAlignment());
       VerticalAlignment v_alignment =
-          v_background_alignment_.value_or(v_alignment_);
+          v_background_alignment_.value_or(GetImageVerticalAlignment());
       gfx::Point background_position = ComputeImagePaintPosition(
           background_image_, h_alignment, v_alignment);
       canvas->DrawImageInt(background_image_, background_position.x(),
                            background_position.y());
     }
 
-    gfx::Point position =
-        ComputeImagePaintPosition(img, h_alignment_, v_alignment_);
+    gfx::Point position = ComputeImagePaintPosition(
+        img, GetImageHorizontalAlignment(), GetImageVerticalAlignment());
     canvas->DrawImageInt(img, position.x(), position.y());
   }
 }
@@ -201,7 +217,7 @@
   else if (h_alignment == ALIGN_RIGHT)
     x = rect.width() - image.width();
 
-  if (v_alignment_ == ALIGN_MIDDLE)
+  if (v_alignment == ALIGN_MIDDLE)
     y = (rect.height() - image.height()) / 2;
   else if (v_alignment == ALIGN_BOTTOM)
     y = rect.height() - image.height();
@@ -301,4 +317,28 @@
   return toggled_;
 }
 
+DEFINE_ENUM_CONVERTERS(ImageButton::HorizontalAlignment,
+                       {ImageButton::HorizontalAlignment::ALIGN_LEFT,
+                        base::ASCIIToUTF16("ALIGN_LEFT")},
+                       {ImageButton::HorizontalAlignment::ALIGN_CENTER,
+                        base::ASCIIToUTF16("ALIGN_CENTER")},
+                       {ImageButton::HorizontalAlignment::ALIGN_RIGHT,
+                        base::ASCIIToUTF16("ALIGN_RIGHT")})
+DEFINE_ENUM_CONVERTERS(ImageButton::VerticalAlignment,
+                       {ImageButton::VerticalAlignment::ALIGN_TOP,
+                        base::ASCIIToUTF16("ALIGN_TOP")},
+                       {ImageButton::VerticalAlignment::ALIGN_MIDDLE,
+                        base::ASCIIToUTF16("ALIGN_MIDDLE")},
+                       {ImageButton::VerticalAlignment::ALIGN_BOTTOM,
+                        base::ASCIIToUTF16("ALIGN_BOTTOM")})
+
+BEGIN_METADATA(ImageButton)
+METADATA_PARENT_CLASS(Button)
+ADD_PROPERTY_METADATA(ImageButton,
+                      HorizontalAlignment,
+                      ImageHorizontalAlignment)
+ADD_PROPERTY_METADATA(ImageButton, VerticalAlignment, ImageVerticalAlignment)
+ADD_PROPERTY_METADATA(ImageButton, gfx::Size, MinimumImageSize)
+END_METADATA()
+
 }  // namespace views
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h
index be4b081..833234d5 100644
--- a/ui/views/controls/button/image_button.h
+++ b/ui/views/controls/button/image_button.h
@@ -21,6 +21,8 @@
 // SetFocusForPlatform() to make it part of the focus chain.
 class VIEWS_EXPORT ImageButton : public Button {
  public:
+  METADATA_HEADER(ImageButton);
+
   static const char kViewClassName[];
 
   // An enum describing the horizontal alignment of images on Buttons.
@@ -56,9 +58,11 @@
                           const gfx::ImageSkia* image,
                           const gfx::ImageSkia* mask);
 
-  // Sets how the image is laid out within the button's bounds.
-  void SetImageAlignment(HorizontalAlignment h_align,
-                         VerticalAlignment v_align);
+  // How the image is laid out within the button's bounds.
+  HorizontalAlignment GetImageHorizontalAlignment() const;
+  VerticalAlignment GetImageVerticalAlignment() const;
+  void SetImageHorizontalAlignment(HorizontalAlignment h_alignment);
+  void SetImageVerticalAlignment(VerticalAlignment v_alignment);
 
   // Sets how the background is laid out within the button's bounds.
   void SetBackgroundImageAlignment(HorizontalAlignment h_align,
@@ -67,7 +71,7 @@
   // The minimum size of the contents (not including the border). The contents
   // will be at least this size, but may be larger if the image itself is
   // larger.
-  const gfx::Size& minimum_image_size() const { return minimum_image_size_; }
+  gfx::Size GetMinimumImageSize() const;
   void SetMinimumImageSize(const gfx::Size& size);
 
   // Whether we should draw our images resources horizontally flipped.
@@ -111,8 +115,8 @@
                                              VerticalAlignment v_alignment);
 
   // Image alignment.
-  HorizontalAlignment h_alignment_;
-  VerticalAlignment v_alignment_;
+  HorizontalAlignment h_alignment_ = ALIGN_LEFT;
+  VerticalAlignment v_alignment_ = ALIGN_TOP;
   gfx::Size minimum_image_size_;
 
   // Background alignment. If these are not set, the background image uses the
@@ -124,7 +128,7 @@
   // linux titlebar, where image resources were designed to be flipped so a
   // small curved corner in the close button designed to fit into the frame
   // resources.
-  bool draw_image_mirrored_;
+  bool draw_image_mirrored_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ImageButton);
 };
diff --git a/ui/views/controls/button/image_button_factory.cc b/ui/views/controls/button/image_button_factory.cc
index 245b32f..c43b3f71 100644
--- a/ui/views/controls/button/image_button_factory.cc
+++ b/ui/views/controls/button/image_button_factory.cc
@@ -20,8 +20,8 @@
 void ConfigureVectorImageButton(ImageButton* button) {
   button->SetInkDropMode(Button::InkDropMode::ON);
   button->set_has_ink_drop_action_on_click(true);
-  button->SetImageAlignment(ImageButton::ALIGN_CENTER,
-                            ImageButton::ALIGN_MIDDLE);
+  button->SetImageHorizontalAlignment(ImageButton::ALIGN_CENTER);
+  button->SetImageVerticalAlignment(ImageButton::ALIGN_MIDDLE);
   button->SetBorder(CreateEmptyBorder(
       LayoutProvider::Get()->GetInsetsMetric(INSETS_VECTOR_IMAGE_BUTTON)));
 }
diff --git a/ui/views/controls/button/image_button_unittest.cc b/ui/views/controls/button/image_button_unittest.cc
index 129955b..ad2be97 100644
--- a/ui/views/controls/button/image_button_unittest.cc
+++ b/ui/views/controls/button/image_button_unittest.cc
@@ -55,12 +55,12 @@
   EXPECT_TRUE(button.GetImageToPaint().isNull());
 
   // Without an image, buttons are 16x14 by default.
-  EXPECT_EQ("16x14", button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(16, 14), button.GetPreferredSize());
 
   // The minimum image size should be applied even when there is no image.
   button.SetMinimumImageSize(gfx::Size(5, 15));
-  EXPECT_EQ("5x15", button.minimum_image_size().ToString());
-  EXPECT_EQ("16x15", button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(5, 15), button.GetMinimumImageSize());
+  EXPECT_EQ(gfx::Size(16, 15), button.GetPreferredSize());
 
   // Set a normal image.
   gfx::ImageSkia normal_image = CreateTestImage(10, 20);
@@ -72,7 +72,7 @@
   EXPECT_EQ(20, button.GetImageToPaint().height());
 
   // Preferred size is the normal button size.
-  EXPECT_EQ("10x20", button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(10, 20), button.GetPreferredSize());
 
   // Set a pushed image.
   gfx::ImageSkia pushed_image = CreateTestImage(11, 21);
@@ -80,7 +80,7 @@
 
   // By convention, preferred size doesn't change, even though pushed image
   // is bigger.
-  EXPECT_EQ("10x20", button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(10, 20), button.GetPreferredSize());
 
   // We're still painting the normal image.
   EXPECT_FALSE(button.GetImageToPaint().isNull());
@@ -89,11 +89,11 @@
 
   // The minimum image size should make the preferred size bigger.
   button.SetMinimumImageSize(gfx::Size(15, 5));
-  EXPECT_EQ("15x5", button.minimum_image_size().ToString());
-  EXPECT_EQ("15x20", button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(15, 5), button.GetMinimumImageSize());
+  EXPECT_EQ(gfx::Size(15, 20), button.GetPreferredSize());
   button.SetMinimumImageSize(gfx::Size(15, 25));
-  EXPECT_EQ("15x25", button.minimum_image_size().ToString());
-  EXPECT_EQ("15x25", button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(15, 25), button.GetMinimumImageSize());
+  EXPECT_EQ(gfx::Size(15, 25), button.GetPreferredSize());
 }
 
 TEST_F(ImageButtonTest, SetAndGetImage) {
@@ -128,47 +128,37 @@
   button.SetImage(Button::STATE_NORMAL, &image);
 
   // The image should be painted at the top-left corner.
-  EXPECT_EQ(gfx::Point().ToString(),
-            button
-                .ComputeImagePaintPosition(image, kDefaultHorizontalAlignment,
-                                           kDefaultVerticalAlignment)
-                .ToString());
+  EXPECT_EQ(gfx::Point(),
+            button.ComputeImagePaintPosition(image, kDefaultHorizontalAlignment,
+                                             kDefaultVerticalAlignment));
 
   button.SetBorder(views::CreateEmptyBorder(10, 5, 0, 0));
-  EXPECT_EQ(gfx::Point(5, 10).ToString(),
-            button
-                .ComputeImagePaintPosition(image, kDefaultHorizontalAlignment,
-                                           kDefaultVerticalAlignment)
-                .ToString());
+  EXPECT_EQ(gfx::Point(5, 10),
+            button.ComputeImagePaintPosition(image, kDefaultHorizontalAlignment,
+                                             kDefaultVerticalAlignment));
 
   button.SetBorder(NullBorder());
   button.SetBounds(0, 0, 50, 50);
-  EXPECT_EQ(gfx::Point().ToString(),
-            button
-                .ComputeImagePaintPosition(image, kDefaultHorizontalAlignment,
-                                           kDefaultVerticalAlignment)
-                .ToString());
+  EXPECT_EQ(gfx::Point(),
+            button.ComputeImagePaintPosition(image, kDefaultHorizontalAlignment,
+                                             kDefaultVerticalAlignment));
 
-  button.SetImageAlignment(ImageButton::ALIGN_CENTER,
-                           ImageButton::ALIGN_MIDDLE);
-  EXPECT_EQ(gfx::Point(15, 10).ToString(),
-            button
-                .ComputeImagePaintPosition(image, ImageButton::ALIGN_CENTER,
-                                           ImageButton::ALIGN_MIDDLE)
-                .ToString());
+  button.SetImageHorizontalAlignment(ImageButton::ALIGN_CENTER);
+  button.SetImageVerticalAlignment(ImageButton::ALIGN_MIDDLE);
+  EXPECT_EQ(gfx::Point(15, 10),
+            button.ComputeImagePaintPosition(image, ImageButton::ALIGN_CENTER,
+                                             ImageButton::ALIGN_MIDDLE));
   button.SetBorder(views::CreateEmptyBorder(10, 10, 0, 0));
-  EXPECT_EQ(gfx::Point(20, 15).ToString(),
-            button
-                .ComputeImagePaintPosition(image, ImageButton::ALIGN_CENTER,
-                                           ImageButton::ALIGN_MIDDLE)
-                .ToString());
+  EXPECT_EQ(gfx::Point(20, 15),
+            button.ComputeImagePaintPosition(image, ImageButton::ALIGN_CENTER,
+                                             ImageButton::ALIGN_MIDDLE));
 
   // The entire button's size should take the border into account.
-  EXPECT_EQ(gfx::Size(30, 40).ToString(), button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(30, 40), button.GetPreferredSize());
 
   // The border should be added on top of the minimum image size.
   button.SetMinimumImageSize(gfx::Size(30, 5));
-  EXPECT_EQ(gfx::Size(40, 40).ToString(), button.GetPreferredSize().ToString());
+  EXPECT_EQ(gfx::Size(40, 40), button.GetPreferredSize());
 }
 
 TEST_F(ImageButtonTest, LeftAlignedMirrored) {
@@ -176,17 +166,14 @@
   gfx::ImageSkia image = CreateTestImage(20, 30);
   button.SetImage(Button::STATE_NORMAL, &image);
   button.SetBounds(0, 0, 50, 30);
-  button.SetImageAlignment(ImageButton::ALIGN_LEFT,
-                           ImageButton::ALIGN_BOTTOM);
+  button.SetImageVerticalAlignment(ImageButton::ALIGN_BOTTOM);
   button.SetDrawImageMirrored(true);
 
   // Because the coordinates are flipped, we should expect this to draw as if
   // it were ALIGN_RIGHT.
-  EXPECT_EQ(gfx::Point(30, 0).ToString(),
-            button
-                .ComputeImagePaintPosition(image, ImageButton::ALIGN_LEFT,
-                                           ImageButton::ALIGN_BOTTOM)
-                .ToString());
+  EXPECT_EQ(gfx::Point(30, 0),
+            button.ComputeImagePaintPosition(image, ImageButton::ALIGN_LEFT,
+                                             ImageButton::ALIGN_BOTTOM));
 }
 
 TEST_F(ImageButtonTest, RightAlignedMirrored) {
@@ -194,17 +181,15 @@
   gfx::ImageSkia image = CreateTestImage(20, 30);
   button.SetImage(Button::STATE_NORMAL, &image);
   button.SetBounds(0, 0, 50, 30);
-  button.SetImageAlignment(ImageButton::ALIGN_RIGHT,
-                           ImageButton::ALIGN_BOTTOM);
+  button.SetImageHorizontalAlignment(ImageButton::ALIGN_RIGHT);
+  button.SetImageVerticalAlignment(ImageButton::ALIGN_BOTTOM);
   button.SetDrawImageMirrored(true);
 
   // Because the coordinates are flipped, we should expect this to draw as if
   // it were ALIGN_LEFT.
-  EXPECT_EQ(gfx::Point(0, 0).ToString(),
-            button
-                .ComputeImagePaintPosition(image, ImageButton::ALIGN_RIGHT,
-                                           ImageButton::ALIGN_BOTTOM)
-                .ToString());
+  EXPECT_EQ(gfx::Point(0, 0),
+            button.ComputeImagePaintPosition(image, ImageButton::ALIGN_RIGHT,
+                                             ImageButton::ALIGN_BOTTOM));
 }
 
 TEST_F(ImageButtonTest, PreferredSizeInvalidation) {
diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc
index 74e7e83..94322109 100644
--- a/ui/views/layout/box_layout.cc
+++ b/ui/views/layout/box_layout.cc
@@ -95,12 +95,7 @@
     : orientation_(orientation),
       inside_border_insets_(inside_border_insets),
       between_child_spacing_(between_child_spacing),
-      main_axis_alignment_(MainAxisAlignment::kStart),
-      cross_axis_alignment_(CrossAxisAlignment::kStretch),
-      default_flex_(0),
-      minimum_cross_axis_size_(0),
-      collapse_margins_spacing_(collapse_margins_spacing),
-      host_(nullptr) {}
+      collapse_margins_spacing_(collapse_margins_spacing) {}
 
 BoxLayout::~BoxLayout() = default;
 
diff --git a/ui/views/layout/box_layout.h b/ui/views/layout/box_layout.h
index b6b1f0c..f91486c 100644
--- a/ui/views/layout/box_layout.h
+++ b/ui/views/layout/box_layout.h
@@ -314,26 +314,26 @@
 
   // The alignment of children in the main axis. This is
   // MainAxisAlignment::kStart by default.
-  MainAxisAlignment main_axis_alignment_;
+  MainAxisAlignment main_axis_alignment_ = MainAxisAlignment::kStart;
 
   // The alignment of children in the cross axis. This is
   // kStretch by default.
-  CrossAxisAlignment cross_axis_alignment_;
+  CrossAxisAlignment cross_axis_alignment_ = CrossAxisAlignment::kStretch;
 
   // A map of views to their flex weights.
   FlexMap flex_map_;
 
   // The flex weight for views if none is set. Defaults to 0.
-  int default_flex_;
+  int default_flex_ = 0;
 
   // The minimum cross axis size for the layout.
-  int minimum_cross_axis_size_;
+  int minimum_cross_axis_size_ = 0;
 
   // Adjacent view margins and spacing should be collapsed.
   const bool collapse_margins_spacing_;
 
   // The view that this BoxLayout is managing the layout for.
-  views::View* host_;
+  views::View* host_ = nullptr;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(BoxLayout);
 };
diff --git a/ui/views/test/widget_test_aura.cc b/ui/views/test/widget_test_aura.cc
index ea2ad38..970fe6a 100644
--- a/ui/views/test/widget_test_aura.cc
+++ b/ui/views/test/widget_test_aura.cc
@@ -6,7 +6,6 @@
 
 #include "build/build_config.h"
 #include "ui/aura/client/focus_client.h"
-#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/test/aura_test_helper.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
diff --git a/ui/views/touchui/touch_selection_controller_impl.cc b/ui/views/touchui/touch_selection_controller_impl.cc
index 640ee55..47418d7 100644
--- a/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/ui/views/touchui/touch_selection_controller_impl.cc
@@ -11,7 +11,6 @@
 #include "base/time/time.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/env.h"
-#include "ui/aura/mus/window_port_mus.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_targeter.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ui/views/view.h b/ui/views/view.h
index f0757315..7820b64 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -556,10 +556,6 @@
   PropertyChangedSubscription AddVisibleChangedCallback(
       PropertyChangedCallback callback) WARN_UNUSED_RESULT;
 
-  // NOTE: Deprecated. Please use GetVisible() which is the getter for the
-  // |Visible| property.
-  bool visible() const { return visible_; }
-
   // Returns true if this view is drawn on screen.
   virtual bool IsDrawn() const;
 
@@ -578,10 +574,6 @@
   PropertyChangedSubscription AddEnabledChangedCallback(
       PropertyChangedCallback callback) WARN_UNUSED_RESULT;
 
-  // NOTE: Deprecated. Please use GetEnabled() which is the getter for the
-  // |Enabled| property.
-  bool enabled() const { return enabled_; }
-
   // Returns the child views ordered in reverse z-order. That is, views later in
   // the returned vector have a higher z-order (are painted later) than those
   // early in the vector. The returned vector has exactly the same number of
diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc
index 4ce7f19..af23de86 100644
--- a/ui/views/window/custom_frame_view.cc
+++ b/ui/views/window/custom_frame_view.cc
@@ -74,8 +74,7 @@
 
 void LayoutButton(ImageButton* button, const gfx::Rect& bounds) {
   button->SetVisible(true);
-  button->SetImageAlignment(ImageButton::ALIGN_LEFT,
-                            ImageButton::ALIGN_BOTTOM);
+  button->SetImageVerticalAlignment(ImageButton::ALIGN_BOTTOM);
   button->SetBoundsRect(bounds);
 }
 
diff --git a/ui/views_content_client/views_content_client_main_parts_chromeos.cc b/ui/views_content_client/views_content_client_main_parts_chromeos.cc
index a196550..391c211 100644
--- a/ui/views_content_client/views_content_client_main_parts_chromeos.cc
+++ b/ui/views_content_client/views_content_client_main_parts_chromeos.cc
@@ -4,7 +4,6 @@
 
 #include "base/macros.h"
 #include "content/public/browser/context_factory.h"
-#include "content/public/common/service_manager_connection.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "ui/aura/env.h"
 #include "ui/aura/test/test_screen.h"
@@ -51,14 +50,7 @@
   test_screen_.reset(aura::TestScreen::Create(host_size));
   display::Screen::SetScreenInstance(test_screen_.get());
   // Set up basic pieces of views::corewm.
-  ui::ContextFactory* ui_context_factory =
-      aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL
-          ? content::GetContextFactory()
-          : nullptr;
-  wm_test_helper_ = std::make_unique<wm::WMTestHelper>(
-      host_size,
-      content::ServiceManagerConnection::GetForProcess()->GetConnector(),
-      ui_context_factory);
+  wm_test_helper_ = std::make_unique<wm::WMTestHelper>(host_size);
   // Ensure the X window gets mapped.
   wm_test_helper_->host()->Show();
 
diff --git a/ui/webui/resources/images/open_in_new.svg b/ui/webui/resources/images/open_in_new.svg
index 92cbfc8..73d36f6a 100644
--- a/ui/webui/resources/images/open_in_new.svg
+++ b/ui/webui/resources/images/open_in_new.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#9AA0A6"><path d="M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5F6368"><path d="M19 19H5V5h7V3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
diff --git a/ui/wm/core/ime_util_chromeos.cc b/ui/wm/core/ime_util_chromeos.cc
index 3df58d11..03e98076 100644
--- a/ui/wm/core/ime_util_chromeos.cc
+++ b/ui/wm/core/ime_util_chromeos.cc
@@ -5,7 +5,6 @@
 #include "ui/wm/core/ime_util_chromeos.h"
 
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/mus/window_mus.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -80,16 +79,6 @@
 
 void EnsureWindowNotInRect(aura::Window* window,
                            const gfx::Rect& rect_in_screen) {
-  // If |window| is embedded, the move should happen at the embedding side.
-  if (auto* window_mus = aura::WindowMus::Get(window->GetRootWindow())) {
-    if (window_mus->window_mus_type() == aura::WindowMusType::EMBED) {
-      window->GetRootWindow()->SetProperty(
-          aura::client::kEmbeddedWindowEnsureNotInRect,
-          new gfx::Rect(rect_in_screen));
-      return;
-    }
-  }
-
   gfx::Rect original_window_bounds = window->GetBoundsInScreen();
   if (window->GetProperty(wm::kVirtualKeyboardRestoreBoundsKey)) {
     original_window_bounds =
diff --git a/ui/wm/core/ime_util_chromeos_unittest.cc b/ui/wm/core/ime_util_chromeos_unittest.cc
index 7fa6fde..5a5c7f9 100644
--- a/ui/wm/core/ime_util_chromeos_unittest.cc
+++ b/ui/wm/core/ime_util_chromeos_unittest.cc
@@ -7,10 +7,7 @@
 #include "base/command_line.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/mus/embed_root.h"
-#include "ui/aura/mus/embed_root_delegate.h"
 #include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/mus/window_tree_client_test_api.h"
 #include "ui/aura/test/test_screen.h"
 #include "ui/aura/test/test_windows.h"
 #include "ui/base/ui_base_switches.h"
@@ -171,57 +168,4 @@
   EXPECT_EQ(original_bounds, top_level->bounds());
 }
 
-class TestEmbedRootDelegate : public aura::EmbedRootDelegate {
- public:
-  TestEmbedRootDelegate() = default;
-  ~TestEmbedRootDelegate() override = default;
-
-  // EmbedRootDelegate:
-  void OnEmbedTokenAvailable(const base::UnguessableToken& token) override {}
-  void OnEmbed(aura::Window* window) override {}
-  void OnUnembed() override {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestEmbedRootDelegate);
-};
-
-class ImeUtilChromeosEmbeddedTest : public ImeUtilChromeosTest {
- public:
-  ImeUtilChromeosEmbeddedTest() = default;
-  ~ImeUtilChromeosEmbeddedTest() override = default;
-
-  // ImeUtilChromeosTest:
-  void SetUp() override {
-    EnableMusWithTestWindowTree();
-    ImeUtilChromeosTest::SetUp();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ImeUtilChromeosEmbeddedTest);
-};
-
-// Tests that EnsureWindowNotInRect on an embedded window sets the
-// kEmbeddedWindowEnsureNotInRect property on the embedded root window and
-// RestoreWindowBoundsOnClientFocusLost resets the property.
-TEST_F(ImeUtilChromeosEmbeddedTest, EnsureWindowNotInRect) {
-  // Simulates embedding and create an embedded root.
-  TestEmbedRootDelegate embed_root_delegate;
-  std::unique_ptr<aura::EmbedRoot> embed_root =
-      window_tree_client_impl()->CreateEmbedRoot(&embed_root_delegate);
-  aura::WindowTreeClientTestApi(window_tree_client_impl())
-      .CallOnEmbedFromToken(embed_root.get());
-  ASSERT_TRUE(embed_root->window());
-
-  // EnsureWindowNotInRect on embedded window sets the property.
-  gfx::Rect occluded_rect(50, 50, 200, 200);
-  EnsureWindowNotInRect(embed_root->window(), occluded_rect);
-  EXPECT_EQ(occluded_rect, *embed_root->window()->GetProperty(
-                               aura::client::kEmbeddedWindowEnsureNotInRect));
-
-  // RestoreWindowBoundsOnClientFocusLost clears the property.
-  RestoreWindowBoundsOnClientFocusLost(embed_root->window());
-  EXPECT_EQ(nullptr, embed_root->window()->GetProperty(
-                         aura::client::kEmbeddedWindowEnsureNotInRect));
-}
-
 }  // namespace wm
diff --git a/ui/wm/test/wm_test_helper.cc b/ui/wm/test/wm_test_helper.cc
index b62bdb6..003170b6 100644
--- a/ui/wm/test/wm_test_helper.cc
+++ b/ui/wm/test/wm_test_helper.cc
@@ -4,27 +4,13 @@
 
 #include "ui/wm/test/wm_test_helper.h"
 
-#include <map>
 #include <memory>
 #include <utility>
-#include <vector>
 
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/ws/public/cpp/input_devices/input_device_client.h"
-#include "services/ws/public/cpp/property_type_converters.h"
-#include "services/ws/public/mojom/constants.mojom.h"
-#include "services/ws/public/mojom/window_manager.mojom.h"
 #include "ui/aura/client/default_capture_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/mus/property_converter.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
-#include "ui/aura/mus/window_tree_host_mus_init_params.h"
-#include "ui/aura/test/mus/window_tree_client_test_api.h"
 #include "ui/aura/test/test_focus_client.h"
 #include "ui/aura/test/test_screen.h"
 #include "ui/aura/window.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/platform_window/platform_window_init_properties.h"
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/default_activation_client.h"
@@ -32,15 +18,17 @@
 
 namespace wm {
 
-WMTestHelper::WMTestHelper(const gfx::Size& default_window_size,
-                           service_manager::Connector* connector,
-                           ui::ContextFactory* context_factory) {
-  if (context_factory)
-    aura::Env::GetInstance()->set_context_factory(context_factory);
-  if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL)
-    InitLocalHost(default_window_size);
-  else
-    InitMusHost(connector, default_window_size);
+WMTestHelper::WMTestHelper(const gfx::Size& default_window_size) {
+  wm_state_ = std::make_unique<WMState>();
+
+  // Install a screen, like TestWindowService's AuraTestHelper for InitMusHost.
+  test_screen_ = base::WrapUnique(aura::TestScreen::Create(gfx::Size()));
+  display::Screen::SetScreenInstance(test_screen_.get());
+
+  host_ = aura::WindowTreeHost::Create(
+      ui::PlatformWindowInitProperties{gfx::Rect(default_window_size)});
+  host_->InitHost();
+
   aura::client::SetWindowParentingClient(host_->window(), this);
 
   focus_client_.reset(new aura::test::TestFocusClient);
@@ -56,13 +44,6 @@
 }
 
 WMTestHelper::~WMTestHelper() {
-  if (test_ws_) {
-    // Wait for test_ws to shutdown so that its AuraTestHelper is destroyed
-    // and there is no lingering WindowTreeHost.
-    base::RunLoop run_loop;
-    test_ws_->Shutdown(run_loop.QuitClosure());
-    run_loop.Run();
-  }
   host_->window()->RemovePreTargetHandler(root_window_event_filter_.get());
 
   if (display::Screen::GetScreen() == test_screen_.get())
@@ -74,85 +55,4 @@
   return host_->window();
 }
 
-void WMTestHelper::InitLocalHost(const gfx::Size& default_window_size) {
-  wm_state_ = std::make_unique<WMState>();
-
-  // Install a screen, like TestWindowService's AuraTestHelper for InitMusHost.
-  test_screen_ = base::WrapUnique(aura::TestScreen::Create(gfx::Size()));
-  display::Screen::SetScreenInstance(test_screen_.get());
-
-  host_ = aura::WindowTreeHost::Create(
-      ui::PlatformWindowInitProperties{gfx::Rect(default_window_size)});
-  host_->InitHost();
-}
-
-void WMTestHelper::InitMusHost(service_manager::Connector* connector,
-                               const gfx::Size& default_window_size) {
-  DCHECK(!aura::Env::GetInstance()->HasWindowTreeClient());
-
-  const bool running_in_ws_process = features::IsSingleProcessMash();
-
-  if (!running_in_ws_process) {
-    wm_state_ = std::make_unique<WMState>();
-
-    input_device_client_ = std::make_unique<ws::InputDeviceClient>();
-    ws::mojom::InputDeviceServerPtr input_device_server;
-    connector->BindInterface(ws::mojom::kServiceName, &input_device_server);
-    input_device_client_->Connect(std::move(input_device_server));
-  }
-
-  property_converter_ = std::make_unique<aura::PropertyConverter>();
-
-  const bool create_discardable_memory = false;
-  window_tree_client_ = aura::WindowTreeClient::CreateForWindowTreeFactory(
-      connector, this, create_discardable_memory);
-  aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client_.get());
-  if (running_in_ws_process) {
-    // Spin message loop to wait for displays when WindowService runs in the
-    // same process to avoid deadlock.
-    display_wait_loop_ = std::make_unique<base::RunLoop>(
-        base::RunLoop::Type::kNestableTasksAllowed);
-    display_wait_loop_->Run();
-    display_wait_loop_.reset();
-
-    // Bind to test_ws so that it could be shutdown at the right time.
-    connector->BindInterface(test_ws::mojom::kServiceName, &test_ws_);
-  } else {
-    window_tree_client_->WaitForDisplays();
-  }
-
-  std::map<std::string, std::vector<uint8_t>> properties;
-  properties[ws::mojom::WindowManager::kBounds_InitProperty] =
-      mojo::ConvertTo<std::vector<uint8_t>>(gfx::Rect(default_window_size));
-
-  auto host_mus = std::make_unique<aura::WindowTreeHostMus>(
-      aura::CreateInitParamsForTopLevel(window_tree_client_.get(), properties));
-  host_mus->InitHost();
-
-  host_ = std::move(host_mus);
-}
-
-void WMTestHelper::OnEmbed(
-    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {}
-
-void WMTestHelper::OnUnembed(aura::Window* root) {}
-
-void WMTestHelper::OnEmbedRootDestroyed(
-    aura::WindowTreeHostMus* window_tree_host) {}
-
-void WMTestHelper::OnLostConnection(aura::WindowTreeClient* client) {}
-
-aura::PropertyConverter* WMTestHelper::GetPropertyConverter() {
-  return property_converter_.get();
-}
-
-void WMTestHelper::OnDisplaysChanged(
-    std::vector<ws::mojom::WsDisplayPtr> ws_displays,
-    int64_t primary_display_id,
-    int64_t internal_display_id,
-    int64_t display_id_for_new_windows) {
-  if (display_wait_loop_)
-    display_wait_loop_->Quit();
-}
-
 }  // namespace wm
diff --git a/ui/wm/test/wm_test_helper.h b/ui/wm/test/wm_test_helper.h
index 3ce5ac0..71f642bf 100644
--- a/ui/wm/test/wm_test_helper.h
+++ b/ui/wm/test/wm_test_helper.h
@@ -10,16 +10,12 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "services/ws/test_ws/test_ws.mojom.h"
 #include "ui/aura/client/window_parenting_client.h"
-#include "ui/aura/mus/window_tree_client_delegate.h"
 #include "ui/aura/window_tree_host.h"
 
 namespace aura {
-class PropertyConverter;
 class TestScreen;
 class Window;
-class WindowTreeClient;
 class WindowTreeHost;
 namespace client {
 class DefaultCaptureClient;
@@ -32,18 +28,6 @@
 class Size;
 }
 
-namespace service_manager {
-class Connector;
-}
-
-namespace ui {
-class ContextFactory;
-}
-
-namespace ws {
-class InputDeviceClient;
-}  // namespace ws
-
 namespace wm {
 
 class CompoundEventFilter;
@@ -52,12 +36,9 @@
 // Creates a minimal environment for running the shell. We can't pull in all of
 // ash here, but we can create and attach several of the same things we'd find
 // in ash.
-class WMTestHelper : public aura::client::WindowParentingClient,
-                     public aura::WindowTreeClientDelegate {
+class WMTestHelper : public aura::client::WindowParentingClient {
  public:
-  WMTestHelper(const gfx::Size& default_window_size,
-               service_manager::Connector* coonnector,
-               ui::ContextFactory* context_factory);
+  explicit WMTestHelper(const gfx::Size& default_window_size);
   ~WMTestHelper() override;
 
   aura::WindowTreeHost* host() { return host_.get(); }
@@ -67,40 +48,13 @@
                                  const gfx::Rect& bounds) override;
 
  private:
-  // Used when aura is running in Mode::LOCAL.
-  void InitLocalHost(const gfx::Size& default_window_size);
-
-  // Used when aura is running in Mode::MUS.
-  void InitMusHost(service_manager::Connector* connector,
-                   const gfx::Size& default_window_size);
-
-  // aura::WindowTreeClientDelegate:
-  void OnEmbed(
-      std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) override;
-  void OnUnembed(aura::Window* root) override;
-  void OnEmbedRootDestroyed(aura::WindowTreeHostMus* window_tree_host) override;
-  void OnLostConnection(aura::WindowTreeClient* client) override;
-  aura::PropertyConverter* GetPropertyConverter() override;
-  void OnDisplaysChanged(std::vector<ws::mojom::WsDisplayPtr> ws_displays,
-                         int64_t primary_display_id,
-                         int64_t internal_display_id,
-                         int64_t display_id_for_new_windows) override;
-
   std::unique_ptr<WMState> wm_state_;
   std::unique_ptr<aura::TestScreen> test_screen_;
-  std::unique_ptr<ws::InputDeviceClient> input_device_client_;
-  std::unique_ptr<aura::PropertyConverter> property_converter_;
-  std::unique_ptr<aura::WindowTreeClient> window_tree_client_;
   std::unique_ptr<aura::WindowTreeHost> host_;
   std::unique_ptr<wm::CompoundEventFilter> root_window_event_filter_;
   std::unique_ptr<aura::client::DefaultCaptureClient> capture_client_;
   std::unique_ptr<aura::client::FocusClient> focus_client_;
 
-  // Loop to wait for |host_| gets embedded under mus.
-  std::unique_ptr<base::RunLoop> display_wait_loop_;
-
-  test_ws::mojom::TestWsPtr test_ws_;
-
   DISALLOW_COPY_AND_ASSIGN(WMTestHelper);
 };