diff --git a/.gn b/.gn
index 3464667..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..a727399 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 4facca4..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 e07b1f0..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 ec90e7f..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 7a67814..9002917 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 52a0955..f845b70 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 6052946..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 f8aa771..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 ed7be4d..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 e926b5f..0ad4d12 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..f2bc883 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..eb86c61 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 845cc48..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..d7314e6 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 acb32f4..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..773d401 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 616d9f0..6bb57f8 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..e3e32c0 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 3246539..3a11692 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 24467bd..0932224 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..276691e 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..2a9ef4f 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 988daea..778aa6f 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..0f98e4f 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..a457c28 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..d074c79 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 5e12523..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 0de9db9..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 fe70247..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..0ec1917
--- /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..667d2a9
--- /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..f0af5bb
--- /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..3e3dcaa
--- /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 1d65761..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 6260c24..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..4deea43 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..74b531c 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..e893d40 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..a1f8b53 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..c1c6957 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..9af0e51 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 5fdf97c..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 c82d7bc..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 2308d92..6eda401 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 f59f5a2..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..47dc8ab 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..7059674 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 087f8b2..77f3210 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 f873c97..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 03d3e09..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 fac25c2..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 42d7b02..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..165bb01 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 650742f..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..9c6d1e0 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..ee45929 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..50ae6ad 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..9c4881f 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..338f3aa 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 71408f6..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 b9ce254..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..f1a980c 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..3d12ebd 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 fc0ccf6..f74851d 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..fc1fd89 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 e0c7624..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 2b3a4f5..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 d637ecd..0814fc7 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 d93a39b..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 bd64927..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 ad64783..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..38e5fda 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..1c70a77 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 0957c1d..0173297 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 610c645..b11be95 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 0ac6c26..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..8c9e616 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 52ab5c9..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 653cc0a..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..f225d54 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 ed2e597..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..22fa67e 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..bb35972 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..a1f0bcd 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 9fee25d..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 0301969..9f90201 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..8c88ef0 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 ba46281..131846c 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 a05900b..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..36444ce 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..578e902 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..1e293ad 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..d133f58 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 b1f3eea..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..6eac149
--- /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 5df1a30..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..b776776 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("