diff --git a/AUTHORS b/AUTHORS
index 0c29cc8..ce3d7cf 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -384,7 +384,6 @@
 Jihun Brent Kim <devgrapher@gmail.com>
 Jin Yang <jin.a.yang@intel.com>
 Jincheol Jo <jincheol.jo@navercorp.com>
-Jinglong Zuo <zuojinglong@xiaomi.com>
 Jingwei Liu <kingweiliu@gmail.com>
 Jingyi Wei <wjywbs@gmail.com>
 Jinho Bang <jinho.bang@samsung.com>
diff --git a/BUILD.gn b/BUILD.gn
index 9dec8407e..8e3a525 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -949,7 +949,6 @@
     if (is_fuchsia) {
       data_deps += [
         "//content/shell:content_shell_fuchsia",
-        "//build/fuchsia/layout_test_proxy:layout_test_proxy_runner",
       ]
     }
 
diff --git a/DEPS b/DEPS
index cb7f18d2..bd8b7f3 100644
--- a/DEPS
+++ b/DEPS
@@ -100,7 +100,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'e3f3bcb29041e7e926c0a6542bfb85d98b8667da',
+  'v8_revision': '9c5f77a1382ee3825f708aba48f5675fb55c84e1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -120,7 +120,7 @@
   # 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': 'ad18d2fba9dd5833a2e34bfe90c8e3c9a485e805',
+  'pdfium_revision': '95061379c9453b941783398826acff674d2bbfd7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -156,7 +156,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': '4a13b64861dc64457f225a772233438ae35f311d',
+  'catapult_revision': '0675e8b8e369f603bbcfc9a992af876d8476e344',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -523,7 +523,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '7c3ff1311a4568e3d369c35560ff77b6b2bdef96',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd3f2c8e7834616e48fbe7cef9286029361b043c5',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -968,7 +968,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7c0541da63f571512c49758cbc0767117997a270',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'b4e0e50a2bbf9361bea22f58002ad4c76a719fed', # commit position 21742
+    Var('webrtc_git') + '/src.git' + '@' + '7f0a069550922031f740eb1a67b18cd06b579199', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/aw_contents_statics.cc b/android_webview/browser/aw_contents_statics.cc
index b1f7b4f7..081c02f5 100644
--- a/android_webview/browser/aw_contents_statics.cc
+++ b/android_webview/browser/aw_contents_statics.cc
@@ -41,7 +41,7 @@
 
 void NotifyClientCertificatesChanged() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  net::CertDatabase::GetInstance()->OnAndroidKeyStoreChanged();
+  net::CertDatabase::GetInstance()->NotifyObserversCertDBChanged();
 }
 
 void SafeBrowsingWhitelistAssigned(const JavaRef<jobject>& callback,
diff --git a/android_webview/browser/aw_field_trial_creator.cc b/android_webview/browser/aw_field_trial_creator.cc
index c5e2044..1f81d4d 100644
--- a/android_webview/browser/aw_field_trial_creator.cc
+++ b/android_webview/browser/aw_field_trial_creator.cc
@@ -37,6 +37,19 @@
       new variations::SHA1EntropyProvider(client_id));
 }
 
+// This experiment is for testing and doesn't control any features. Log it so QA
+// can check whether variations is working.
+// TODO(crbug/841623): Remove this after launch.
+void LogTestExperiment() {
+  static const char* const test_name = "First-WebView-Experiment";
+  base::FieldTrial* test_trial = base::FieldTrialList::Find(test_name);
+  if (test_trial) {
+    LOG(INFO) << test_name << " found, group=" << test_trial->group_name();
+  } else {
+    LOG(INFO) << test_name << " not found";
+  }
+}
+
 }  // anonymous namespace
 
 AwFieldTrialCreator::AwFieldTrialCreator()
@@ -108,6 +121,8 @@
       std::vector<std::string>(), CreateLowEntropyProvider(client_id),
       std::make_unique<base::FeatureList>(), aw_field_trials_.get(),
       &ignored_safe_seed_manager);
+
+  LogTestExperiment();
 }
 
 }  // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 19abaed..2bdd9c5 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1208,6 +1208,7 @@
   public_deps = [
     "//ash/public/cpp",
     "//ash/public/cpp/vector_icons",
+    "//ash/resources",
     "//ash/resources/vector_icons",
     "//ash/strings",
     "//ash/wayland",
@@ -1830,6 +1831,7 @@
     "//ash/public/cpp",
     "//ash/public/cpp:unit_tests",
     "//ash/public/cpp/vector_icons",
+    "//ash/resources",
     "//ash/resources/vector_icons",
     "//ash/strings",
     "//ash/touch_hud",
@@ -2128,6 +2130,7 @@
     "//ash/components/fast_ink",
     "//ash/public/cpp",
     "//ash/public/interfaces:test_interfaces",
+    "//ash/resources",
     "//base",
     "//base:i18n",
     "//base/test:test_support",
@@ -2229,6 +2232,7 @@
   output = "$root_out_dir/ash_service_resources.pak"
   sources = [
     "$root_gen_dir/ash/components/resources/ash_components_resources_100_percent.pak",
+    "$root_gen_dir/ash/resources/ash_resources_100_percent.pak",
     "$root_gen_dir/ash/strings/ash_strings_en-US.pak",
     "$root_gen_dir/ui/chromeos/resources/ui_chromeos_resources_100_percent.pak",
     "$root_gen_dir/ui/chromeos/strings/ui_chromeos_strings_en-US.pak",
@@ -2239,6 +2243,7 @@
   ]
   deps = [
     "//ash/components/resources",
+    "//ash/resources",
     "//ash/strings",
     "//ui/chromeos/resources",
     "//ui/chromeos/strings",
@@ -2253,12 +2258,14 @@
   output = "$root_out_dir/ash_service_resources_200.pak"
   sources = [
     "$root_gen_dir/ash/components/resources/ash_components_resources_200_percent.pak",
+    "$root_gen_dir/ash/resources/ash_resources_200_percent.pak",
     "$root_gen_dir/ui/chromeos/resources/ui_chromeos_resources_200_percent.pak",
     "$root_gen_dir/ui/resources/ui_resources_200_percent.pak",
     "$root_gen_dir/ui/views/resources/views_resources_200_percent.pak",
   ]
   deps = [
     "//ash/components/resources",
+    "//ash/resources",
     "//ui/chromeos/resources",
     "//ui/resources",
     "//ui/views/resources",
diff --git a/ash/display/resolution_notification_controller.cc b/ash/display/resolution_notification_controller.cc
index 7d31f4e..22e7bb2 100644
--- a/ash/display/resolution_notification_controller.cc
+++ b/ash/display/resolution_notification_controller.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/display/display.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/managed_display_info.h"
@@ -220,22 +221,17 @@
                 base::UTF8ToUTF16(
                     change_info_->current_resolution.size().ToString()));
 
-  std::unique_ptr<Notification> notification =
-      Notification::CreateSystemNotification(
-          message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message,
-          timeout_message, gfx::Image(),
-          base::string16(),  // display_source
-          GURL(),
-          message_center::NotifierId(
-              message_center::NotifierId::SYSTEM_COMPONENT,
-              kNotifierDisplayResolutionChange),
-          data,
-          base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
-              weak_factory_.GetWeakPtr()),
-          kNotificationScreenIcon,
-          message_center::SystemNotificationWarningLevel::NORMAL);
-  notification->set_priority(message_center::SYSTEM_PRIORITY);
-
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+  auto notification = std::make_unique<Notification>(
+      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message,
+      timeout_message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_DISPLAY),
+      base::string16() /* display_source */, GURL(),
+      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
+                                 kNotifierDisplayResolutionChange),
+      data,
+      base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
+          weak_factory_.GetWeakPtr()));
+  notification->SetSystemPriority();
   message_center->AddNotification(std::move(notification));
 }
 
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc
index d357ba7..5001aad 100644
--- a/ash/frame/caption_buttons/frame_caption_button.cc
+++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -220,7 +220,13 @@
 }
 
 void FrameCaptionButton::SetBackgroundColor(SkColor background_color) {
+  if (background_color_ == background_color)
+    return;
+
   background_color_ = background_color;
+  // Refresh the icon since the color may have changed.
+  if (icon_definition_)
+    SetImage(icon_, ANIMATE_NO, *icon_definition_);
   UpdateInkDropBaseColor();
 }
 
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h
index cb94faa6..5bed667 100644
--- a/ash/frame/caption_buttons/frame_caption_button.h
+++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -73,6 +73,8 @@
     paint_as_active_ = paint_as_active;
   }
 
+  bool paint_as_active() { return paint_as_active_; }
+
   CaptionButtonIcon icon() const { return icon_; }
 
   const gfx::VectorIcon* icon_definition_for_test() const {
diff --git a/ash/frame/custom_frame_header.cc b/ash/frame/custom_frame_header.cc
index d47f98f..89b710d 100644
--- a/ash/frame/custom_frame_header.cc
+++ b/ash/frame/custom_frame_header.cc
@@ -141,6 +141,15 @@
   appearance_provider_ = appearance_provider;
   is_incognito_ = incognito;
   caption_button_container_ = caption_button_container;
+
+  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_MINIMIZE,
+                                            kWindowControlMinimizeIcon);
+  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_CLOSE,
+                                            kWindowControlCloseIcon);
+  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_LEFT_SNAPPED,
+                                            kWindowControlLeftSnappedIcon);
+  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
+                                            kWindowControlRightSnappedIcon);
 }
 
 int CustomFrameHeader::GetMinimumHeaderWidth() const {
@@ -216,6 +225,7 @@
 void CustomFrameHeader::OnShowStateChanged(ui::WindowShowState show_state) {
   if (show_state == ui::SHOW_STATE_MINIMIZED)
     return;
+
   // Call LayoutHeaderInternal() instead of LayoutHeader() here because
   // |show_state| shouldn't cause |painted_height_| change.
   LayoutHeaderInternal();
@@ -249,7 +259,19 @@
 // CustomFrameHeader, private:
 
 void CustomFrameHeader::LayoutHeaderInternal() {
-  UpdateCaptionButtons();
+  caption_button_container_->SetButtonImage(
+      CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
+      GetWidget()->IsMaximized() || GetWidget()->IsFullscreen()
+          ? kWindowControlRestoreIcon
+          : kWindowControlMaximizeIcon);
+
+  const AshLayoutSize button_size_type =
+      GetWidget()->IsMaximized() || GetWidget()->IsFullscreen() ||
+              appearance_provider_->IsTabletMode()
+          ? AshLayoutSize::kBrowserCaptionMaximized
+          : AshLayoutSize::kBrowserCaptionRestored;
+  caption_button_container_->SetButtonSize(GetAshLayoutSize(button_size_type));
+
   const gfx::Size caption_button_container_size =
       caption_button_container_->GetPreferredSize();
   caption_button_container_->SetBounds(
@@ -307,35 +329,6 @@
       gfx::Canvas::NO_SUBPIXEL_RENDERING);
 }
 
-void CustomFrameHeader::UpdateCaptionButtons() {
-  // When |frame_| minimized, avoid tablet mode toggling to update caption
-  // buttons as it would cause mismatch beteen window state and size button.
-  if (GetWidget()->IsMinimized())
-    return;
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_MINIMIZE,
-                                            kWindowControlMinimizeIcon);
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_CLOSE,
-                                            kWindowControlCloseIcon);
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_LEFT_SNAPPED,
-                                            kWindowControlLeftSnappedIcon);
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
-                                            kWindowControlRightSnappedIcon);
-
-  const bool is_maximized_or_fullscreen =
-      GetWidget()->IsMaximized() || GetWidget()->IsFullscreen();
-  const AshLayoutSize button_size_type =
-      is_maximized_or_fullscreen || appearance_provider_->IsTabletMode()
-          ? AshLayoutSize::kBrowserCaptionMaximized
-          : AshLayoutSize::kBrowserCaptionRestored;
-  const gfx::VectorIcon* const size_icon = is_maximized_or_fullscreen
-                                               ? &kWindowControlRestoreIcon
-                                               : &kWindowControlMaximizeIcon;
-
-  caption_button_container_->SetButtonImage(
-      CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, *size_icon);
-  caption_button_container_->SetButtonSize(GetAshLayoutSize(button_size_type));
-}
-
 gfx::Rect CustomFrameHeader::GetPaintedBounds() const {
   return gfx::Rect(view_->width(), painted_height_);
 }
diff --git a/ash/frame/custom_frame_header.h b/ash/frame/custom_frame_header.h
index 8eaa05b..561d3732 100644
--- a/ash/frame/custom_frame_header.h
+++ b/ash/frame/custom_frame_header.h
@@ -82,10 +82,6 @@
   // Paints the title bar, primarily the title string.
   void PaintTitleBar(gfx::Canvas* canvas);
 
-  // Updates the size and icons used for the minimize, restore, and close
-  // buttons.
-  void UpdateCaptionButtons();
-
   // Returns bounds of the region in |view_| which is painted with the header
   // images. The region is assumed to start at the top left corner of |view_|
   // and to have the same width as |view_|.
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index adc097f..373155c2 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -37,9 +37,6 @@
 const base::Feature kLockScreenNotifications{"LockScreenNotifications",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kModeSpecificPowerButton{"ModeSpecificPowerButton",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 bool IsDisplayMoveWindowAccelsEnabled() {
   return base::FeatureList::IsEnabled(kDisplayMoveWindowAccels);
 }
@@ -70,9 +67,5 @@
   return base::FeatureList::IsEnabled(kLockScreenNotifications);
 }
 
-bool IsModeSpecificPowerButtonEnabled() {
-  return base::FeatureList::IsEnabled(kModeSpecificPowerButton);
-}
-
 }  // namespace features
 }  // namespace ash
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 764849d..14c226a 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -55,11 +55,6 @@
 // Enables notifications on the lock screen.
 ASH_PUBLIC_EXPORT extern const base::Feature kLockScreenNotifications;
 
-// Enables mode-specific power button behavior.
-// TODO(derat): Remove this after we make a decision about whether to enable it
-// by default: https://crbug.com/819276
-ASH_PUBLIC_EXPORT extern const base::Feature kModeSpecificPowerButton;
-
 ASH_PUBLIC_EXPORT bool IsDisplayMoveWindowAccelsEnabled();
 
 ASH_PUBLIC_EXPORT bool IsDockedMagnifierEnabled();
@@ -74,8 +69,6 @@
 
 ASH_PUBLIC_EXPORT bool IsLockScreenNotificationsEnabled();
 
-ASH_PUBLIC_EXPORT bool IsModeSpecificPowerButtonEnabled();
-
 }  // namespace features
 }  // namespace ash
 
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 79c94b0..b494e79 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -122,10 +122,6 @@
 // instead of displaying an interactive animation.
 const char kAuraLegacyPowerButton[] = "aura-legacy-power-button";
 
-// Forces non-tablet-style power button behavior even if the device has a
-// convertible form factor.
-const char kForceClamshellPowerButton[] = "force-clamshell-power-button";
-
 // Whether this device has an internal stylus.
 const char kHasInternalStylus[] = "has-internal-stylus";
 
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index 0b198ed6..4bd63cbc 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -53,7 +53,6 @@
 ASH_PUBLIC_EXPORT extern const char kAshSidebarEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAshTouchHud[];
 ASH_PUBLIC_EXPORT extern const char kAuraLegacyPowerButton[];
-ASH_PUBLIC_EXPORT extern const char kForceClamshellPowerButton[];
 ASH_PUBLIC_EXPORT extern const char kHasInternalStylus[];
 ASH_PUBLIC_EXPORT extern const char kShowTaps[];
 ASH_PUBLIC_EXPORT extern const char kShowViewsLogin[];
diff --git a/ash/resources/BUILD.gn b/ash/resources/BUILD.gn
index 630351a..625e6dc 100644
--- a/ash/resources/BUILD.gn
+++ b/ash/resources/BUILD.gn
@@ -9,6 +9,15 @@
 assert(is_chromeos)
 assert(enable_hidpi)
 
+grit("resources") {
+  source = "ash_resources.grd"
+  outputs = [
+    "grit/ash_resources.h",
+    "ash_resources_100_percent.pak",
+    "ash_resources_200_percent.pak",
+  ]
+}
+
 # Repacks resources needed for ash_unittests, etc. at a given scale.
 # TODO(msw): Use ui_test.pak instead of its pieces? (no 200% support?)
 template("ash_test_resources") {
@@ -20,6 +29,7 @@
     sources = [
       "$root_gen_dir/ash/components/resources/ash_components_resources_${percent}_percent.pak",
       "$root_gen_dir/ash/public/cpp/resources/ash_public_unscaled_resources.pak",
+      "$root_gen_dir/ash/resources/ash_resources_${percent}_percent.pak",
       "$root_gen_dir/ui/app_list/resources/app_list_resources_${percent}_percent.pak",
       "$root_gen_dir/ui/chromeos/resources/ui_chromeos_resources_${percent}_percent.pak",
       "$root_gen_dir/ui/resources/ui_resources_${percent}_percent.pak",
@@ -40,6 +50,7 @@
     deps = [
       "//ash/components/resources",
       "//ash/public/cpp/resources:ash_public_unscaled_resources",
+      "//ash/resources",
       "//mojo/public/js:resources",
       "//ui/app_list/resources",
       "//ui/chromeos/resources",
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
new file mode 100644
index 0000000..1edf3c9
--- /dev/null
+++ b/ash/resources/ash_resources.grd
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/ash_resources.h" type="rc_header" context="default_100_percent">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="ash_resources_100_percent.pak" type="data_package" context="default_100_percent" />
+    <output filename="ash_resources_200_percent.pak" type="data_package" context="default_200_percent" />
+  </outputs>
+  <release seq="1">
+    <structures fallback_to_low_resolution="true">
+      <!-- KEEP THESE IN ALPHABETICAL ORDER!  DO NOT ADD TO RANDOM PLACES JUST
+           BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE
+           SAME CONDITIONALS. -->
+
+      <structure type="chrome_scaled_image" name="IDR_AURA_NOTIFICATION_DISPLAY" file="cros/notification/display_notification_icon.png" />
+    </structures>
+  </release>
+</grit>
diff --git a/ash/resources/default_100_percent/cros/notification/display_notification_icon.png b/ash/resources/default_100_percent/cros/notification/display_notification_icon.png
new file mode 100644
index 0000000..e49d82a2
--- /dev/null
+++ b/ash/resources/default_100_percent/cros/notification/display_notification_icon.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/notification/display_notification_icon.png b/ash/resources/default_200_percent/cros/notification/display_notification_icon.png
new file mode 100644
index 0000000..832e974f
--- /dev/null
+++ b/ash/resources/default_200_percent/cros/notification/display_notification_icon.png
Binary files differ
diff --git a/ash/system/bluetooth/bluetooth_notification_controller.cc b/ash/system/bluetooth/bluetooth_notification_controller.cc
index c517b81b..58e6b82 100644
--- a/ash/system/bluetooth/bluetooth_notification_controller.cc
+++ b/ash/system/bluetooth/bluetooth_notification_controller.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "base/bind.h"
diff --git a/ash/system/locale/locale_notification_controller.cc b/ash/system/locale/locale_notification_controller.cc
index 8c2a573..bb84369c 100644
--- a/ash/system/locale/locale_notification_controller.cc
+++ b/ash/system/locale/locale_notification_controller.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/public/cpp/vector_icons/vector_icons.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/strings/string16.h"
diff --git a/ash/system/message_center/notification_tray.cc b/ash/system/message_center/notification_tray.cc
index 66ee5a3..8c3fe8c 100644
--- a/ash/system/message_center/notification_tray.cc
+++ b/ash/system/message_center/notification_tray.cc
@@ -189,6 +189,16 @@
  private:
   // gfx::AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override {
+    // After HideAndDelete() has been called and |this| is responsible for
+    // deleting itself, but |tray_| has been deleted before the animation
+    // reached its end, |this| will be parentless. It's ok to stop the animation
+    // (deleting |this|). See https://crbug.com/841768
+    if (!parent()) {
+      DCHECK(delete_after_animation_);
+      animation_->Stop();
+      return;
+    }
+
     gfx::Transform transform;
     if (tray_->shelf()->IsHorizontalAlignment()) {
       transform.Translate(0, animation->CurrentValueBetween(
@@ -202,6 +212,7 @@
     layer()->SetTransform(transform);
     PreferredSizeChanged();
   }
+
   void AnimationEnded(const gfx::Animation* animation) override {
     if (animation->GetCurrentValue() < 0.1)
       views::View::SetVisible(false);
diff --git a/ash/system/power/battery_notification.cc b/ash/system/power/battery_notification.cc
index 75d9066..6202550 100644
--- a/ash/system/power/battery_notification.cc
+++ b/ash/system/power/battery_notification.cc
@@ -5,6 +5,7 @@
 #include "ash/system/power/battery_notification.h"
 
 #include "ash/public/cpp/power_utils.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/power/power_status.h"
diff --git a/ash/system/power/dual_role_notification.cc b/ash/system/power/dual_role_notification.cc
index a27e009..9f6b204 100644
--- a/ash/system/power/dual_role_notification.cc
+++ b/ash/system/power/dual_role_notification.cc
@@ -6,6 +6,7 @@
 
 #include <set>
 
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/system/power/peripheral_battery_notifier.cc b/ash/system/power/peripheral_battery_notifier.cc
index f3850e7..f1b9023 100644
--- a/ash/system/power/peripheral_battery_notifier.cc
+++ b/ash/system/power/peripheral_battery_notifier.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc
index fbd0033..a75a504 100644
--- a/ash/system/power/power_button_controller.cc
+++ b/ash/system/power/power_button_controller.cc
@@ -211,7 +211,7 @@
     const base::TimeTicks& timestamp) {
   if (down) {
     force_off_on_button_up_ = false;
-    if (ShouldTurnScreenOffForTap()) {
+    if (in_tablet_mode_) {
       force_off_on_button_up_ = true;
 
       // When the system resumes in response to the power button being pressed,
@@ -242,7 +242,7 @@
       return;
     }
 
-    if (!ShouldTurnScreenOffForTap()) {
+    if (!in_tablet_mode_) {
       StartPowerMenuAnimation();
     } else {
       base::TimeDelta timeout = screen_off_when_power_button_down_
@@ -268,7 +268,7 @@
     pre_shutdown_timer_.Stop();
 
     const bool menu_was_opened = IsMenuOpened();
-    if (!ShouldTurnScreenOffForTap()) {
+    if (!in_tablet_mode_) {
       // Cancel the menu animation if it's still ongoing when the button is
       // released on a laptop-mode device.
       if (menu_was_opened && !show_menu_animation_done_) {
@@ -407,27 +407,17 @@
   if (!result.has_value())
     return;
 
-  // Turn screen off if tapping the power button (except
-  // |force_clamshell_power_button_|) and power button screenshot accelerator
-  // are enabled on devices that have a tablet mode switch.
-  if (result->tablet_mode ==
+  if (result->tablet_mode !=
       chromeos::PowerManagerClient::TabletMode::UNSUPPORTED) {
-    return;
+    has_tablet_mode_switch_ = true;
+    InitTabletPowerButtonMembers();
   }
-
-  has_tablet_mode_switch_ = true;
-  InitTabletPowerButtonMembers();
 }
 
 void PowerButtonController::OnAccelerometerUpdated(
     scoped_refptr<const chromeos::AccelerometerUpdate> update) {
-  // Turn screen off if tapping the power button (except
-  // |force_clamshell_power_button_|) and power button screenshot accelerator
-  // are enabled on devices that can enter tablet mode, which must have a tablet
-  // mode switch or report accelerometer data before user actions.
-  if (has_tablet_mode_switch_ || !observe_accelerometer_events_)
-    return;
-  InitTabletPowerButtonMembers();
+  if (!has_tablet_mode_switch_ && observe_accelerometer_events_)
+    InitTabletPowerButtonMembers();
 }
 
 void PowerButtonController::OnBacklightsForcedOffChanged(bool forced_off) {
@@ -460,12 +450,6 @@
     lock_button_down_ = false;
 }
 
-bool PowerButtonController::ShouldTurnScreenOffForTap() const {
-  return features::IsModeSpecificPowerButtonEnabled()
-             ? in_tablet_mode_
-             : default_turn_screen_off_for_tap_;
-}
-
 void PowerButtonController::StopTimersAndDismissMenu() {
   pre_shutdown_timer_.Stop();
   power_button_menu_timer_.Stop();
@@ -503,16 +487,11 @@
                      ? ButtonType::LEGACY
                      : ButtonType::NORMAL;
   observe_accelerometer_events_ = cl->HasSwitch(switches::kAshEnableTabletMode);
-  force_clamshell_power_button_ =
-      cl->HasSwitch(switches::kForceClamshellPowerButton);
 
   ParsePowerButtonPositionSwitch();
 }
 
 void PowerButtonController::InitTabletPowerButtonMembers() {
-  if (!force_clamshell_power_button_)
-    default_turn_screen_off_for_tap_ = true;
-
   if (!screenshot_controller_) {
     screenshot_controller_ =
         std::make_unique<PowerButtonScreenshotController>(tick_clock_);
diff --git a/ash/system/power/power_button_controller.h b/ash/system/power/power_button_controller.h
index 0a19026..9e78275 100644
--- a/ash/system/power/power_button_controller.h
+++ b/ash/system/power/power_button_controller.h
@@ -126,8 +126,8 @@
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
   void SuspendDone(const base::TimeDelta& sleep_duration) override;
 
-  // Initializes |default_turn_screen_off_for_tap_| and |screenshot_controller_|
-  // according to the tablet mode switch in |result|.
+  // Initializes |screenshot_controller_| according to the tablet mode switch in
+  // |result|.
   void OnGetSwitchStates(
       base::Optional<chromeos::PowerManagerClient::SwitchStates> result);
 
@@ -153,10 +153,6 @@
   class ActiveWindowWidgetController;
   friend class PowerButtonControllerTestApi;
 
-  // Returns true if the screen should be turned off in response to the power
-  // button being tapped.
-  bool ShouldTurnScreenOffForTap() const;
-
   // Stops |power_button_menu_timer_|, |shutdown_timer_| and dismisses the power
   // button menu.
   void StopTimersAndDismissMenu();
@@ -173,8 +169,8 @@
   // current command line.
   void ProcessCommandLine();
 
-  // Initializes tablet power button behavior related members
-  // |default_turn_screen_off_for_tap_| and |screenshot_controller_|.
+  // Initializes tablet power button behavior related member
+  // |screenshot_controller_|.
   void InitTabletPowerButtonMembers();
 
   // Locks the screen if the "Show lock screen when waking from sleep" pref is
@@ -225,11 +221,6 @@
   // True if the device has tablet mode switch.
   bool has_tablet_mode_switch_ = false;
 
-  // True if we should turn screen off when the power button is tapped.
-  // This may be overridden by a feature; use ShouldTurnScreenOffForTap() to
-  // get the actual desired behavior.
-  bool default_turn_screen_off_for_tap_ = false;
-
   // True if the screen was off when the power button was pressed.
   bool screen_off_when_power_button_down_ = false;
 
diff --git a/ash/system/power/power_button_controller_test_api.cc b/ash/system/power/power_button_controller_test_api.cc
index bb50db71..4bb27c7 100644
--- a/ash/system/power/power_button_controller_test_api.cc
+++ b/ash/system/power/power_button_controller_test_api.cc
@@ -93,11 +93,6 @@
           controller_->backlights_forced_off_setter_, controller_->tick_clock_);
 }
 
-void PowerButtonControllerTestApi::SetTurnScreenOffForTap(
-    bool turn_screen_off_for_tap) {
-  controller_->default_turn_screen_off_for_tap_ = turn_screen_off_for_tap;
-}
-
 void PowerButtonControllerTestApi::SetShowMenuAnimationDone(
     bool show_menu_animation_done) {
   controller_->show_menu_animation_done_ = show_menu_animation_done;
diff --git a/ash/system/power/power_button_controller_test_api.h b/ash/system/power/power_button_controller_test_api.h
index 4d4c14f..000f23b 100644
--- a/ash/system/power/power_button_controller_test_api.h
+++ b/ash/system/power/power_button_controller_test_api.h
@@ -67,8 +67,6 @@
 
   void SetTickClock(const base::TickClock* tick_clock);
 
-  void SetTurnScreenOffForTap(bool turn_screen_off_for_tap);
-
   void SetShowMenuAnimationDone(bool show_menu_animation_done);
 
  private:
diff --git a/ash/system/power/power_button_controller_unittest.cc b/ash/system/power/power_button_controller_unittest.cc
index 8776299..ed7ac33 100644
--- a/ash/system/power/power_button_controller_unittest.cc
+++ b/ash/system/power/power_button_controller_unittest.cc
@@ -278,24 +278,6 @@
   // Should turn screen on if screen is off.
   AdvanceClockToAvoidIgnoring();
   TappingPowerButtonWhenScreenIsIdleOff();
-
-  // Should not turn screen off if clamshell-like power button behavior is
-  // requested.
-  AdvanceClockToAvoidIgnoring();
-  ForceClamshellPowerButton();
-  SetTabletModeSwitchState(PowerManagerClient::TabletMode::ON);
-  AdvanceClockToAvoidIgnoring();
-  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
-  PressPowerButton();
-  power_button_test_api_->SetShowMenuAnimationDone(false);
-  // Forced clamshell power button device should start showing menu animation
-  // immediately as pressing the power button.
-  EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
-  ReleasePowerButton();
-  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
-  // Forced clamshell power button device should start dismissing menu animation
-  // immediately as releasing the power button.
-  EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
 }
 
 // Tests that power button taps turn the screen off while in tablet mode but not
diff --git a/ash/system/power/power_button_test_base.cc b/ash/system/power/power_button_test_base.cc
index 352110f..4f51a11 100644
--- a/ash/system/power/power_button_test_base.cc
+++ b/ash/system/power/power_button_test_base.cc
@@ -67,9 +67,7 @@
   if (initial_tablet_mode_switch_state !=
       chromeos::PowerManagerClient::TabletMode::UNSUPPORTED) {
     SetTabletModeSwitchState(initial_tablet_mode_switch_state);
-    screenshot_controller_ = power_button_test_api_->GetScreenshotController();
   } else {
-    power_button_test_api_->SetTurnScreenOffForTap(false);
     screenshot_controller_ = nullptr;
   }
 }
@@ -84,12 +82,6 @@
   screenshot_controller_ = power_button_test_api_->GetScreenshotController();
 }
 
-void PowerButtonTestBase::ForceClamshellPowerButton() {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kForceClamshellPowerButton);
-  ResetPowerButtonController();
-}
-
 void PowerButtonTestBase::PressPowerButton() {
   power_button_controller_->PowerButtonEventReceived(true,
                                                      tick_clock_.NowTicks());
diff --git a/ash/system/power/power_button_test_base.h b/ash/system/power/power_button_test_base.h
index f96c3fe..783f755 100644
--- a/ash/system/power/power_button_test_base.h
+++ b/ash/system/power/power_button_test_base.h
@@ -55,10 +55,6 @@
   void SetTabletModeSwitchState(
       chromeos::PowerManagerClient::TabletMode tablet_mode_switch_state);
 
-  // Sets the flag for forcing clamshell-like power button behavior and resets
-  // |power_button_controller_|.
-  void ForceClamshellPowerButton();
-
   // Simulates a power button press.
   void PressPowerButton();
 
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc
index 630e6d8..df245179 100644
--- a/ash/system/power/tray_power.cc
+++ b/ash/system/power/tray_power.cc
@@ -8,7 +8,7 @@
 
 #include "ash/accessibility/accessibility_delegate.h"
 #include "ash/public/cpp/ash_switches.h"
-
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/date/date_view.h"
diff --git a/ash/system/screen_layout_observer.cc b/ash/system/screen_layout_observer.cc
index 78aae21..b4b96a3 100644
--- a/ash/system/screen_layout_observer.cc
+++ b/ash/system/screen_layout_observer.cc
@@ -11,6 +11,7 @@
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/metrics/user_metrics_action.h"
 #include "ash/metrics/user_metrics_recorder.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
diff --git a/ash/system/screen_security/screen_capture_tray_item.cc b/ash/system/screen_security/screen_capture_tray_item.cc
index 61616d8..472194a9 100644
--- a/ash/system/screen_security/screen_capture_tray_item.cc
+++ b/ash/system/screen_security/screen_capture_tray_item.cc
@@ -9,7 +9,7 @@
 #include "ash/metrics/user_metrics_action.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/ash_features.h"
-
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/system/screen_security/screen_share_tray_item.cc b/ash/system/screen_security/screen_share_tray_item.cc
index eed0520c..38ee086 100644
--- a/ash/system/screen_security/screen_share_tray_item.cc
+++ b/ash/system/screen_security/screen_share_tray_item.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index ad0fd94..a007d60b 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -635,24 +635,6 @@
   EXPECT_TRUE(controller.IsTabletModeWindowManagerEnabled());
 }
 
-// Verify when the force clamshell mode flag is turned on, opening the lid past
-// 180 degrees or setting tablet mode to true will no turn on tablet mode.
-TEST_F(TabletModeControllerTest, ForceClamshellModeTest) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kAshUiMode, switches::kAshUiModeClamshell);
-  tablet_mode_controller()->OnShellInitialized();
-  EXPECT_EQ(TabletModeController::UiMode::CLAMSHELL, forced_ui_mode());
-  EXPECT_FALSE(IsTabletModeStarted());
-
-  OpenLidToAngle(300.0f);
-  EXPECT_FALSE(IsTabletModeStarted());
-  EXPECT_FALSE(AreEventsBlocked());
-
-  SetTabletMode(true);
-  EXPECT_FALSE(IsTabletModeStarted());
-  EXPECT_FALSE(AreEventsBlocked());
-}
-
 // Verify when the force touch view mode flag is turned on, tablet mode is on
 // initially, and opening the lid to less than 180 degress or setting tablet
 // mode to off will not turn off tablet mode.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index f56fd47..9104990 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -54,6 +54,14 @@
   # LockImpl::PriorityInheritanceAvailable() in lock_impl_posix.cc for the
   # platform requirements to safely enable priority inheritance.
   enable_mutex_priority_inheritance = false
+
+  # Determines whether libevent should be dep.
+  dep_libevent = !is_fuchsia && !is_win && !(is_nacl && !is_nacl_nonsfi)
+}
+
+declare_args() {
+  # Determines whether message_pump_libevent should be used.
+  use_libevent = dep_libevent && !is_ios
 }
 
 if (is_android) {
@@ -1409,11 +1417,6 @@
       "//third_party/fuchsia-sdk:svc",
       "//third_party/fuchsia-sdk:zx",
     ]
-  } else {
-    sources += [
-      "message_loop/message_pump_libevent.cc",
-      "message_loop/message_pump_libevent.h",
-    ]
   }
 
   # NaCl.
@@ -1483,8 +1486,6 @@
         "files/file_util_posix.cc",
         "json/json_file_value_serializer.cc",
         "json/json_file_value_serializer.h",
-        "message_loop/message_pump_libevent.cc",
-        "message_loop/message_pump_libevent.h",
         "posix/unix_domain_socket.cc",
         "process/kill_posix.cc",
         "process/launch.cc",
@@ -1557,7 +1558,6 @@
       "file_descriptor_store.h",
       "memory/shared_memory_helper.cc",
       "memory/shared_memory_helper.h",
-      "message_loop/message_pump_libevent.cc",
       "strings/string16.cc",
     ]
 
@@ -1587,9 +1587,6 @@
       ":base_win_linker_flags",
       "//tools/win/DebugVisualizers:chrome",
     ]
-  } else if ((!is_nacl && !is_fuchsia) || is_nacl_nonsfi) {
-    # Non-Windows.
-    deps += [ "//base/third_party/libevent" ]
   }
 
   # Desktop Mac.
@@ -1685,8 +1682,6 @@
       "files/file_path_watcher_kqueue.h",
       "memory/discardable_shared_memory.cc",
       "memory/discardable_shared_memory.h",
-      "message_loop/message_pump_libevent.cc",
-      "message_loop/message_pump_libevent.h",
       "process/kill.cc",
       "process/kill.h",
       "process/kill_posix.cc",
@@ -1747,6 +1742,17 @@
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
+  if (dep_libevent) {
+    deps += [ "//base/third_party/libevent" ]
+  }
+
+  if (use_libevent) {
+    sources += [
+      "message_loop/message_pump_libevent.cc",
+      "message_loop/message_pump_libevent.h",
+    ]
+  }
+
   # Android and MacOS have their own custom shared memory handle
   # implementations. e.g. due to supporting both POSIX and native handles.
   if (is_posix && !is_android && !is_mac) {
@@ -2124,7 +2130,6 @@
     sources = [
       "fuchsia/test.fidl",
     ]
-    namespace = "base"
   }
 }
 
@@ -2597,7 +2602,7 @@
     sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
   }
 
-  if (is_posix && !is_ios) {
+  if (use_libevent) {
     sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
     deps += [ "//base/third_party/libevent" ]
   }
diff --git a/base/message_loop/message_loop_current.cc b/base/message_loop/message_loop_current.cc
index 502b424..0255a770 100644
--- a/base/message_loop/message_loop_current.cc
+++ b/base/message_loop/message_loop_current.cc
@@ -154,7 +154,7 @@
 #endif  // defined(OS_ANDROID)
 }
 
-#if defined(USE_OZONE) && !defined(OS_FUCHSIA)
+#if defined(USE_OZONE) && !defined(OS_FUCHSIA) && !defined(OS_WIN)
 bool MessageLoopCurrentForUI::WatchFileDescriptor(
     int fd,
     bool persistent,
diff --git a/base/message_loop/message_loop_current.h b/base/message_loop/message_loop_current.h
index cf30bae0..2bbad5d 100644
--- a/base/message_loop/message_loop_current.h
+++ b/base/message_loop/message_loop_current.h
@@ -210,7 +210,7 @@
 
   MessageLoopCurrentForUI* operator->() { return this; }
 
-#if defined(USE_OZONE) && !defined(OS_FUCHSIA)
+#if defined(USE_OZONE) && !defined(OS_FUCHSIA) && !defined(OS_WIN)
   // Please see MessagePumpLibevent for definition.
   static_assert(std::is_same<MessagePumpForUI, MessagePumpLibevent>::value,
                 "MessageLoopCurrentForUI::WatchFileDescriptor is not supported "
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
index ff8d2ff..993a222 100644
--- a/base/trace_event/trace_event_etw_export_win.cc
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -69,7 +69,7 @@
     "gpu",                                             // 0x20
     "input",                                           // 0x40
     "netlog",                                          // 0x80
-    "renderer.scheduler",                              // 0x100
+    "sequence_manager",                                // 0x100
     "toplevel",                                        // 0x200
     "v8",                                              // 0x400
     "disabled-by-default-cc.debug",                    // 0x800
diff --git a/build/android/gradle/AndroidManifest.xml b/build/android/gradle/AndroidManifest.xml
new file mode 100644
index 0000000..f3e50e0
--- /dev/null
+++ b/build/android/gradle/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2018 The Chromium Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file.
+-->
+
+<!--
+  This is a dummy manifest which is required by Android Studio's _all target.
+  No <uses-sdk> is allowed due to https://crbug.com/841529.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.dummy">
+</manifest>
diff --git a/build/android/gradle/android.jinja b/build/android/gradle/android.jinja
index 658955d..9a10875 100644
--- a/build/android/gradle/android.jinja
+++ b/build/android/gradle/android.jinja
@@ -78,6 +78,14 @@
 {% endif %}
     }
 
+{% if native is defined %}
+    externalNativeBuild {
+        cmake {
+            path "CMakeLists.txt"
+        }
+    }
+{% endif %}
+
     defaultConfig {
         vectorDrawables.useSupportLibrary = true
     }
diff --git a/build/android/gradle/cmake.jinja b/build/android/gradle/cmake.jinja
new file mode 100644
index 0000000..3b9c19a
--- /dev/null
+++ b/build/android/gradle/cmake.jinja
@@ -0,0 +1,26 @@
+{# Copyright 2018 The Chromium Authors. All rights reserved. #}
+{# Use of this source code is governed by a BSD-style license that can be #}
+{# found in the LICENSE file. #}
+# Generated by //build/android/generate_gradle.py
+
+cmake_minimum_required(VERSION 3.4.1)
+
+project(chrome C CXX)
+
+{% for name, target in native.targets.iteritems() %}
+{% if target.sources is defined %}
+add_library("{{ name }}"
+{% for path in target.sources %}
+    {{ path }}
+{% endfor %}
+)
+{% endif %}
+{% endfor %}
+
+{% if native.includes is defined %}
+include_directories(
+{% for path in native.includes %}
+    {{ path }}
+{% endfor %}
+)
+{% endif %}
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index cb05d60..d8dff95 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -9,6 +9,7 @@
 import codecs
 import collections
 import glob
+import json
 import logging
 import os
 import re
@@ -32,13 +33,15 @@
 import find_depot_tools  # pylint: disable=import-error
 
 _DEFAULT_ANDROID_MANIFEST_PATH = os.path.join(
-    host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'AndroidManifest.xml')
+    host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'gradle',
+    'AndroidManifest.xml')
 _FILE_DIR = os.path.dirname(__file__)
 _SRCJARS_SUBDIR = 'extracted-srcjars'
 _JNI_LIBS_SUBDIR = 'symlinked-libs'
 _ARMEABI_SUBDIR = 'armeabi'
 _RES_SUBDIR = 'extracted-res'
 _GRADLE_BUILD_FILE = 'build.gradle'
+_CMAKE_FILE = 'CMakeLists.txt'
 # This needs to come first alphabetically among all modules.
 _MODULE_ALL = '_all'
 _SRC_INTERNAL = os.path.join(
@@ -110,6 +113,17 @@
     return dict(l.rstrip().split('=', 1) for l in f if '=' in l)
 
 
+def _RunGnGen(output_dir, args):
+  cmd = [
+    os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'gn'),
+    'gen',
+    output_dir,
+  ]
+  cmd.extend(args)
+  logging.info('Running: %r', cmd)
+  subprocess.check_call(cmd)
+
+
 def _RunNinja(output_dir, args, j):
   cmd = [
     os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'ninja'),
@@ -596,8 +610,38 @@
           'testing/' in path)
 
 
-def _GenerateModuleAll(gradle_output_dir, generator, build_vars,
-    source_properties, jinja_processor):
+# Example: //chrome/android:monochrome
+def _GetNative(relative_func, target_names):
+  out_dir = constants.GetOutDirectory()
+  with open(os.path.join(out_dir, 'project.json'), 'r') as project_file:
+    projects = json.load(project_file)
+  project_targets = projects['targets']
+  root_dir = projects['build_settings']['root_path']
+  targets = {}
+  includes = set()
+  def process_paths(paths):
+    # Ignores leading //
+    return relative_func(
+        sorted(os.path.join(root_dir, path[2:]) for path in paths))
+  for target_name in target_names:
+    target = project_targets[target_name]
+    includes.update(target.get('include_dirs', []))
+    sources = target.get('sources', [])
+    if sources:
+      # CMake does not like forward slashes or colons for the target name.
+      filtered_name = target_name.replace('/', '.').replace(':', '-')
+      targets[filtered_name] = {
+          'sources': process_paths(sources),
+      }
+  return {
+      'targets': targets,
+      'includes': process_paths(includes),
+  }
+
+
+def _GenerateModuleAll(
+    gradle_output_dir, generator, build_vars, source_properties,
+    jinja_processor, native_targets):
   """Returns the data for a pseudo build.gradle of all dirs.
 
   See //docs/android_studio.md for more details."""
@@ -623,10 +667,17 @@
       'java_dirs': Relativize(test_java_dirs),
       'java_excludes': ['**/*.java'],
   }]
+  if native_targets:
+    variables['native'] = _GetNative(
+        relative_func=Relativize, target_names=native_targets)
   data = jinja_processor.Render(
       _TemplatePath(target_type.split('_')[0]), variables)
   _WriteFile(
       os.path.join(gradle_output_dir, _MODULE_ALL, _GRADLE_BUILD_FILE), data)
+  if native_targets:
+    cmake_data = jinja_processor.Render(_TemplatePath('cmake'), variables)
+    _WriteFile(
+        os.path.join(gradle_output_dir, _MODULE_ALL, _CMAKE_FILE), cmake_data)
 
 
 def _GenerateRootGradle(jinja_processor, channel):
@@ -752,6 +803,11 @@
   parser.add_argument('-j',
                       default=1000 if os.path.exists(_SRC_INTERNAL) else 50,
                       help='Value for number of parallel jobs for ninja')
+  parser.add_argument('--native-target',
+                      dest='native_targets',
+                      action='append',
+                      help='GN native targets to generate for. May be '
+                           'repeated.')
   version_group = parser.add_mutually_exclusive_group()
   version_group.add_argument('--beta',
                       action='store_true',
@@ -805,11 +861,15 @@
     targets_from_args.update(args.extra_targets)
 
   if args.all:
-    # Run GN gen if necessary (faster than running "gn gen" in the no-op case).
-    _RunNinja(constants.GetOutDirectory(), ['build.ninja'], args.j)
+    if args.native_targets:
+      _RunGnGen(output_dir, ['--ide=json'])
+    else:
+      # Faster than running "gn gen" in the no-op case.
+      _RunNinja(constants.GetOutDirectory(), ['build.ninja'], args.j)
     # Query ninja for all __build_config targets.
     targets = _QueryForAllGnTargets(output_dir)
   else:
+    assert not args.native_targets, 'Native editing requires --all.'
     targets = [re.sub(r'_test_apk$', '_test_apk__apk', t)
                for t in targets_from_args]
 
@@ -866,7 +926,7 @@
     project_entries.append((_MODULE_ALL, _MODULE_ALL))
     _GenerateModuleAll(
         _gradle_output_dir, generator, build_vars, source_properties,
-        jinja_processor)
+        jinja_processor, args.native_targets)
 
   _WriteFile(os.path.join(generator.project_dir, _GRADLE_BUILD_FILE),
              _GenerateRootGradle(jinja_processor, channel))
diff --git a/build/android/gradle/root.jinja b/build/android/gradle/root.jinja
index a3c0db9..d5c5e56 100644
--- a/build/android/gradle/root.jinja
+++ b/build/android/gradle/root.jinja
@@ -5,14 +5,12 @@
 
 buildscript {
     repositories {
+        google()
         jcenter()
-        maven {
-            url 'https://maven.google.com'
-        }
     }
     dependencies {
 {% if channel == 'canary' %}
-        classpath "com.android.tools.build:gradle:3.2.0-alpha04"
+        classpath "com.android.tools.build:gradle:3.2.0-alpha14"
 {% elif channel == 'beta' %}
         classpath "com.android.tools.build:gradle:3.1.0-beta4"
 {% else %}
diff --git a/build/fuchsia/layout_test_proxy/BUILD.gn b/build/fuchsia/layout_test_proxy/BUILD.gn
deleted file mode 100644
index 43ed152..0000000
--- a/build/fuchsia/layout_test_proxy/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-assert(is_fuchsia)
-
-import("//testing/test.gni")
-
-# Binary used to proxy TCP connections from a Fuchsia process. Potentially SSH
-# can be used to forward TCP, but this feature is currently broken on Fuchsia,
-# see ZX-1555. layout_test_proxy can be removed once that issue with sshd is
-# fixed and layout tests are updated to use SSH.
-executable("layout_test_proxy") {
-  testonly = true
-  sources = [
-    "layout_test_proxy.cc",
-  ]
-  deps = [
-    "//net",
-    "//net:test_support",
-  ]
-}
-
-fuchsia_executable_runner("layout_test_proxy_runner") {
-  testonly = true
-  exe_target = ":layout_test_proxy"
-}
diff --git a/build/fuchsia/layout_test_proxy/DEPS b/build/fuchsia/layout_test_proxy/DEPS
deleted file mode 100644
index b2f6f8e..0000000
--- a/build/fuchsia/layout_test_proxy/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+net",
-]
\ No newline at end of file
diff --git a/build/fuchsia/layout_test_proxy/layout_test_proxy.cc b/build/fuchsia/layout_test_proxy/layout_test_proxy.cc
deleted file mode 100644
index 1d14df99..0000000
--- a/build/fuchsia/layout_test_proxy/layout_test_proxy.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "net/base/ip_endpoint.h"
-#include "net/test/tcp_socket_proxy.h"
-
-const char kPortsSwitch[] = "ports";
-const char kRemoteAddressSwitch[] = "remote-address";
-
-int main(int argc, char** argv) {
-  base::CommandLine::Init(argc, argv);
-
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
-  if (!command_line->HasSwitch(kPortsSwitch)) {
-    LOG(ERROR) << "--" << kPortsSwitch << " was not specified.";
-    return 1;
-  }
-
-  std::vector<std::string> ports_strings =
-      base::SplitString(command_line->GetSwitchValueASCII(kPortsSwitch), ",",
-                        base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  if (ports_strings.empty()) {
-    LOG(ERROR) << "At least one port must be specified with --" << kPortsSwitch;
-    return 1;
-  }
-
-  std::vector<int> ports;
-  for (auto& port_string : ports_strings) {
-    int port;
-    if (!base::StringToInt(port_string, &port) || port <= 0 || port > 65535) {
-      LOG(ERROR) << "Invalid value specified for --" << kPortsSwitch << ": "
-                 << port_string;
-      return 1;
-    }
-    ports.push_back(port);
-  }
-
-  if (!command_line->HasSwitch(kRemoteAddressSwitch)) {
-    LOG(ERROR) << "--" << kRemoteAddressSwitch << " was not specified.";
-    return 1;
-  }
-
-  std::string remote_address_str =
-      command_line->GetSwitchValueASCII(kRemoteAddressSwitch);
-  net::IPAddress remote_address;
-  if (!remote_address.AssignFromIPLiteral(remote_address_str)) {
-    LOG(ERROR) << "Invalid value specified for --" << kRemoteAddressSwitch
-               << ": " << remote_address_str;
-    return 1;
-  }
-
-  base::MessageLoopForIO message_loop;
-
-  std::vector<std::unique_ptr<net::TcpSocketProxy>> proxies;
-
-  for (int port : ports) {
-    auto test_server_proxy =
-        std::make_unique<net::TcpSocketProxy>(message_loop.task_runner());
-    if (!test_server_proxy->Initialize(port)) {
-      LOG(ERROR) << "Can't bind proxy to port " << port;
-      return 1;
-    }
-    LOG(INFO) << "Listening on port " << test_server_proxy->local_port();
-    test_server_proxy->Start(net::IPEndPoint(remote_address, port));
-    proxies.push_back(std::move(test_server_proxy));
-  }
-
-  // Run the message loop indefinitely.
-  base::RunLoop().Run();
-
-  return 0;
-}
\ No newline at end of file
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index 5411f6d..c08436a 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-4538a17f3a0240b4fb27b809239f03c6d4184431
\ No newline at end of file
+dcd8c3f6050ecca8c59ff841203587e903c115ea
\ No newline at end of file
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index 380cedc..e5d6c1f 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -49,15 +49,12 @@
   return display_item_list;
 }
 
-class OopPixelTestBase : public testing::Test {
+class OopPixelTest : public testing::Test {
  public:
-  virtual bool UseRasterDecoder() = 0;
-
   void SetUp() override {
     raster_context_provider_ =
         base::MakeRefCounted<TestInProcessContextProvider>(
-            /*enable_oop_rasterization=*/true,
-            /*enable_gles2_interface=*/!UseRasterDecoder());
+            /*enable_oop_rasterization=*/true);
     const int raster_max_texture_size =
         raster_context_provider_->ContextCapabilities().max_texture_size;
     oop_image_cache_.reset(new GpuImageDecodeCache(
@@ -66,8 +63,7 @@
 
     gles2_context_provider_ =
         base::MakeRefCounted<TestInProcessContextProvider>(
-            /*enable_oop_rasterization=*/false,
-            /*enable_gles2_interface=*/true);
+            /*enable_oop_rasterization=*/false);
     const int gles2_max_texture_size =
         raster_context_provider_->ContextCapabilities().max_texture_size;
     gpu_image_cache_.reset(new GpuImageDecodeCache(
@@ -309,18 +305,10 @@
   int color_space_id_ = 0;
 };
 
-class OopPixelTest : public OopPixelTestBase,
-                     public ::testing::WithParamInterface<bool> {
+class OopImagePixelTest : public OopPixelTest,
+                          public ::testing::WithParamInterface<bool> {
  public:
-  bool UseRasterDecoder() final { return GetParam(); }
-};
-
-class OopImagePixelTest
-    : public OopPixelTestBase,
-      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
- public:
-  bool UseRasterDecoder() final { return std::get<0>(GetParam()); }
-  bool UseTooLargeImage() { return std::get<1>(GetParam()); }
+  bool UseTooLargeImage() { return GetParam(); }
   gfx::Size GetImageSize() {
     const int kMaxSize = 20000;
     DCHECK_GT(kMaxSize, gles2_context_provider_->GrContext()->maxTextureSize());
@@ -328,7 +316,7 @@
   }
 };
 
-TEST_P(OopPixelTest, DrawColor) {
+TEST_F(OopPixelTest, DrawColor) {
   gfx::Rect rect(10, 10);
   auto display_item_list = base::MakeRefCounted<DisplayItemList>();
   display_item_list->StartPaint();
@@ -350,7 +338,7 @@
   ExpectEquals(actual_gpu, expected, "gpu");
 }
 
-TEST_P(OopPixelTest, DrawColorWithTargetColorSpace) {
+TEST_F(OopPixelTest, DrawColorWithTargetColorSpace) {
   gfx::Rect rect(10, 10);
   auto display_item_list = base::MakeRefCounted<DisplayItemList>();
   display_item_list->StartPaint();
@@ -371,7 +359,7 @@
   EXPECT_EQ(SkColorSetARGB(255, 38, 15, 221), expected.getColor(0, 0));
 }
 
-TEST_P(OopPixelTest, DrawRect) {
+TEST_F(OopPixelTest, DrawRect) {
   gfx::Rect rect(10, 10);
   auto color_paint = [](int r, int g, int b) {
     PaintFlags flags;
@@ -566,7 +554,7 @@
   ExpectEquals(actual, expected);
 }
 
-TEST_P(OopPixelTest, Preclear) {
+TEST_F(OopPixelTest, Preclear) {
   gfx::Rect rect(10, 10);
   auto display_item_list = base::MakeRefCounted<DisplayItemList>();
   display_item_list->Finalize();
@@ -587,7 +575,7 @@
   ExpectEquals(actual, expected);
 }
 
-TEST_P(OopPixelTest, ClearingOpaqueCorner) {
+TEST_F(OopPixelTest, ClearingOpaqueCorner) {
   // Verify that clears work properly for both the right and bottom sides
   // of an opaque corner tile.
 
@@ -629,7 +617,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingOpaqueCornerExactEdge) {
+TEST_F(OopPixelTest, ClearingOpaqueCornerExactEdge) {
   // Verify that clears work properly for both the right and bottom sides
   // of an opaque corner tile whose content rect exactly lines up with
   // the edge of the resource.
@@ -672,7 +660,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingOpaqueCornerPartialRaster) {
+TEST_F(OopPixelTest, ClearingOpaqueCornerPartialRaster) {
   // Verify that clears do nothing on an opaque corner tile whose
   // partial raster rect doesn't intersect the edge of the content.
 
@@ -709,7 +697,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingOpaqueRightEdge) {
+TEST_F(OopPixelTest, ClearingOpaqueRightEdge) {
   // Verify that a tile that intersects the right edge of content
   // but not the bottom only clears the right pixels.
 
@@ -748,7 +736,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingOpaqueBottomEdge) {
+TEST_F(OopPixelTest, ClearingOpaqueBottomEdge) {
   // Verify that a tile that intersects the bottom edge of content
   // but not the right only clears the bottom pixels.
 
@@ -789,7 +777,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingOpaqueInternal) {
+TEST_F(OopPixelTest, ClearingOpaqueInternal) {
   // Verify that an internal opaque tile does no clearing.
 
   RasterOptions options;
@@ -827,7 +815,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingTransparentCorner) {
+TEST_F(OopPixelTest, ClearingTransparentCorner) {
   RasterOptions options;
   gfx::Point arbitrary_offset(5, 8);
   options.resource_size = gfx::Size(10, 10);
@@ -863,7 +851,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingTransparentInternalTile) {
+TEST_F(OopPixelTest, ClearingTransparentInternalTile) {
   // Content rect much larger than full raster rect or playback rect.
   // This should still clear the tile.
   RasterOptions options;
@@ -900,7 +888,7 @@
   ExpectEquals(gpu_result, bitmap, "gpu");
 }
 
-TEST_P(OopPixelTest, ClearingTransparentCornerPartialRaster) {
+TEST_F(OopPixelTest, ClearingTransparentCornerPartialRaster) {
   RasterOptions options;
   options.resource_size = gfx::Size(10, 10);
   gfx::Point arbitrary_offset(30, 12);
@@ -943,7 +931,7 @@
 // Test various bitmap and playback rects in the raster options, to verify
 // that in process (RasterSource) and out of process (GLES2Implementation)
 // raster behave identically.
-TEST_P(OopPixelTest, DrawRectBasicRasterOptions) {
+TEST_F(OopPixelTest, DrawRectBasicRasterOptions) {
   PaintFlags flags;
   flags.setColor(SkColorSetARGB(255, 250, 10, 20));
   gfx::Rect draw_rect(3, 1, 8, 9);
@@ -976,7 +964,7 @@
   }
 }
 
-TEST_P(OopPixelTest, DrawRectScaleTransformOptions) {
+TEST_F(OopPixelTest, DrawRectScaleTransformOptions) {
   PaintFlags flags;
   // Use powers of two here to make floating point blending consistent.
   flags.setColor(SkColorSetARGB(128, 64, 128, 32));
@@ -1007,7 +995,7 @@
   ExpectEquals(actual, expected);
 }
 
-TEST_P(OopPixelTest, DrawRectQueryMiddleOfDisplayList) {
+TEST_F(OopPixelTest, DrawRectQueryMiddleOfDisplayList) {
   auto display_item_list = base::MakeRefCounted<DisplayItemList>();
   std::vector<SkColor> colors = {
       SkColorSetARGB(255, 0, 0, 255),    SkColorSetARGB(255, 0, 255, 0),
@@ -1040,7 +1028,7 @@
   ExpectEquals(actual, expected);
 }
 
-TEST_P(OopPixelTest, DrawRectColorSpace) {
+TEST_F(OopPixelTest, DrawRectColorSpace) {
   RasterOptions options;
   options.resource_size = gfx::Size(100, 100);
   options.content_size = options.resource_size;
@@ -1085,7 +1073,7 @@
   return builder.TakeTextBlob();
 }
 
-TEST_P(OopPixelTest, DrawTextBlob) {
+TEST_F(OopPixelTest, DrawTextBlob) {
   RasterOptions options;
   options.resource_size = gfx::Size(100, 100);
   options.content_size = options.resource_size;
@@ -1107,12 +1095,7 @@
   ExpectEquals(actual, expected);
 }
 
-INSTANTIATE_TEST_CASE_P(P, OopPixelTest, ::testing::Bool());
-
-INSTANTIATE_TEST_CASE_P(P,
-                        OopImagePixelTest,
-                        ::testing::Combine(::testing::Bool(),
-                                           ::testing::Bool()));
+INSTANTIATE_TEST_CASE_P(P, OopImagePixelTest, ::testing::Bool());
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/paint/transfer_cache_unittest.cc b/cc/paint/transfer_cache_unittest.cc
index 8685b37..d8fb589 100644
--- a/cc/paint/transfer_cache_unittest.cc
+++ b/cc/paint/transfer_cache_unittest.cc
@@ -27,12 +27,10 @@
 namespace cc {
 namespace {
 
-class TransferCacheTest : public testing::TestWithParam<bool> {
+class TransferCacheTest : public testing::Test {
  public:
   TransferCacheTest() : test_client_entry_(std::vector<uint8_t>(100)) {}
 
-  bool UseRasterDecoder() { return GetParam(); }
-
   void SetUp() override {
     gpu::ContextCreationAttribs attribs;
     attribs.alpha_size = -1;
@@ -45,7 +43,7 @@
     // Enable OOP rasterization.
     attribs.enable_oop_rasterization = true;
     attribs.enable_raster_interface = true;
-    attribs.enable_gles2_interface = !UseRasterDecoder();
+    attribs.enable_gles2_interface = false;
 
     context_ = std::make_unique<gpu::RasterInProcessContext>();
     auto result = context_->Initialize(
@@ -91,9 +89,7 @@
   ClientRawMemoryTransferCacheEntry test_client_entry_;
 };
 
-INSTANTIATE_TEST_CASE_P(Service, TransferCacheTest, ::testing::Bool());
-
-TEST_P(TransferCacheTest, Basic) {
+TEST_F(TransferCacheTest, Basic) {
   auto* service_cache = ServiceTransferCache();
   auto* context_support = ContextSupport();
 
@@ -121,7 +117,7 @@
   EXPECT_EQ(nullptr, service_cache->GetEntry(entry.Type(), entry.Id()));
 }
 
-TEST_P(TransferCacheTest, Eviction) {
+TEST_F(TransferCacheTest, Eviction) {
   auto* service_cache = ServiceTransferCache();
   auto* context_support = ContextSupport();
 
@@ -147,7 +143,7 @@
       entry.UnsafeType(), entry.Id()));
 }
 
-TEST_P(TransferCacheTest, RawMemoryTransfer) {
+TEST_F(TransferCacheTest, RawMemoryTransfer) {
   auto* service_cache = ServiceTransferCache();
 
   // Create an entry with some initialized data.
@@ -171,7 +167,7 @@
   EXPECT_EQ(data, service_data);
 }
 
-TEST_P(TransferCacheTest, ImageMemoryTransfer) {
+TEST_F(TransferCacheTest, ImageMemoryTransfer) {
 // TODO(ericrk): This test doesn't work on Android. crbug.com/777628
 #if defined(OS_ANDROID)
   return;
diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc
index 3b0941a..e5340ff6 100644
--- a/cc/raster/raster_buffer_provider_perftest.cc
+++ b/cc/raster/raster_buffer_provider_perftest.cc
@@ -87,7 +87,7 @@
     capabilities_.sync_query = true;
 
     raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>(
-        context_gl_.get(), &support_, nullptr, capabilities_);
+        context_gl_.get(), nullptr, capabilities_);
   }
 
   // viz::ContextProvider implementation.
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 5f94532..1730005 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -46,11 +46,9 @@
   scoped_refptr<TestInProcessContextProvider> worker_context_provider;
   if (test_type_ == PIXEL_TEST_GL) {
     compositor_context_provider = new TestInProcessContextProvider(
-        /*enable_oop_rasterization=*/false,
-        /*supports_gles2_interface=*/true);
+        /*enable_oop_rasterization=*/false);
     worker_context_provider = new TestInProcessContextProvider(
-        /*enable_oop_rasterization=*/false,
-        /*supports_gles2_interface=*/true);
+        /*enable_oop_rasterization=*/false);
   }
   static constexpr bool disable_display_vsync = false;
   bool synchronous_composite =
@@ -80,8 +78,7 @@
     // compositor.
     auto display_context_provider =
         base::MakeRefCounted<TestInProcessContextProvider>(
-            /*enable_oop_rasterization=*/false,
-            /*support_gles2_interface=*/true);
+            /*enable_oop_rasterization=*/false);
     display_context_provider->BindToCurrentThread();
 
     bool flipped_output_surface = false;
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 6dd3be2..dcdfb848 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -194,8 +194,7 @@
   enable_pixel_output_ = std::make_unique<gl::DisableNullDrawGLBindings>();
 
   auto context_provider = base::MakeRefCounted<TestInProcessContextProvider>(
-      /*enable_oop_rasterization=*/false,
-      /*support_gles2_interface=*/true);
+      /*enable_oop_rasterization=*/false);
   output_surface_ = std::make_unique<PixelTestOutputSurface>(
       std::move(context_provider), flipped_output_surface);
   output_surface_->BindToClient(output_surface_client_.get());
@@ -205,8 +204,7 @@
       output_surface_->context_provider(), shared_bitmap_manager_.get());
 
   child_context_provider_ = base::MakeRefCounted<TestInProcessContextProvider>(
-      /*enable_oop_rasterization=*/false,
-      /*support_gles2_interface=*/true);
+      /*enable_oop_rasterization=*/false);
   child_context_provider_->BindToCurrentThread();
   child_resource_provider_ = std::make_unique<LayerTreeResourceProvider>(
       child_context_provider_.get(), true, settings_.resource_settings);
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index f4b8793..c5dfb836d 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -25,7 +25,6 @@
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLInterface.h"
 #include "ui/gfx/native_widget_types.h"
-
 namespace cc {
 
 namespace {
@@ -64,16 +63,13 @@
 }
 
 TestInProcessContextProvider::TestInProcessContextProvider(
-    bool enable_oop_rasterization,
-    bool support_gles2_interface) {
+    bool enable_oop_rasterization) {
   if (enable_oop_rasterization) {
     gpu::ContextCreationAttribs attribs;
     attribs.bind_generates_resource = false;
     attribs.enable_oop_rasterization = true;
     attribs.enable_raster_interface = true;
-    // TODO(crbug.com/834313): Remove this once we start tearing down OOP-R in
-    // GLES2Decoder.
-    attribs.enable_gles2_interface = support_gles2_interface;
+    attribs.enable_gles2_interface = false;
 
     raster_context_.reset(new gpu::RasterInProcessContext);
     auto result = raster_context_->Initialize(
@@ -96,7 +92,6 @@
     raster_implementation_gles2_ =
         std::make_unique<gpu::raster::RasterImplementationGLES>(
             gles2_context_->GetImplementation(),
-            gles2_context_->GetImplementation(),
             gles2_context_->GetImplementation()->command_buffer(),
             gles2_context_->GetCapabilities());
   }
diff --git a/cc/test/test_in_process_context_provider.h b/cc/test/test_in_process_context_provider.h
index 605a2b07..0daece7 100644
--- a/cc/test/test_in_process_context_provider.h
+++ b/cc/test/test_in_process_context_provider.h
@@ -37,10 +37,7 @@
       public viz::ContextProvider,
       public viz::RasterContextProvider {
  public:
-  // TODO(backer): Once we only support OOP-R on Raster{Implementation,Decoder},
-  // fold these two options into one.
-  TestInProcessContextProvider(bool enable_oop_rasterization,
-                               bool support_gles2_interface);
+  explicit TestInProcessContextProvider(bool enable_oop_rasterization);
 
   // viz::ContextProvider / viz::RasterContextProvider implementation.
   void AddRef() const override;
diff --git a/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index f4f4735..b251df56 100644
--- a/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -150,8 +150,7 @@
   background->AddChild(layer);
 
   scoped_refptr<TestInProcessContextProvider> context(
-      new TestInProcessContextProvider(/*enable_oop_rasterization=*/false,
-                                       /*support_gles2_interface=*/true));
+      new TestInProcessContextProvider(/*enable_oop_rasterization=*/false));
   context->BindToCurrentThread();
   int max_texture_size = 0;
   context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 47204ff..1482c16a 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -6326,10 +6326,6 @@
       : will_begin_impl_frame_count_(0), did_finish_impl_frame_count_(0) {}
 
   void BeginTest() override {
-    // Test terminates when a main frame is no longer expected so request that
-    // this message is actually sent.
-    layer_tree_host()->RequestBeginMainFrameNotExpected(true);
-
     PostSetNeedsCommitToMainThread();
   }
 
@@ -6344,27 +6340,20 @@
     did_finish_impl_frame_count_++;
     EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_);
 
-    // Request a number of commits to cause multiple impl frames. We expect to
-    // get one more impl frames than the number of commits requested because
-    // after a commit it takes one frame to become idle.
-    if (did_finish_impl_frame_count_ < kExpectedNumImplFrames - 1)
-      PostSetNeedsCommitToMainThread();
+    // Trigger a new impl frame until we are done testing.
+    if (did_finish_impl_frame_count_ < kExpectedNumImplFrames)
+      PostSetNeedsRedrawToMainThread();
+    else
+      EndTest();
   }
 
-  void BeginMainFrameNotExpectedSoon() override { EndTest(); }
-
   void AfterTest() override {
     EXPECT_GT(will_begin_impl_frame_count_, 0);
     EXPECT_GT(did_finish_impl_frame_count_, 0);
     EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_);
 
-    // TODO(mithro): Figure out why the multithread version of this test
-    // sometimes has one more frame then expected. Possibly related to
-    // http://crbug.com/443185
-    if (!HasImplThread()) {
-      EXPECT_EQ(will_begin_impl_frame_count_, kExpectedNumImplFrames);
-      EXPECT_EQ(did_finish_impl_frame_count_, kExpectedNumImplFrames);
-    }
+    EXPECT_EQ(will_begin_impl_frame_count_, kExpectedNumImplFrames);
+    EXPECT_EQ(did_finish_impl_frame_count_, kExpectedNumImplFrames);
   }
 
  private:
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index edc62a8..fcc9524 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -1049,63 +1049,6 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestCreatesTexture);
 
-class LayerTreeHostCopyRequestTestProvideTexture
-    : public LayerTreeHostCopyRequestTestCountTextures {
- protected:
-  void BeginTest() override {
-    external_context_provider_ = viz::TestContextProvider::Create();
-    EXPECT_EQ(external_context_provider_->BindToCurrentThread(),
-              gpu::ContextResult::kSuccess);
-    LayerTreeHostCopyRequestTestCountTextures::BeginTest();
-  }
-
-  void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) {
-    EXPECT_FALSE(result->IsEmpty());
-    EXPECT_EQ(result->format(), viz::CopyOutputResult::Format::RGBA_TEXTURE);
-    ASSERT_NE(nullptr, result->GetTextureResult());
-
-    std::unique_ptr<viz::SingleReleaseCallback> release_callback =
-        result->TakeTextureOwnership();
-    ASSERT_TRUE(release_callback);
-    release_callback->Run(gpu::SyncToken(), false);
-  }
-
-  void RequestCopy(Layer* layer) override {
-    // Request a copy to a provided texture. This should not create a new
-    // texture.
-    std::unique_ptr<viz::CopyOutputRequest> request =
-        std::make_unique<viz::CopyOutputRequest>(
-            viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE,
-            base::BindOnce(
-                &LayerTreeHostCopyRequestTestProvideTexture::CopyOutputCallback,
-                base::Unretained(this)));
-
-    gpu::gles2::GLES2Interface* gl = external_context_provider_->ContextGL();
-    gpu::Mailbox mailbox;
-    gl->GenMailboxCHROMIUM(mailbox.name);
-
-    gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
-
-    request->SetMailbox(mailbox, sync_token_);
-    EXPECT_TRUE(request->has_mailbox());
-
-    copy_layer_->RequestCopyOfOutput(std::move(request));
-  }
-
-  void AfterTest() override {
-    // Expect the compositor to have waited for the sync point provided with the
-    // mailbox.
-    EXPECT_EQ(sync_token_, waited_sync_token_after_readback_);
-    // Except the copy to have *not* made another texture.
-    EXPECT_EQ(num_textures_without_readback_, num_textures_with_readback_);
-  }
-
-  scoped_refptr<viz::TestContextProvider> external_context_provider_;
-  gpu::SyncToken sync_token_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestProvideTexture);
-
 class LayerTreeHostCopyRequestTestDestroyBeforeCopy
     : public LayerTreeHostCopyRequestTest {
  protected:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index bb8add1c..3ee6cbc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -162,13 +162,7 @@
     public static final String CCT_POST_MESSAGE_API = "CCTPostMessageAPI";
     public static final String CCT_REDIRECT_PRECONNECT = "CCTRedirectPreconnect";
     public static final String CHROME_DUPLEX = "ChromeDuplex";
-    // TODO(mdjones): Remove CHROME_HOME completely.
-    public static final String CHROME_HOME = "ChromeHome";
-    public static final String CHROME_HOME_DROP_ALL_BUT_FIRST_THUMBNAIL =
-            "ChromeHomeDropAllButFirstThumbnail";
-    public static final String CHROME_HOME_PERSISTENT_IPH = "ChromeHomePersistentIph";
-    public static final String CHROME_HOME_PULL_TO_REFRESH_IPH_AT_TOP =
-            "ChromeHomePullToRefreshIphAtTop";
+    // TODO(mdjones): Remove CHROME_HOME_SWIPE_VELOCITY_FEATURE or rename.
     public static final String CHROME_HOME_SWIPE_VELOCITY_FEATURE = "ChromeHomeSwipeLogicVelocity";
     public static final String CHROME_MEMEX = "ChromeMemex";
     public static final String CHROME_MODERN_DESIGN = "ChromeModernDesign";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
index bcd442a..0c8702f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.compositor.TitleCache;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
@@ -414,6 +415,7 @@
             if (mScrollDirection == ScrollDirection.UNKNOWN) return;
 
             if (mOverviewLayout != null && mScrollDirection == ScrollDirection.DOWN) {
+                RecordUserAction.record("MobileToolbarSwipeOpenStackView");
                 startShowing(mOverviewLayout, true);
             } else if (mToolbarSwipeLayout != null
                     && (mScrollDirection == ScrollDirection.LEFT
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
index e2c3edc..fd26014 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -138,4 +139,17 @@
         if (mStacks.size() == 2 && !mStacks.get(1).isDisplayable()) return SWIPE_MODE_SEND_TO_STACK;
         return super.computeInputMode(time, x, y, dx, dy);
     }
+
+    @Override
+    public void setActiveStackState(int stackIndex) {
+        if (stackIndex != getTabStackIndex(Tab.INVALID_TAB_ID)) {
+            if (stackIndex == NORMAL_STACK_INDEX) {
+                RecordUserAction.record("MobileStackViewNormalMode");
+            } else {
+                RecordUserAction.record("MobileStackViewIncognitoMode");
+            }
+        }
+
+        super.setActiveStackState(stackIndex);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
index aa473773..c90c03d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsMediator.java
@@ -28,6 +28,9 @@
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
+import org.chromium.content_public.browser.GestureListenerManager;
+import org.chromium.content_public.browser.GestureStateListener;
+import org.chromium.content_public.browser.RenderCoordinates;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.widget.ViewRectProvider;
 
@@ -41,6 +44,9 @@
  */
 class ContextualSuggestionsMediator
         implements EnabledStateMonitor.Observer, FetchHelper.Delegate, ListMenuButton.Delegate {
+    private static final float INVALID_PERCENTAGE = -1f;
+    private static boolean sOverrideBrowserControlsHiddenForTesting;
+
     private final Profile mProfile;
     private final TabModelSelector mTabModelSelector;
     private final ContextualSuggestionsCoordinator mCoordinator;
@@ -48,6 +54,7 @@
     private final ChromeFullscreenManager mFullscreenManager;
     private final View mIphParentView;
     private final EnabledStateMonitor mEnabledStateMonitor;
+    private final GestureStateListener mGestureStateListener;
     private final Handler mHandler = new Handler();
 
     private @Nullable ContextualSuggestionsSource mSuggestionsSource;
@@ -55,13 +62,16 @@
     private @Nullable String mCurrentRequestUrl;
     private @Nullable BottomSheetObserver mSheetObserver;
     private @Nullable TextBubble mHelpBubble;
+    private @Nullable WebContents mCurrentWebContents;
 
     private boolean mDidSuggestionsShowForTab;
     private boolean mHasRecordedPeekEventForTab;
 
+    private boolean mHasReachedTargetScrollPercentage;
     private boolean mHasPeekDelayPassed;
     private boolean mUpdateRemainingCountOnNextPeek;
     private float mRemainingPeekCount;
+    private float mTargetScrollPercentage = INVALID_PERCENTAGE;
 
     /** Whether the content sheet is observed to be opened for the first time. */
     private boolean mHasSheetBeenOpened;
@@ -92,6 +102,25 @@
                 ContextualSuggestionsDependencyFactory.getInstance().createEnabledStateMonitor(
                         this);
 
+        mGestureStateListener = new GestureStateListener() {
+            @Override
+            public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {
+                if (mHasReachedTargetScrollPercentage) return;
+
+                final RenderCoordinates coordinates =
+                        RenderCoordinates.fromWebContents(mCurrentWebContents);
+                // Use rounded percentage to avoid the approximated percentage not reaching 100%.
+                float percentage = Math.round((float) coordinates.getScrollYPixInt()
+                        / coordinates.getMaxVerticalScrollPixInt() * 100f) / 100f;
+
+                if (Float.compare(mTargetScrollPercentage, INVALID_PERCENTAGE) != 0
+                        && Float.compare(percentage, mTargetScrollPercentage) >= 0) {
+                    mHasReachedTargetScrollPercentage = true;
+                    maybeShowContentInSheet();
+                }
+            }
+        };
+
         fullscreenManager.addListener(new FullscreenListener() {
             @Override
             public void onContentOffsetChanged(float offset) {}
@@ -99,13 +128,7 @@
             @Override
             public void onControlsOffsetChanged(
                     float topOffset, float bottomOffset, boolean needsAnimate) {
-                // When the controls scroll completely off-screen, the suggestions are "shown" but
-                // remain hidden since their offset from the bottom of the screen is determined by
-                // the top controls.
-                if (!mDidSuggestionsShowForTab && mModel.hasSuggestions()
-                        && areBrowserControlsHidden() && mSuggestionsSource != null) {
-                    showContentInSheet();
-                }
+                maybeShowContentInSheet();
             }
 
             @Override
@@ -131,6 +154,12 @@
         }
 
         if (mHelpBubble != null) mHelpBubble.dismiss();
+
+        if (mCurrentWebContents != null) {
+            GestureListenerManager.fromWebContents(mCurrentWebContents)
+                    .removeListener(mGestureStateListener);
+            mCurrentWebContents = null;
+        }
     }
 
     /** Called when accessibility mode changes. */
@@ -142,8 +171,9 @@
      * @return Whether the browser controls are currently completely hidden.
      */
     private boolean areBrowserControlsHidden() {
-        return MathUtils.areFloatsEqual(-mFullscreenManager.getTopControlOffset(),
-                mFullscreenManager.getTopControlsHeight());
+        return sOverrideBrowserControlsHiddenForTesting
+                || MathUtils.areFloatsEqual(-mFullscreenManager.getTopControlOffset(),
+                        mFullscreenManager.getTopControlsHeight());
     }
 
     @Override
@@ -184,7 +214,11 @@
         reportEvent(ContextualSuggestionsEvent.FETCH_REQUESTED);
         mCurrentRequestUrl = url;
         mSuggestionsSource.fetchSuggestions(url, (suggestionsResult) -> {
-            if (mSuggestionsSource == null) return;
+            if (mTabModelSelector.getCurrentTab() == null
+                    || mTabModelSelector.getCurrentTab().getWebContents() == null
+                    || mSuggestionsSource == null) {
+                return;
+            }
             assert mFetchHelper != null;
 
             // Avoiding double fetches causing suggestions for incorrect context.
@@ -194,21 +228,31 @@
 
             PeekConditions peekConditions = suggestionsResult.getPeekConditions();
             mRemainingPeekCount = peekConditions.getMaximumNumberOfPeeks();
+            mTargetScrollPercentage = peekConditions.getPageScrollPercentage();
             long remainingDelay =
                     mFetchHelper.getFetchTimeBaselineMillis(mTabModelSelector.getCurrentTab())
                     + Math.round(peekConditions.getMinimumSecondsOnPage() * 1000)
                     - SystemClock.uptimeMillis();
-            Runnable runnable = () -> mHasPeekDelayPassed = true;
+
+            assert mCurrentWebContents == null
+                : "The current web contents should be cleared before suggestions are requested.";
+            mCurrentWebContents = mTabModelSelector.getCurrentTab().getWebContents();
+            GestureListenerManager.fromWebContents(mCurrentWebContents)
+                    .addListener(mGestureStateListener);
 
             if (remainingDelay <= 0) {
                 // Don't postDelayed if the minimum delay has passed so that the suggestions may
-                // be shown through the following #showContentInSheet() call.
-                runnable.run();
+                // be shown through the following call to show contents in the bottom sheet.
+                mHasPeekDelayPassed = true;
             } else {
-                // Once delay expires, the bottom sheet can be peeked the next time the browser
-                // controls are fully hidden and reshown. Note that this triggering is handled by
+                // Once delay expires, the bottom sheet can be peeked if the browser controls are
+                // already hidden, or the next time the browser controls are fully hidden and
+                // reshown. Note that this triggering on the latter case is handled by
                 // FullscreenListener#onControlsOffsetChanged() in this class.
-                mHandler.postDelayed(runnable, remainingDelay);
+                mHandler.postDelayed(() -> {
+                    mHasPeekDelayPassed = true;
+                    maybeShowContentInSheet();
+                }, remainingDelay);
             }
 
             if (clusters.size() > 0 && clusters.get(0).getSuggestions().size() > 0) {
@@ -216,7 +260,7 @@
                         generateClusterList(clusters), suggestionsResult.getPeekText());
                 // If the controls are already off-screen, show the suggestions immediately so they
                 // are available on reverse scroll.
-                if (areBrowserControlsHidden()) showContentInSheet();
+                maybeShowContentInSheet();
             }
         });
     }
@@ -261,12 +305,23 @@
      */
     private void clearSuggestions() {
         // TODO(twellington): Does this signal need to go back to FetchHelper?
+
+        // Call remove suggestions before clearing model state so that views don't respond to model
+        // changes while suggestions are hiding. See https://crbug.com/840579.
+        if (mSheetObserver != null) {
+            mCoordinator.removeBottomSheetObserver(mSheetObserver);
+            mSheetObserver = null;
+        }
+        mCoordinator.removeSuggestions();
+
         mDidSuggestionsShowForTab = false;
         mHasRecordedPeekEventForTab = false;
         mHasSheetBeenOpened = false;
         mHandler.removeCallbacksAndMessages(null);
+        mHasReachedTargetScrollPercentage = false;
         mHasPeekDelayPassed = false;
         mUpdateRemainingCountOnNextPeek = false;
+        mTargetScrollPercentage = INVALID_PERCENTAGE;
         mRemainingPeekCount = 0f;
         mModel.setClusterList(new ClusterList(Collections.emptyList()));
         mModel.setCloseButtonOnClickListener(null);
@@ -275,16 +330,17 @@
         mModel.setMenuButtonDelegate(null);
         mModel.setDefaultToolbarClickListener(null);
         mModel.setTitle(null);
-        mCoordinator.removeSuggestions();
         mCurrentRequestUrl = "";
 
         if (mSuggestionsSource != null) mSuggestionsSource.clearState();
 
-        if (mSheetObserver != null) {
-            mCoordinator.removeBottomSheetObserver(mSheetObserver);
-        }
-
         if (mHelpBubble != null) mHelpBubble.dismiss();
+
+        if (mCurrentWebContents != null) {
+            GestureListenerManager.fromWebContents(mCurrentWebContents)
+                    .removeListener(mGestureStateListener);
+            mCurrentWebContents = null;
+        }
     }
 
     private void preloadContentInSheet(ClusterList clusters, String title) {
@@ -309,8 +365,15 @@
         mCoordinator.preloadContentInSheet();
     }
 
-    private void showContentInSheet() {
-        if (!mHasPeekDelayPassed || !hasRemainingPeek()) return;
+    private void maybeShowContentInSheet() {
+        // When the controls scroll completely off-screen, the suggestions are "shown" but
+        // remain hidden since their offset from the bottom of the screen is determined by
+        // the top controls.
+        if (mDidSuggestionsShowForTab || !mModel.hasSuggestions() || mSuggestionsSource == null
+                || !areBrowserControlsHidden() || !mHasReachedTargetScrollPercentage
+                || !mHasPeekDelayPassed || !hasRemainingPeek()) {
+            return;
+        }
 
         mDidSuggestionsShowForTab = true;
         mUpdateRemainingCountOnNextPeek = true;
@@ -426,13 +489,24 @@
     }
 
     @VisibleForTesting
-    void showContentInSheetForTesting(boolean disablePeekDelay) {
+    void showContentInSheetForTesting(boolean disableScrollPercentage, boolean disablePeekDelay) {
+        if (disableScrollPercentage) mHasReachedTargetScrollPercentage = true;
         if (disablePeekDelay) mHasPeekDelayPassed = true;
-        showContentInSheet();
+        maybeShowContentInSheet();
     }
 
     @VisibleForTesting
     TextBubble getHelpBubbleForTesting() {
         return mHelpBubble;
     }
+
+    @VisibleForTesting
+    void setTargetScrollPercentageForTesting(float percentage) {
+        mTargetScrollPercentage = percentage;
+    }
+
+    @VisibleForTesting
+    static void setOverrideBrowserControlsHiddenForTesting(boolean override) {
+        sOverrideBrowserControlsHiddenForTesting = override;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java
index 9819928..924cc1b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java
@@ -169,27 +169,35 @@
 
     /**
      * Show the specified dialog. If another dialog is currently showing, the specified dialog will
-     * be added to the pending dialog list.
+     * be added to the end of the pending dialog list of the specified type.
      * @param dialog The dialog to be shown or added to pending list.
      * @param dialogType The type of the dialog to be shown.
      */
     public void showDialog(ModalDialogView dialog, @ModalDialogType int dialogType) {
+        showDialog(dialog, dialogType, false);
+    }
+
+    /**
+     * Show the specified dialog. If another dialog is currently showing, the specified dialog will
+     * be added to the pending dialog list. If showNext is set to true, the dialog will be added
+     * to the top of the pending list of its type, otherwise it will be added to the end.
+     * @param dialog The dialog to be shown or added to pending list.
+     * @param dialogType The type of the dialog to be shown.
+     * @param showAsNext Whether the specified dialog should be set highest priority of its type.
+     */
+    public void showDialog(
+            ModalDialogView dialog, @ModalDialogType int dialogType, boolean showAsNext) {
         List<ModalDialogView> dialogs = mPendingDialogs.get(dialogType);
         if (dialogs == null) mPendingDialogs.put(dialogType, dialogs = new ArrayList<>());
 
-        if (mSuspendedTypes.contains(dialogType)) {
-            dialogs.add(dialog);
+        // Put the new dialog in pending list if the dialog type is suspended or the current dialog
+        // is of higher priority.
+        if (mSuspendedTypes.contains(dialogType) || (isShowing() && mCurrentType <= dialogType)) {
+            dialogs.add(showAsNext ? 0 : dialogs.size(), dialog);
             return;
         }
 
-        if (isShowing()) {
-            // Put the new dialog in pending list if the current dialog is of higher priority.
-            if (mCurrentType <= dialogType) {
-                dialogs.add(dialog);
-                return;
-            }
-            suspendCurrentDialog();
-        }
+        if (isShowing()) suspendCurrentDialog();
 
         assert !isShowing();
         dialog.prepareBeforeShow();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
index f0d824ee..b4a1a6d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -531,9 +531,7 @@
         Resources res = context.getResources();
 
         // Record whether it's known whether notifications can be shown to the user at all.
-        RecordHistogram.recordEnumeratedHistogram("Notifications.AppNotificationStatus",
-                NotificationSystemStatusUtil.determineAppNotificationStatus(context),
-                NotificationSystemStatusUtil.APP_NOTIFICATIONS_STATUS_BOUNDARY);
+        NotificationSystemStatusUtil.recordAppNotificationStatusHistogram(context);
 
         PendingIntent clickIntent = makePendingIntent(context,
                 NotificationConstants.ACTION_CLICK_NOTIFICATION, notificationId, origin, scopeUrl,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtil.java
index 2e7189b..04670ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtil.java
@@ -5,12 +5,11 @@
 package org.chromium.chrome.browser.notifications;
 
 import android.annotation.TargetApi;
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.os.Build;
+import android.support.v4.app.NotificationManagerCompat;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
+import org.chromium.base.metrics.RecordHistogram;
 
 /**
  * Utility for determining whether the user has disabled all of Chrome's notifications using the
@@ -23,65 +22,37 @@
  */
 public class NotificationSystemStatusUtil {
     /** Status codes returned by {@link determineAppNotificationsEnabled}. **/
-    public static final int APP_NOTIFICATIONS_STATUS_UNDETERMINABLE = 0;
-    public static final int APP_NOTIFICATIONS_STATUS_EXCEPTION = 1;
-    public static final int APP_NOTIFICATIONS_STATUS_ENABLED = 2;
-    public static final int APP_NOTIFICATIONS_STATUS_DISABLED = 3;
+    private static final int APP_NOTIFICATIONS_STATUS_UNDETERMINABLE = 0;
+    private static final int APP_NOTIFICATIONS_STATUS_ENABLED = 2;
+    private static final int APP_NOTIFICATIONS_STATUS_DISABLED = 3;
 
     /** Must be set to the maximum value of the above values, plus one. **/
-    public static final int APP_NOTIFICATIONS_STATUS_BOUNDARY = 4;
-
-    /** Method name on the AppOpsManager class to check for a setting's value. **/
-    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
-
-    /** The POST_NOTIFICATION operation understood by the AppOpsManager. **/
-    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
+    private static final int APP_NOTIFICATIONS_STATUS_BOUNDARY = 4;
 
     /**
-     * Determines whether notifications are enabled for the app represented by |context|.
+     * Determines whether notifications are enabled for the app represented by |context| and updates
+     * the histogram "Notifications.AppNotiicationStatus".
      * Notifications may be disabled because either the user, or a management tool, has explicitly
      * disallowed the Chrome App to display notifications.
      *
-     * This check requires Android KitKat or later. Earlier versions will return an INDETERMINABLE
-     * status. When an exception occurs, an EXCEPTION status will be returned instead.
+     * This check requires Android KitKat or later. Earlier versions will log an INDETERMINABLE
+     * status.
      *
      * @param context The context to check of whether it can show notifications.
-     * @return One of the APP_NOTIFICATION_STATUS_* constants defined in this class.
      */
     @TargetApi(Build.VERSION_CODES.KITKAT)
-    static int determineAppNotificationStatus(Context context) {
+    static void recordAppNotificationStatusHistogram(Context context) {
+        int histogramValue;
+
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
-            return APP_NOTIFICATIONS_STATUS_UNDETERMINABLE;
+            histogramValue = APP_NOTIFICATIONS_STATUS_UNDETERMINABLE;
+        } else {
+            NotificationManagerCompat manager = NotificationManagerCompat.from(context);
+            histogramValue = manager.areNotificationsEnabled() ? APP_NOTIFICATIONS_STATUS_ENABLED
+                                                               : APP_NOTIFICATIONS_STATUS_DISABLED;
         }
 
-        final String packageName = context.getPackageName();
-        final int uid = context.getApplicationInfo().uid;
-        final AppOpsManager appOpsManager =
-                (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-
-        try {
-            Class appOpsManagerClass = Class.forName(AppOpsManager.class.getName());
-
-            @SuppressWarnings("unchecked")
-            final Method checkOpNoThrowMethod =
-                    appOpsManagerClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,
-                                                 String.class);
-
-            final Field opPostNotificationField =
-                    appOpsManagerClass.getDeclaredField(OP_POST_NOTIFICATION);
-
-            int value = (int) opPostNotificationField.get(Integer.class);
-            int status = (int) checkOpNoThrowMethod.invoke(appOpsManager, value, uid, packageName);
-
-            return status == AppOpsManager.MODE_ALLOWED
-                    ? APP_NOTIFICATIONS_STATUS_ENABLED : APP_NOTIFICATIONS_STATUS_DISABLED;
-
-        } catch (RuntimeException e) {
-        } catch (Exception e) {
-            // Silently fail here, since this is just collecting statistics. The histogram includes
-            // a count for thrown exceptions, if that proves to be significant we can revisit.
-        }
-
-        return APP_NOTIFICATIONS_STATUS_EXCEPTION;
+        RecordHistogram.recordEnumeratedHistogram("Notifications.AppNotificationStatus",
+                histogramValue, APP_NOTIFICATIONS_STATUS_BOUNDARY);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java
deleted file mode 100644
index 6ed1ad3..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-package org.chromium.chrome.browser.physicalweb;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-
-/**
- * A class that represents an HTTP request for an image.
- * The response is a Bitmap.
- */
-class BitmapHttpRequest extends HttpRequest<Bitmap> {
-    /**
-     * Construct a bitmap HTTP request.
-     * @param url The url to make this HTTP request to.
-     * @param userAgent The string to set as the User-Agent request header.
-     * @param acceptLanguage The string to set as the Accept-Language request header.
-     * @param callback The callback run when the HTTP response is received.
-     *     The callback can be called with a null bitmap if the image
-     *     couldn't be decoded.
-     * @throws MalformedURLException on invalid url
-     */
-    public BitmapHttpRequest(String url, String userAgent, String acceptLanguage,
-            RequestCallback callback)
-            throws MalformedURLException {
-        super(url, userAgent, acceptLanguage, callback);
-    }
-
-    /**
-     * The callback that gets run after the request is made.
-     */
-    public interface RequestCallback extends HttpRequest.HttpRequestCallback<Bitmap> {}
-
-    /**
-     * Helper method to make an HTTP request.
-     * @param urlConnection The HTTP connection.
-     */
-    @Override
-    public void writeToUrlConnection(HttpURLConnection urlConnection) throws IOException {}
-
-    /**
-     * Helper method to read an HTTP response.
-     * @param is The InputStream.
-     * @return The decoded image.
-     */
-    @Override
-    protected Bitmap readInputStream(InputStream is) throws IOException {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        byte[] buffer = new byte[1024];
-        int len;
-        while ((len = is.read(buffer)) != -1) {
-            os.write(buffer, 0, len);
-        }
-        byte[] bitmapData = os.toByteArray();
-        return BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
-    }
-}
-
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/HttpRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/HttpRequest.java
deleted file mode 100644
index c306a70..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/HttpRequest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-package org.chromium.chrome.browser.physicalweb;
-
-import org.chromium.base.ThreadUtils;
-
-import org.chromium.chrome.browser.UrlConstants;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * This class represents an HTTP request.
- * This is to be used as a base class for more specific request classes.
- * @param <T> The type representing the request payload.
- */
-abstract class HttpRequest<T> implements Runnable {
-    // HTTP request header field names
-    private static final String USER_AGENT_HEADER_NAME = "User-Agent";
-    private static final String ACCEPT_LANGUAGE_HEADER_NAME = "Accept-Language";
-
-    private final URL mUrl;
-    private final String mUserAgent;
-    private final String mAcceptLanguage;
-    private final HttpRequestCallback<T> mCallback;
-
-    /**
-     * Construct a Request object.
-     * @param url The URL to make an HTTP request to.
-     * @param userAgent The string to set as the User-Agent request header.
-     * @param acceptLanguage The string to set as the Accept-Language request header.
-     * @param callback The callback run when the HTTP response is received.
-     *     The callback will be run on the main thread.
-     * @throws MalformedURLException on invalid url
-     */
-    public HttpRequest(String url, String userAgent, String acceptLanguage,
-            HttpRequestCallback<T> callback)
-            throws MalformedURLException {
-        mUrl = new URL(url);
-        mUserAgent = userAgent;
-        mAcceptLanguage = acceptLanguage;
-        if (!mUrl.getProtocol().equals(UrlConstants.HTTP_SCHEME)
-                && !mUrl.getProtocol().equals(UrlConstants.HTTPS_SCHEME)) {
-            throw new MalformedURLException("This is not a http or https URL: " + url);
-        }
-        mCallback = callback;
-    }
-
-    /**
-     * The callback that gets run after the request is made.
-     */
-    public interface HttpRequestCallback<T> {
-        /**
-         * The callback run on a valid response.
-         * @param result The result object.
-         */
-        void onResponse(T result);
-
-        /**
-         * The callback run on an Exception.
-         * @param httpResponseCode The HTTP response code.  This will be 0 if no
-         *        response was received.
-         * @param e The encountered Exception.
-         */
-        void onError(int httpResponseCode, Exception e);
-    }
-
-    /**
-     * Make the HTTP request and parse the HTTP response.
-     */
-    @Override
-    public void run() {
-        // Setup some values
-        HttpURLConnection urlConnection = null;
-        T result = null;
-        InputStream inputStream = null;
-        int responseCode = 0;
-        IOException ioException = null;
-
-        // Make the request
-        try {
-            urlConnection = (HttpURLConnection) mUrl.openConnection();
-            urlConnection.setRequestProperty(USER_AGENT_HEADER_NAME, mUserAgent);
-            urlConnection.setRequestProperty(ACCEPT_LANGUAGE_HEADER_NAME, mAcceptLanguage);
-            writeToUrlConnection(urlConnection);
-            responseCode = urlConnection.getResponseCode();
-            inputStream = new BufferedInputStream(urlConnection.getInputStream());
-            result = readInputStream(inputStream);
-        } catch (IOException e) {
-            ioException = e;
-        } finally {
-            if (urlConnection != null) {
-                urlConnection.disconnect();
-            }
-        }
-
-        // Invoke the callback on the main thread.
-        final Exception finalException = ioException;
-        final T finalResult = result;
-        final int finalResponseCode = responseCode;
-        ThreadUtils.postOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (finalException == null) {
-                    mCallback.onResponse(finalResult);
-                } else {
-                    mCallback.onError(finalResponseCode, finalException);
-                }
-            }
-        });
-    }
-
-    /**
-     * Helper method to make an HTTP request.
-     * @param urlConnection The HTTP connection.
-     * @throws IOException on error
-     */
-    protected abstract void writeToUrlConnection(HttpURLConnection urlConnection)
-            throws IOException;
-
-    /**
-     * Helper method to read an HTTP response.
-     * @param is The InputStream.
-     * @return An object representing the HTTP response.
-     * @throws IOException on error
-     */
-    protected abstract T readInputStream(InputStream is) throws IOException;
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java
deleted file mode 100644
index 57997fa..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-package org.chromium.chrome.browser.physicalweb;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.chromium.base.ApiCompatibilityUtils;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-
-/**
- * A class that represents an HTTP request for a JSON object.
- * Both the request payload and the response are JSON objects.
- */
-class JsonObjectHttpRequest extends HttpRequest<JSONObject> {
-    private final JSONObject mJsonObject;
-
-    /**
-     * Construct a JSON object request.
-     * @param url The url to make this HTTP request to.
-     * @param userAgent The string to set as the User-Agent request header.
-     * @param acceptLanguage The string to set as the Accept-Language request header.
-     * @param jsonObject The JSON payload.
-     * @param callback The callback run when the HTTP response is received.
-     * @throws MalformedURLException on invalid url
-     */
-    public JsonObjectHttpRequest(String url, String userAgent, String acceptLanguage,
-            JSONObject jsonObject, RequestCallback callback)
-            throws MalformedURLException {
-        super(url, userAgent, acceptLanguage, callback);
-        mJsonObject = jsonObject;
-    }
-
-    /**
-     * The callback that gets run after the request is made.
-     */
-    public interface RequestCallback extends HttpRequest.HttpRequestCallback<JSONObject> {}
-
-    /**
-     * Helper method to make an HTTP request.
-     * @param urlConnection The HTTP connection.
-     */
-    @Override
-    public void writeToUrlConnection(HttpURLConnection urlConnection) throws IOException {
-        urlConnection.setDoOutput(true);
-        urlConnection.setRequestProperty("Content-Type", "application/json");
-        urlConnection.setRequestProperty("Accept", "application/json");
-        urlConnection.setRequestMethod("POST");
-        OutputStream os = urlConnection.getOutputStream();
-        os.write(ApiCompatibilityUtils.getBytesUtf8(mJsonObject.toString()));
-        os.close();
-    }
-
-    /**
-     * Helper method to read an HTTP response.
-     * @param is The InputStream.
-     * @return An object representing the HTTP response.
-     */
-    @Override
-    protected JSONObject readInputStream(InputStream is) throws IOException {
-        String jsonString = readStreamToString(is);
-        JSONObject jsonObject;
-        try {
-            return new JSONObject(jsonString);
-        } catch (JSONException error) {
-            throw new IOException(error.toString());
-        }
-    }
-
-    private static String readStreamToString(InputStream is) throws IOException {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        byte[] buffer = new byte[1024];
-        int len;
-        while ((len = is.read(buffer)) != -1) {
-            os.write(buffer, 0, len);
-        }
-        return os.toString("UTF-8");
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java
deleted file mode 100644
index d11562d..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import android.graphics.Bitmap;
-
-import java.util.Collection;
-
-/**
- * This class sends requests to the Physical Web Service.
- */
-interface PwsClient {
-    /**
-     * Callback that is run after the PWS sends a response to a resolve-scan request.
-     */
-    interface ResolveScanCallback {
-        /**
-         * Handle newly returned PwsResults.
-         * @param pwsResults The results returned by the PWS.
-         */
-        public void onPwsResults(Collection<PwsResult> pwsResults);
-    }
-
-    /**
-     * Callback that is run after receiving the response to an icon fetch request.
-     */
-    interface FetchIconCallback {
-        /**
-         * Handle newly returned favicon Bitmaps.
-         * @param iconUrl The favicon URL.
-         * @param iconBitmap The icon image data.
-         */
-        public void onIconReceived(String iconUrl, Bitmap iconBitmap);
-    }
-
-    /**
-     * Send an HTTP request to the PWS to resolve a set of URLs.
-     * @param broadcastUrls The URLs to resolve.
-     * @param resolveScanCallback The callback to be run when the response is received.
-     */
-    void resolve(Collection<UrlInfo> broadcastUrls, ResolveScanCallback resolveScanCallback);
-
-    /**
-     * Send an HTTP request to fetch a favicon.
-     * @param iconUrl The URL of the favicon.
-     * @param fetchIconCallback The callback to be run when the icon is received.
-     */
-    void fetchIcon(String iconUrl, FetchIconCallback fetchIconCallback);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java
deleted file mode 100644
index fe2cb02..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java
+++ /dev/null
@@ -1,314 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.text.TextUtils;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.base.LocaleUtils;
-import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.GoogleAPIKeys;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
-import org.chromium.chrome.browser.physicalweb.PwsClient.FetchIconCallback;
-import org.chromium.chrome.browser.physicalweb.PwsClient.ResolveScanCallback;
-
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Formatter;
-import java.util.HashSet;
-import java.util.Locale;
-
-/**
- * This class sends requests to the Physical Web Service.
- */
-class PwsClientImpl implements PwsClient {
-    private static final String TAG = "PhysicalWeb";
-    private static final String ENDPOINT_URL =
-            "https://physicalweb.googleapis.com/v1alpha1/urls:resolve";
-
-    // Format strings for creating the User-Agent string. It should somewhat resemble the Chrome for
-    // Android User-Agent but doesn't need to match perfectly as this value will only be seen by the
-    // Physical Web metadata service and favicon fetcher.
-    // The WebKit version is not accessible from here so it is reported as 0.0.
-    private static final String USER_AGENT_FORMAT =
-            "Mozilla/5.0 (%s) AppleWebKit/0.0 (KHTML, like Gecko) %s Safari/0.0";
-    private static final String OS_INFO_FORMAT = "Linux; Android %s; %s Build/%s";
-    private static final String PRODUCT_FORMAT = "Chrome/%s Mobile";
-
-    // HTTP request header strings, lazily initialized.
-    private static String sUserAgent;
-    private static String sAcceptLanguage;
-
-    // Cached locale string. When the default locale changes, recreate the Accept-Language header.
-    private static String sDefaultLocale;
-
-    public PwsClientImpl() {}
-
-    private String getApiKey() {
-        if (ChromeVersionInfo.isStableBuild()) {
-            return GoogleAPIKeys.GOOGLE_API_KEY;
-        } else {
-            return GoogleAPIKeys.GOOGLE_API_KEY_PHYSICAL_WEB_TEST;
-        }
-    }
-
-    private static JSONObject createResolveScanPayload(Collection<UrlInfo> urls)
-            throws JSONException {
-        // Encode the urls.
-        JSONArray objects = new JSONArray();
-        for (UrlInfo urlInfo : urls) {
-            JSONObject obj = new JSONObject();
-            obj.put("url", urlInfo.getUrl());
-            objects.put(obj);
-        }
-
-        // Organize the data into a single object.
-        JSONObject jsonObject = new JSONObject();
-        jsonObject.put("urls", objects);
-        return jsonObject;
-    }
-
-    private static Collection<PwsResult> parseResolveScanResponse(JSONObject result) {
-        // Get the metadata array.
-        Collection<PwsResult> pwsResults = new ArrayList<>();
-        JSONArray metadata = result.optJSONArray("results");
-        if (metadata == null) {
-            // There are no valid results.
-            return pwsResults;
-        }
-
-        // Loop through the metadata for each url.
-        for (int i = 0; i < metadata.length(); i++) {
-            try {
-                pwsResults.add(PwsResult.jsonDeserialize(metadata.getJSONObject(i)));
-            } catch (JSONException e) {
-                Log.e(TAG, "PWS returned invalid data", e);
-                continue;
-            }
-        }
-        return pwsResults;
-    }
-
-    /**
-     * Send an HTTP request to the PWS to resolve a set of URLs.
-     * @param broadcastUrls The URLs to resolve.
-     * @param resolveScanCallback The callback to be run when the response is received.
-     */
-    @Override
-    public void resolve(final Collection<UrlInfo> broadcastUrls,
-            final ResolveScanCallback resolveScanCallback) {
-        // Create the response callback.
-        JsonObjectHttpRequest.RequestCallback requestCallback =
-                new JsonObjectHttpRequest.RequestCallback() {
-            @Override
-            public void onResponse(JSONObject result) {
-                ThreadUtils.assertOnUiThread();
-                Collection<PwsResult> pwsResults = parseResolveScanResponse(result);
-                resolveScanCallback.onPwsResults(pwsResults);
-            }
-
-            @Override
-            public void onError(int responseCode, Exception e) {
-                ThreadUtils.assertOnUiThread();
-                String httpErr = "";
-                if (responseCode > 0) {
-                    httpErr = ", HTTP " + responseCode;
-                }
-                Log.e(TAG, "Error making request to PWS%s", httpErr);
-                resolveScanCallback.onPwsResults(new ArrayList<PwsResult>());
-            }
-        };
-
-        // Create the request.
-        HttpRequest request = null;
-        try {
-            JSONObject payload = createResolveScanPayload(broadcastUrls);
-            String url = ENDPOINT_URL + "?key=" + getApiKey();
-            request = new JsonObjectHttpRequest(
-                    url, getUserAgent(), updateAcceptLanguage(), payload, requestCallback);
-        } catch (MalformedURLException e) {
-            Log.e(TAG, "Error creating PWS HTTP request", e);
-            return;
-        } catch (JSONException e) {
-            Log.e(TAG, "Error creating PWS JSON payload", e);
-            return;
-        }
-        // The callback will be called on the main thread.
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(request);
-    }
-
-    /**
-     * Send an HTTP request to fetch a favicon.
-     * @param iconUrl The URL of the favicon.
-     * @param fetchIconCallback The callback to be run when the icon is received.
-     */
-    @Override
-    public void fetchIcon(final String iconUrl,
-            final FetchIconCallback fetchIconCallback) {
-        // Create the response callback.
-        BitmapHttpRequest.RequestCallback requestCallback =
-                new BitmapHttpRequest.RequestCallback() {
-            @Override
-            public void onResponse(Bitmap iconBitmap) {
-                fetchIconCallback.onIconReceived(iconUrl, iconBitmap);
-            }
-
-            @Override
-            public void onError(int responseCode, Exception e) {
-                ThreadUtils.assertOnUiThread();
-                String httpErr = "";
-                if (responseCode > 0) {
-                    httpErr = ", HTTP " + responseCode;
-                }
-                Log.e(TAG, "Error requesting icon%s", httpErr);
-            }
-        };
-
-        // Create the request.
-        BitmapHttpRequest request = null;
-        try {
-            request = new BitmapHttpRequest(
-                    iconUrl, getUserAgent(), updateAcceptLanguage(), requestCallback);
-        } catch (MalformedURLException e) {
-            Log.e(TAG, "Error creating icon request", e);
-            return;
-        }
-        // The callback will be called on the main thread.
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(request);
-    }
-
-    /**
-     * Recreate the Chrome for Android User-Agent string as closely as possible without calling any
-     * native code.
-     * @return A User-Agent string
-     */
-    @VisibleForTesting
-    String getUserAgent() {
-        if (sUserAgent == null) {
-            // Build the OS info string.
-            // eg: Linux; Android 5.1.1; Nexus 4 Build/LMY48T
-            String osInfo = String.format(OS_INFO_FORMAT, Build.VERSION.RELEASE, Build.MODEL,
-                    Build.ID);
-
-            // Build the product string.
-            // eg: Chrome/50.0.2661.89 Mobile
-            String product = String.format(PRODUCT_FORMAT, ChromeVersionInfo.getProductVersion());
-
-            // Build the User-Agent string.
-            // eg: Mozilla/5.0 (Linux; Android 5.1.1; Nexus 4 Build/LMY48T) AppleWebKit/0.0 (KHTML,
-            //     like Gecko) Chrome/50.0.2661.89 Mobile Safari/0.0
-            sUserAgent = String.format(USER_AGENT_FORMAT, osInfo, product);
-        }
-        return sUserAgent;
-    }
-
-    /**
-     * Update an Accept-Language string based on the current default locales and make a string of
-     * an Accept-Language header with q-values.
-     * @return An Accept-Language string made of an Accept-Language header with q-values.
-     */
-    @VisibleForTesting
-    String updateAcceptLanguage() {
-        String localeString = LocaleUtils.getDefaultLocaleListString();
-        if (sDefaultLocale == null || !sDefaultLocale.equals(localeString)) {
-            Context context = ContextUtils.getApplicationContext();
-            String acceptLanguages = context.getResources().getString(R.string.accept_languages);
-            acceptLanguages = prependToAcceptLanguagesIfNecessary(localeString, acceptLanguages);
-            sAcceptLanguage = generateAcceptLanguageHeader(acceptLanguages);
-            sDefaultLocale = localeString;
-        }
-        return sAcceptLanguage;
-    }
-
-    /**
-     * Get the language code for the default locales and prepend it to the Accept-Language string
-     * if it isn't already present. The logic should match PrependToAcceptLanguagesIfNecessary in
-     * chrome/browser/android/preferences/pref_service_bridge.cc
-     * @param locales A comma separated string that represents a list of default locales.
-     * @param acceptLanguages The default language list for the language of the user's locales.
-     * @return An updated language list.
-     */
-    @VisibleForTesting
-    static String prependToAcceptLanguagesIfNecessary(String locales, String acceptLanguages) {
-        String localeStrings = locales + "," + acceptLanguages;
-        String[] localeList = localeStrings.split(",");
-
-        ArrayList<Locale> uniqueList = new ArrayList<>();
-        for (String localeString : localeList) {
-            Locale locale = LocaleUtils.forLanguageTag(localeString);
-            if (uniqueList.contains(locale) || locale.getLanguage().isEmpty()) {
-                continue;
-            }
-            uniqueList.add(locale);
-        }
-
-        // If language is not in the accept languages list, also add language code.
-        // A language code should only be inserted after the last languageTag that
-        // contains that language.
-        // This will work with the IDS_ACCEPT_LANGUAGE localized strings bundled
-        // with Chrome but may fail on arbitrary lists of language tags due to
-        // differences in case and whitespace.
-        HashSet<String> seenLanguages = new HashSet<>();
-        ArrayList<String> outputList = new ArrayList<>();
-        for (int i = uniqueList.size() - 1; i >= 0; i--) {
-            Locale localeAdd = uniqueList.get(i);
-            String languageAdd = localeAdd.getLanguage();
-            String countryAdd = localeAdd.getCountry();
-
-            if (!seenLanguages.contains(languageAdd)) {
-                seenLanguages.add(languageAdd);
-                outputList.add(languageAdd);
-            }
-            if (!countryAdd.isEmpty()) {
-                outputList.add(LocaleUtils.toLanguageTag(localeAdd));
-            }
-        }
-        Collections.reverse(outputList);
-        return TextUtils.join(",", outputList);
-    }
-
-    /**
-     * Given a list of comma-delimited language codes in decreasing order of preference, insert
-     * q-values to represent the relative quality/precedence of each language. The logic should
-     * match GenerateAcceptLanguageHeader in net/http/http_util.cc.
-     * @param languageList A comma-delimited list of language codes containing no whitespace.
-     * @return An Accept-Language header with q-values.
-     */
-    @VisibleForTesting
-    static String generateAcceptLanguageHeader(String languageList) {
-        // We use integers for qvalue and qvalue decrement that are 10 times larger than actual
-        // values to avoid a problem with comparing two floating point numbers.
-        int kQvalueDecrement10 = 2;
-        int qvalue10 = 10;
-        String[] parts = languageList.split(",");
-        Formatter langListWithQ = new Formatter();
-        for (String language : parts) {
-            if (qvalue10 == 10) {
-                // q=1.0 is implicit
-                langListWithQ.format("%s", language);
-            } else {
-                langListWithQ.format(",%s;q=0.%d", language, qvalue10);
-            }
-            // It does not make sense to have 'q=0'.
-            if (qvalue10 > kQvalueDecrement10) {
-                qvalue10 -= kQvalueDecrement10;
-            }
-        }
-        return langListWithQ.toString();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java
deleted file mode 100644
index 8db0ade1..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-package org.chromium.chrome.browser.physicalweb;
-
-import org.chromium.base.Log;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * A result from the Physical Web Server.
- *
- * This represents metadata about a URL retrieved from from a PWS response.  It does not
- * necessarily represent one response as a single PWS response may include metadata about multiple
- * URLs.
- */
-class PwsResult {
-    private static final String TAG = "PhysicalWeb";
-    private static final String PAGE_INFO_KEY = "pageInfo";
-    private static final String REQUEST_URL_KEY = "scannedUrl";
-    private static final String SITE_URL_KEY = "resolvedUrl";
-    private static final String ICON_KEY = "icon";
-    private static final String TITLE_KEY = "title";
-    private static final String DESCRIPTION_KEY = "description";
-    private static final String GROUP_ID_KEY = "groupId";
-
-    /**
-     * The URL that was set in the request to the PWS.
-     */
-    public final String requestUrl;
-
-    /**
-     * The destination URL that the requestUrl redirects to.
-     */
-    public final String siteUrl;
-
-    /**
-     * The URL for the destination's favicon.
-     */
-    public final String iconUrl;
-
-    /**
-     * The title of the web page.
-     */
-    public final String title;
-
-    /**
-     * The description of the webpage.
-     */
-    public final String description;
-
-    /**
-     * The group id as determined by the PWS.
-     * This value is useful for associating multiple URLs that refer to similar content in the same
-     * bucket.
-     */
-    public final String groupId;
-
-    /**
-     * Construct a PwsResult.
-     */
-    PwsResult(String requestUrl, String siteUrl, String iconUrl, String title, String description,
-                String groupId) {
-        this.requestUrl = requestUrl;
-        this.siteUrl = siteUrl;
-        this.iconUrl = iconUrl;
-        this.title = title;
-        this.description = description;
-
-        String groupIdToSet = groupId;
-        if (groupId == null) {
-            try {
-                groupIdToSet = new URL(siteUrl).getHost() + title;
-            } catch (MalformedURLException e) {
-                Log.e(TAG, "PwsResult created with a malformed URL", e);
-                groupIdToSet = siteUrl + title;
-            }
-        }
-        this.groupId = groupIdToSet;
-    }
-
-    /**
-     * Creates a JSON object that represents this data structure.
-     * @return a JSON serialization of this data structure.
-     * @throws JSONException if the values cannot be deserialized.
-     */
-    public JSONObject jsonSerialize() throws JSONException {
-        return new JSONObject()
-                .put(REQUEST_URL_KEY, requestUrl)
-                .put(SITE_URL_KEY, siteUrl)
-                .put(PAGE_INFO_KEY, new JSONObject()
-                    .put(ICON_KEY, iconUrl)
-                    .put(TITLE_KEY, title)
-                    .put(DESCRIPTION_KEY, description)
-                    .put(GROUP_ID_KEY, groupId));
-    }
-
-    /**
-     * Populates a PwsResult with data from a given JSON object.
-     * @param jsonObject a serialized PwsResult.
-     * @return The PwsResult represented by the serialized object.
-     * @throws JSONException if the values cannot be serialized.
-     */
-    public static PwsResult jsonDeserialize(JSONObject jsonObject) throws JSONException {
-        JSONObject pageInfo = jsonObject.getJSONObject(PAGE_INFO_KEY);
-        return new PwsResult(
-                jsonObject.getString(REQUEST_URL_KEY),
-                jsonObject.getString(SITE_URL_KEY),
-                pageInfo.optString(ICON_KEY, null),
-                pageInfo.optString(TITLE_KEY, ""),
-                pageInfo.optString(DESCRIPTION_KEY, null),
-                pageInfo.optString(GROUP_ID_KEY, null));
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java
deleted file mode 100644
index a90ab33..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java
+++ /dev/null
@@ -1,148 +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.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.Locale;
-
-/**
- * This class represents a scanned URL and information associated with that URL.
- */
-class UrlInfo {
-    private static final String URL_KEY = "url";
-    private static final String DISTANCE_KEY = "distance";
-    private static final String FIRST_SEEN_TIMESTAMP_KEY = "first_seen_timestamp";
-    private static final String DEVICE_ADDRESS_KEY = "device_address";
-    private static final String HAS_BEEN_DISPLAYED_KEY = "has_been_displayed";
-    private final String mUrl;
-    private final long mFirstSeenTimestamp;
-    private double mDistance;
-    private String mDeviceAddress;
-    private boolean mHasBeenDisplayed;
-
-    public UrlInfo(String url, double distance, long firstSeenTimestamp) {
-        mUrl = url;
-        mDistance = distance;
-        mFirstSeenTimestamp = firstSeenTimestamp;
-        mDeviceAddress = null;
-        mHasBeenDisplayed = false;
-    }
-
-    /**
-     * Constructs a simple UrlInfo with only a URL.
-     */
-    public UrlInfo(String url) {
-        this(url, -1.0, System.currentTimeMillis());
-    }
-
-    /**
-     * Gets the URL represented by this object.
-     * @param The URL.
-     */
-    public String getUrl() {
-        return mUrl;
-    }
-
-    /**
-     * Sets the distance of the URL from the scanner in meters.
-     * @param distance The estimated distance of the URL from the scanner in meters.
-     */
-    public UrlInfo setDistance(double distance) {
-        mDistance = distance;
-        return this;
-    }
-
-    /**
-     * Gets the distance of the URL from the scanner in meters.
-     * @return The estimated distance of the URL from the scanner in meters.
-     */
-    public double getDistance() {
-        return mDistance;
-    }
-
-    /**
-     * Gets the timestamp of when the URL was first scanned.
-     * This timestamp is recorded using System.currentTimeMillis().
-     * @return The first seen timestamp.
-     */
-    public long getFirstSeenTimestamp() {
-        return mFirstSeenTimestamp;
-    }
-
-    /**
-     * Sets the device address for the BLE beacon that last emitted this URL.
-     * @param deviceAddress the new device address, matching the
-     *        BluetoothAdapter.checkBluetoothAddress format.
-     */
-    public UrlInfo setDeviceAddress(String deviceAddress) {
-        mDeviceAddress = deviceAddress;
-        return this;
-    }
-
-    /**
-     * Gets the device address for the BLE beacon that last emitted this URL.
-     * @return The device address.
-     */
-    public String getDeviceAddress() {
-        return mDeviceAddress;
-    }
-
-    /**
-     * Marks this URL as having been displayed to the user.
-     */
-    public UrlInfo setHasBeenDisplayed() {
-        mHasBeenDisplayed = true;
-        return this;
-    }
-
-    /**
-     * Tells if we've displayed this URL.
-     * @return Whether we've displayed this URL.
-     */
-    public boolean hasBeenDisplayed() {
-        return mHasBeenDisplayed;
-    }
-
-    /**
-     * Creates a JSON object that represents this data structure.
-     * @return a JSON serialization of this data structure.
-     * @throws JSONException if the values cannot be deserialized.
-     */
-    public JSONObject jsonSerialize() throws JSONException {
-        return new JSONObject()
-                .put(URL_KEY, mUrl)
-                .put(DISTANCE_KEY, mDistance)
-                .put(FIRST_SEEN_TIMESTAMP_KEY, mFirstSeenTimestamp)
-                .put(DEVICE_ADDRESS_KEY, mDeviceAddress)
-                .put(HAS_BEEN_DISPLAYED_KEY, mHasBeenDisplayed);
-    }
-
-    /**
-     * Populates a UrlInfo with data from a given JSON object.
-     * @param jsonObject a serialized UrlInfo.
-     * @return The UrlInfo represented by the serialized object.
-     * @throws JSONException if the values cannot be serialized.
-     */
-    public static UrlInfo jsonDeserialize(JSONObject jsonObject) throws JSONException {
-        UrlInfo urlInfo = new UrlInfo(jsonObject.getString(URL_KEY),
-                jsonObject.getDouble(DISTANCE_KEY), jsonObject.getLong(FIRST_SEEN_TIMESTAMP_KEY))
-                                  .setDeviceAddress(jsonObject.optString(DEVICE_ADDRESS_KEY));
-        if (jsonObject.optBoolean(HAS_BEEN_DISPLAYED_KEY, false)) {
-            urlInfo.setHasBeenDisplayed();
-        }
-        return urlInfo;
-    }
-
-    /**
-     * Represents the UrlInfo as a String.
-     */
-    @Override
-    public String toString() {
-        return String.format(Locale.getDefault(), "%s %f %d %b", mUrl, mDistance,
-                mFirstSeenTimestamp, mHasBeenDisplayed);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
index a0587d3..f2f97f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
@@ -13,6 +13,9 @@
 import org.chromium.chrome.browser.preferences.autofill.AutofillAndPaymentsPreferences;
 import org.chromium.chrome.browser.preferences.password.SavePasswordsPreferences;
 import org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataTabsFragment;
+import org.chromium.content_public.browser.WebContents;
+
+import java.lang.ref.WeakReference;
 
 /**
  * A utility class for launching Chrome Settings.
@@ -62,8 +65,11 @@
     }
 
     @CalledByNative
-    private static void showAutofillSettings() {
-        launchSettingsPage(ContextUtils.getApplicationContext(),
+    private static void showAutofillSettings(WebContents webContents) {
+        WeakReference<Activity> currentActivity =
+                webContents.getTopLevelNativeWindow().getActivity();
+
+        launchSettingsPage(currentActivity.get(),
                 AutofillAndPaymentsPreferences.class.getName());
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
index d449844..f597db9b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SiteSection.java
@@ -10,14 +10,12 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.cards.ItemViewType;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
 import org.chromium.chrome.browser.ntp.cards.NodeVisitor;
 import org.chromium.chrome.browser.ntp.cards.OptionalLeaf;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
 
 /**
@@ -30,16 +28,6 @@
      */
     private static final int MAX_TILE_COLUMNS = 4;
 
-    /**
-     * Experiment parameter for the maximum number of tile suggestion rows to show.
-     */
-    private static final String PARAM_CHROME_HOME_MAX_TILE_ROWS = "chrome_home_max_tile_rows";
-
-    /**
-     * Experiment parameter for the number of tile title lines to show.
-     */
-    private static final String PARAM_CHROME_HOME_TILE_TITLE_LINES = "chrome_home_tile_title_lines";
-
     private final TileGroup mTileGroup;
     private final TileRenderer mTileRenderer;
 
@@ -110,17 +98,11 @@
     }
 
     private static int getMaxTileRows() {
-        int defaultValue = 2;
-        if (!FeatureUtilities.isChromeHomeEnabled()) return defaultValue;
-        return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
-                ChromeFeatureList.CHROME_HOME, PARAM_CHROME_HOME_MAX_TILE_ROWS, defaultValue);
+        return 2;
     }
 
     private static int getTileTitleLines() {
-        int defaultValue = 1;
-        if (!FeatureUtilities.isChromeHomeEnabled()) return defaultValue;
-        return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
-                ChromeFeatureList.CHROME_HOME, PARAM_CHROME_HOME_TILE_TITLE_LINES, defaultValue);
+        return 1;
     }
 
     @LayoutRes
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java
index 1ab1579..4260f906 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java
@@ -63,6 +63,7 @@
     TabBrowserControlsOffsetHelper(Tab tab) {
         mTab = tab;
         VrShellDelegate.registerVrModeObserver(this);
+        if (VrShellDelegate.isInVr()) onEnterVr();
     }
 
     /**
@@ -258,7 +259,11 @@
     @Override
     public void onExitVr() {
         mIsInVr = false;
+        // Call resetPositions() to clear the VR-specific overrides for controls height.
         resetPositions();
+        // Show the Controls explicitly because under some situations, like when we're showing a
+        // Native Page, the renderer won't send any new offsets.
+        showAndroidControls(false);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentUtils.java
index d99f165..bd6d093 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrIntentUtils.java
@@ -155,6 +155,7 @@
      * @return Options that a VR-specific Chrome activity should be launched with.
      */
     public static Bundle getVrIntentOptions(Context context) {
+        if (!VrShellDelegate.isVrEnabled()) return null;
         // These options are used to start the Activity with a custom animation to keep it hidden
         // for a few hundred milliseconds - enough time for us to draw the first black view.
         // The animation is sufficient to hide the 2D screenshot but not to the 2D UI while the
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 71e6063..71f2252 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -788,6 +788,8 @@
      */
     public static VrClassesWrapper getVrClassesWrapper() {
         if (sVrClassesWrapper == null) sVrClassesWrapper = createVrClassesWrapper();
+        // Disable VR on standalone VR devices (https://crbug.com/841850).
+        if (sVrClassesWrapper != null && sVrClassesWrapper.bootsToVr()) return null;
         return sVrClassesWrapper;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 3058f71..1741830 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -577,7 +577,14 @@
     public void onWindowFocusChanged(boolean focused) {
         // This handles the case where we open 2D popups in 2D-in-VR. We lose window focus, but stay
         // resumed, so we have to listen for focus gain to know when the popup was closed.
-        if (focused) VrShellDelegate.setVrModeEnabled(mActivity, true);
+        // This also handles the case where we're launched via intent and turn VR mode on with
+        // a popup open. We'll lose window focus when the popup 'gets shown' and know to turn VR
+        // mode off.
+        // TODO(asimjour): Focus is a bad signal. We should listen for windows being created and
+        // destroyed if possible.
+        if (VrShellDelegate.getVrClassesWrapper().bootsToVr()) {
+            VrShellDelegate.setVrModeEnabled(mActivity, focused);
+        }
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 00163757..0151197 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -1160,7 +1160,7 @@
         float offsetWithBrowserControls = getCurrentOffsetPx() - getOffsetFromBrowserControls();
 
         // Do not send events for states less than the hidden state unless 0 has not been sent.
-        if (offsetWithBrowserControls < getSheetHeightForState(SHEET_STATE_HIDDEN)
+        if (offsetWithBrowserControls <= getSheetHeightForState(SHEET_STATE_HIDDEN)
                 && mLastOffsetRatioSent <= 0) {
             return;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
index 42dde8c..d02f41a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -173,6 +173,7 @@
 
             @Override
             public void onTransitionPeekToHalf(float transitionFraction) {
+                if (!mBottomSheet.isSheetOpen()) return;
                 fadingBackgroundView.setViewAlpha(transitionFraction);
             }
 
@@ -395,7 +396,7 @@
         // TODO(mdjones): Replace usages of bottom sheet with a model in line with MVC.
         // TODO(mdjones): It would probably be useful to expose an observer method that notifies
         //                objects when all content requests are cleared.
-        hideContent(mBottomSheet.getCurrentSheetContent(), true);
+        hideContent(mBottomSheet.getCurrentSheetContent(), false);
         mWasShownForCurrentTab = false;
         mIsSuppressed = false;
     }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 0764133..60dcc68 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -939,7 +939,6 @@
   "java/src/org/chromium/chrome/browser/permissions/PermissionDialogDelegate.java",
   "java/src/org/chromium/chrome/browser/permissions/PermissionDialogView.java",
   "java/src/org/chromium/chrome/browser/permissions/PermissionUmaUtil.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java",
   "java/src/org/chromium/chrome/browser/photo_picker/BitmapScalerTask.java",
   "java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java",
   "java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java",
@@ -953,14 +952,8 @@
   "java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapView.java",
   "java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java",
   "java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/HttpRequest.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/JsonObjectHttpRequest.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java",
   "java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java",
-  "java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java",
   "java/src/org/chromium/chrome/browser/physicalweb/Utils.java",
   "java/src/org/chromium/chrome/browser/policy/PolicyAuditor.java",
   "java/src/org/chromium/chrome/browser/preferences/AboutChromePreferences.java",
@@ -1751,7 +1744,6 @@
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java",
-  "javatests/src/org/chromium/chrome/browser/physicalweb/MockPwsClient.java",
   "javatests/src/org/chromium/chrome/browser/policy/CombinedPolicyProviderTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java",
@@ -2068,9 +2060,6 @@
   "junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java",
   "junit/src/org/chromium/chrome/browser/payments/AutofillContactUnitTest.java",
   "junit/src/org/chromium/chrome/browser/payments/PaymentManifestVerifierTest.java",
-  "junit/src/org/chromium/chrome/browser/physicalweb/PwsClientImplTest.java",
-  "junit/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java",
-  "junit/src/org/chromium/chrome/browser/physicalweb/UrlInfoTest.java",
   "junit/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManagerTest.java",
   "junit/src/org/chromium/chrome/browser/preferences/password/DialogManagerTest.java",
   "junit/src/org/chromium/chrome/browser/preferences/password/EnsureAsyncPostingRule.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FeaturesAnnotationsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FeaturesAnnotationsTest.java
index 1134fd13..fc3fe7c9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FeaturesAnnotationsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FeaturesAnnotationsTest.java
@@ -9,7 +9,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.core.IsCollectionContaining.hasItems;
-import static org.junit.Assert.assertFalse;
 
 import android.support.test.filters.SmallTest;
 
@@ -20,15 +19,13 @@
 
 import org.chromium.base.CommandLine;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.browser.ChromeHome;
+import org.chromium.chrome.test.util.browser.ChromeModernDesign;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
-import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.Arrays;
 import java.util.List;
@@ -40,7 +37,7 @@
 @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE)
 public class FeaturesAnnotationsTest {
     @Rule
-    public TestRule mChromeHomeProcessor = new ChromeHome.Processor();
+    public TestRule mChromeHomeProcessor = new ChromeModernDesign.Processor();
 
     @Rule
     public TestRule mFeaturesProcessor = new Features.InstrumentationProcessor();
@@ -69,21 +66,22 @@
     }
 
     /**
-     * Tests the compatibility between {@link EnableFeatures} and other rules. {@link ChromeHome}
-     * here explicitly calls {@link Features#enable(String...)}, so its feature should also be added
-     * to the set of registered flags.
+     * Tests the compatibility between {@link EnableFeatures} and other rules.
+     * {@link @ChromeModernDesign} here explicitly calls {@link Features#enable(String...)}, so
+     * its feature should also be added to the set of registered flags.
      */
-    @DisabledTest(message = "https://crbug.com/805160")
     @Test
     @SmallTest
-    @ChromeHome.Enable
+    @ChromeModernDesign.Enable
     @EnableFeatures("One")
     public void testFeaturesIncludeValuesSetFromOtherRules() throws InterruptedException {
         mActivityRule.startMainActivityOnBlankPage();
 
         List<String> finalEnabledList = getArgsList(true);
-        assertThat(finalEnabledList, hasItems("One", ChromeFeatureList.CHROME_HOME));
-        assertTrue(ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME));
+        assertThat(finalEnabledList, hasItems("One", ChromeFeatureList.CHROME_MODERN_DESIGN));
+        assertTrue(ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_MODERN_DESIGN));
+        assertTrue("ChromeModernDesign should be enabled.",
+                FeatureUtilities.isChromeModernDesignEnabled());
     }
 
     /**
@@ -123,15 +121,6 @@
         assertThat(finalEnabledList.size(), equalTo(4));
     }
 
-    @DisabledTest(message = "https://crbug.com/805160")
-    @Test
-    @SmallTest
-    @ChromeHome.Enable
-    public void testChromeHomeSkipping() {
-        assertFalse("The test should only run on phones.", DeviceFormFactor.isTablet());
-        assertTrue("ChromeHome should be enabled.", FeatureUtilities.isChromeHomeEnabled());
-    }
-
     private static List<String> getArgsList(boolean enabled) {
         String switchName = enabled ? "enable-features" : "disable-features";
         return Arrays.asList(CommandLine.getInstance().getSwitchValue(switchName).split(","));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
index a7ba337..3ff7b03 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsTest.java
@@ -63,7 +63,10 @@
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.TestWebContentsObserver;
+import org.chromium.content_public.browser.GestureListenerManager;
+import org.chromium.content_public.browser.GestureStateListener;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.ui.test.util.UiRestriction;
 
@@ -118,6 +121,7 @@
         mFakeSource = new FakeContextualSuggestionsSource();
         mContextualSuggestionsDeps.getFactory().suggestionsSource = mFakeSource;
         FetchHelper.setDisableDelayForTesting(true);
+        ContextualSuggestionsMediator.setOverrideBrowserControlsHiddenForTesting(true);
 
         FakeEnabledStateMonitor stateMonitor = new FakeEnabledStateMonitor();
         mContextualSuggestionsDeps.getFactory().enabledStateMonitor = new FakeEnabledStateMonitor();
@@ -147,6 +151,7 @@
     public void tearDown() {
         mTestServer.stopAndDestroyServer();
         FetchHelper.setDisableDelayForTesting(false);
+        ContextualSuggestionsMediator.setOverrideBrowserControlsHiddenForTesting(false);
     }
 
     @Test
@@ -171,7 +176,7 @@
         assertEquals("RecyclerView should be empty.", 0, recyclerView.getChildCount());
 
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            mMediator.showContentInSheetForTesting(true);
+            mMediator.showContentInSheetForTesting(true, true);
             mBottomSheet.endAnimations();
         });
 
@@ -190,6 +195,8 @@
     @MediumTest
     @Feature({"ContextualSuggestions"})
     public void testScrollPageToTrigger() throws InterruptedException, TimeoutException {
+        ContextualSuggestionsMediator.setOverrideBrowserControlsHiddenForTesting(false);
+        mMediator.setTargetScrollPercentageForTesting(0f);
         assertEquals("Sheet should be hidden.", BottomSheet.SHEET_STATE_HIDDEN,
                 mBottomSheet.getSheetState());
 
@@ -427,7 +434,7 @@
                 mModel2.getClusterList().getItemCount());
 
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            mMediator2.showContentInSheetForTesting(true);
+            mMediator2.showContentInSheetForTesting(true, true);
             mBottomSheet2.endAnimations();
 
             ContextualSuggestionsBottomSheetContent content1 =
@@ -538,6 +545,53 @@
     @Test
     @MediumTest
     @Feature({"ContextualSuggestions"})
+    public void testPeekWithPageScrollPercentage() throws Exception {
+        CallbackHelper scrollChangedCallback = new CallbackHelper();
+        GestureStateListener gestureStateListener = new GestureStateListener() {
+            @Override
+            public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {
+                scrollChangedCallback.notifyCalled();
+            }
+        };
+        WebContents webContents = mActivityTestRule.getWebContents();
+        GestureListenerManager.fromWebContents(webContents).addListener(gestureStateListener);
+        View view = webContents.getViewAndroidDelegate().getContainerView();
+
+        // Verify that suggestions are not shown before scroll.
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> mMediator.showContentInSheetForTesting(false, true));
+        assertEquals("Bottom sheet should be hidden before scroll.", BottomSheet.SHEET_STATE_HIDDEN,
+                mBottomSheet.getSheetState());
+
+        // Scroll the page to 30% and verify that the suggestions are not shown. The pixel to scroll
+        // is hard coded (approximately) based on the html height of the TEST_PAGE.
+        int callCount = scrollChangedCallback.getCallCount();
+        ThreadUtils.runOnUiThreadBlocking(() -> view.scrollBy(0, 3000));
+        scrollChangedCallback.waitForCallback(callCount);
+
+        // Simulate call to show content without browser controls being hidden.
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> mMediator.showContentInSheetForTesting(false, true));
+        assertEquals("Bottom sheet should be hidden on 30% scroll percentage.",
+                BottomSheet.SHEET_STATE_HIDDEN, mBottomSheet.getSheetState());
+
+        // Scroll the page to approximately 60% and verify that the suggestions are shown.
+        callCount = scrollChangedCallback.getCallCount();
+        ThreadUtils.runOnUiThreadBlocking(() -> view.scrollBy(0, 3000));
+        scrollChangedCallback.waitForCallback(callCount);
+
+        // Simulate call to show content without browser controls being hidden.
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> mMediator.showContentInSheetForTesting(false, true));
+        assertEquals("Bottom sheet should be shown on >=50% scroll percentage.",
+                BottomSheet.SHEET_STATE_PEEK, mBottomSheet.getSheetState());
+
+        GestureListenerManager.fromWebContents(webContents).removeListener(gestureStateListener);
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"ContextualSuggestions"})
     public void testPeekDelay() throws Exception {
         // Close the suggestions from setUp().
         ThreadUtils.runOnUiThreadBlocking(() -> {
@@ -550,12 +604,12 @@
         FetchHelper.setFetchTimeBaselineMillisForTesting(startTime);
         ThreadUtils.runOnUiThreadBlocking(
                 () -> mMediator.requestSuggestions("http://www.testurl.com"));
-        assertTrue("Bottom sheet should be hidden before delay.",
-                mBottomSheet.getSheetState() == BottomSheet.SHEET_STATE_HIDDEN);
+        assertEquals("Bottom sheet should be hidden before delay.", BottomSheet.SHEET_STATE_HIDDEN,
+                mBottomSheet.getSheetState());
 
         // Simulate user scroll by calling showContentInSheet until the sheet is peeked.
         CriteriaHelper.pollUiThread(() -> {
-            mMediator.showContentInSheetForTesting(false);
+            mMediator.showContentInSheetForTesting(true, false);
             mBottomSheet.endAnimations();
             return mBottomSheet.getSheetState() == BottomSheet.SHEET_STATE_PEEK;
         });
@@ -606,7 +660,7 @@
                 mModel.getClusterList().getItemCount());
 
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            mMediator.showContentInSheetForTesting(true);
+            mMediator.showContentInSheetForTesting(true, true);
             mBottomSheet.endAnimations();
 
             assertEquals("Sheet should be peeked.", BottomSheet.SHEET_STATE_PEEK,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeContextualSuggestionsSource.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeContextualSuggestionsSource.java
index 70519ba9..a23ca58 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeContextualSuggestionsSource.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextual_suggestions/FakeContextualSuggestionsSource.java
@@ -28,6 +28,7 @@
     final static String TEST_TOOLBAR_TITLE = "More about capybaras";
     // There should be 6 items in the cluster list - 5 articles and one cluster title.
     final static Integer TOTAL_ITEM_COUNT = 6;
+    final static float TEST_PEEK_TARGET_PERCENTAGE = .5f;
     final static int TEST_PEEK_COUNT = 3;
     final static int TEST_PEEK_DELAY_SECONDS = 2;
 
@@ -135,7 +136,8 @@
         cluster2.getSuggestions().add(article5);
 
         ContextualSuggestionsResult result = new ContextualSuggestionsResult(TEST_TOOLBAR_TITLE);
-        result.setPeekConditions(new PeekConditions(0f, TEST_PEEK_DELAY_SECONDS, TEST_PEEK_COUNT));
+        result.setPeekConditions(new PeekConditions(
+                TEST_PEEK_TARGET_PERCENTAGE, TEST_PEEK_DELAY_SECONDS, TEST_PEEK_COUNT));
         result.getClusters().add(cluster1);
         result.getClusters().add(cluster2);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java
index 4ddbc673..c253860 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java
@@ -258,13 +258,13 @@
         checkBrowserControls(false);
         checkCurrentPresenter(null);
 
-        // Insert a tab modal dialog and two app modal dialogs for showing.
+        // Insert two tab modal dialogs and two app modal dialogs for showing.
         showDialog(0, ModalDialogManager.TAB_MODAL);
         showDialog(1, ModalDialogManager.TAB_MODAL);
         showDialog(2, ModalDialogManager.APP_MODAL);
         showDialog(3, ModalDialogManager.APP_MODAL);
 
-        // The first inserted app modal dialog show be shown.
+        // The first inserted app modal dialog is shown.
         checkPendingSize(ModalDialogManager.APP_MODAL, 1);
         checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
         onView(withText("2")).check(matches(isDisplayed()));
@@ -304,6 +304,59 @@
 
     @Test
     @SmallTest
+    public void testShow_ShowDialogAsNext() throws Exception {
+        // Initially there are no dialogs in the pending list. Browser controls are not restricted.
+        checkPendingSize(ModalDialogManager.APP_MODAL, 0);
+        checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
+        checkBrowserControls(false);
+        checkCurrentPresenter(null);
+
+        // Insert a tab modal dialog and a app modal dialog for showing.
+        showDialog(0, ModalDialogManager.TAB_MODAL);
+        showDialog(1, ModalDialogManager.TAB_MODAL);
+        showDialog(2, ModalDialogManager.APP_MODAL);
+
+        // The first inserted app modal dialog is shown.
+        checkPendingSize(ModalDialogManager.APP_MODAL, 0);
+        checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
+        onView(withText("2")).check(matches(isDisplayed()));
+        onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
+        checkCurrentPresenter(ModalDialogManager.APP_MODAL);
+
+        // Show a tab modal dialog as the next dialog to be shown. Verify that the app modal dialog
+        // is still showing.
+        showDialogAsNext(3, ModalDialogManager.TAB_MODAL);
+        checkPendingSize(ModalDialogManager.APP_MODAL, 0);
+        checkPendingSize(ModalDialogManager.TAB_MODAL, 3);
+        onView(withText("2")).check(matches(isDisplayed()));
+        onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
+        checkCurrentPresenter(ModalDialogManager.APP_MODAL);
+
+        // Dismiss the dialog by clicking OK. The third tab modal dialog should be shown.
+        onView(withText(R.string.ok)).perform(click());
+        checkPendingSize(ModalDialogManager.APP_MODAL, 0);
+        checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
+        onView(withId(R.id.tab_modal_dialog_container))
+                .check(matches(allOf(hasDescendant(withText("3")),
+                        not(hasDescendant(withText("0"))), not(hasDescendant(withText("1"))),
+                        not(hasDescendant(withText("2"))))));
+        checkBrowserControls(true);
+        checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
+
+        // Dismiss the dialog by clicking OK. The first tab modal dialog should be shown.
+        onView(withText(R.string.ok)).perform(click());
+        checkPendingSize(ModalDialogManager.APP_MODAL, 0);
+        checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
+        onView(withId(R.id.tab_modal_dialog_container))
+                .check(matches(allOf(hasDescendant(withText("0")),
+                        not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))),
+                        not(hasDescendant(withText("3"))))));
+        checkBrowserControls(true);
+        checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
+    }
+
+    @Test
+    @SmallTest
     @DisabledTest(message = "crbug.com/812066")
     public void testShow_UrlBarFocused() throws Exception {
         // Show a dialog. The dialog should be shown on top of the toolbar.
@@ -658,12 +711,17 @@
     private void showDialog(
             final int index, final @ModalDialogManager.ModalDialogType int dialogType) {
         ThreadUtils.runOnUiThreadBlocking(
-                () -> { mManager.showDialog(mModalDialogViews[index], dialogType); });
+                () -> mManager.showDialog(mModalDialogViews[index], dialogType));
+    }
+
+    private void showDialogAsNext(
+            final int index, final @ModalDialogManager.ModalDialogType int dialogType) {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> mManager.showDialog(mModalDialogViews[index], dialogType, true));
     }
 
     private void dismissDialog(final int index) {
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> { mManager.dismissDialog(mModalDialogViews[index]); });
+        ThreadUtils.runOnUiThreadBlocking(() -> mManager.dismissDialog(mModalDialogViews[index]));
     }
 
     private void checkPendingSize(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
index 10f8e59..53d9bc41 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
@@ -729,6 +729,9 @@
         assertThat(actionTester.toString(), getNotificationActions(actionTester),
                 Matchers.contains(
                         "Notifications.Persistent.Shown", "Notifications.Persistent.Clicked"));
+        Assert.assertEquals(1,
+                RecordHistogram.getHistogramTotalCountForTesting(
+                        "Notifications.AppNotificationStatus"));
     }
 
     /**
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index 697eeff3..e1a8b75 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -81,7 +81,6 @@
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
-import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.CategoryInfoBuilder;
 import org.chromium.chrome.test.util.browser.suggestions.FakeSuggestionsSource;
 import org.chromium.components.signin.AccountManagerFacade;
@@ -103,10 +102,9 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE, shadows = {CustomShadowAsyncTask.class})
 
-@DisableFeatures({ChromeFeatureList.CHROME_HOME,
-    ChromeFeatureList.CONTENT_SUGGESTIONS_SCROLL_TO_LOAD,
-    ChromeFeatureList.NTP_ARTICLE_SUGGESTIONS_EXPANDABLE_HEADER,
-    ChromeFeatureList.SIMPLIFIED_NTP, ChromeFeatureList.CHROME_DUPLEX})
+@DisableFeatures({ChromeFeatureList.CONTENT_SUGGESTIONS_SCROLL_TO_LOAD,
+        ChromeFeatureList.NTP_ARTICLE_SUGGESTIONS_EXPANDABLE_HEADER,
+        ChromeFeatureList.SIMPLIFIED_NTP, ChromeFeatureList.CHROME_DUPLEX})
 
 public class NewTabPageAdapterTest {
     @Rule
@@ -1016,10 +1014,9 @@
         assertEquals(0, preferenceManager.getNewTabPageSigninPromoSuppressionPeriodStart());
     }
 
-    @Ignore // Disabled for new Chrome Home, see: https://crbug.com/805160
+    @Ignore // Disabled for new Chrome Home, see: https://crbug.com/805160, re-enable for Modern
     @Test
     @Feature({"Ntp"})
-    @EnableFeatures(ChromeFeatureList.CHROME_HOME)
     public void testSigninPromoModern() {
         when(mMockSigninManager.isSignInAllowed()).thenReturn(true);
         when(mMockSigninManager.isSignedInOnNative()).thenReturn(false);
@@ -1176,10 +1173,9 @@
                 mAdapter.getFirstPositionForType(ItemViewType.ALL_DISMISSED));
     }
 
-    @Ignore // Disabled for new Chrome Home, see: https://crbug.com/805160
+    @Ignore // Disabled for new Chrome Home, see: https://crbug.com/805160, re-enable for Modern
     @Test
     @Feature({"Ntp"})
-    @EnableFeatures(ChromeFeatureList.CHROME_HOME)
     public void testAllDismissedModern() {
         when(mUiDelegate.isVisible()).thenReturn(true);
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/PwsClientImplTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/PwsClientImplTest.java
deleted file mode 100644
index de1a965..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/PwsClientImplTest.java
+++ /dev/null
@@ -1,193 +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.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-import android.text.TextUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowResources;
-
-import org.chromium.base.LocaleUtils;
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.R;
-
-import java.util.Locale;
-
-/**
- * Tests for {@link PwsClientImpl}.
- */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class PwsClientImplTest {
-    private static final String ACCEPT_LANGUAGES = "en-US,en";
-    PwsClientImpl mPwsClientImpl;
-
-    /**
-     * Robolectric shadow to mock out calls to {@link Resources#getString}.
-     */
-    @Implements(Resources.class)
-    public static class AcceptLanguageShadowResources extends ShadowResources {
-        public static final Resources sResources = mock(Resources.class);
-
-        @Implementation
-        public CharSequence getText(int id) {
-            return sResources.getText(id);
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        mPwsClientImpl = new PwsClientImpl();
-    }
-
-    @Test
-    public void testUserAgentNonEmpty() {
-        assertFalse(TextUtils.isEmpty(mPwsClientImpl.getUserAgent()));
-    }
-
-    @Test
-    @Config(shadows = AcceptLanguageShadowResources.class)
-    public void testLanguageTagIsIncludedInAcceptLanguageHeader() {
-        when(AcceptLanguageShadowResources.sResources.getText(R.string.accept_languages))
-                .thenReturn(ACCEPT_LANGUAGES);
-        String defaultLocaleString = LocaleUtils.getDefaultLocaleString();
-        String[] languageTags = defaultLocaleString.split(",");
-
-        // Ensure Accept-Language contains the full language tag.
-        String acceptLanguage = mPwsClientImpl.updateAcceptLanguage();
-        for (String tag : languageTags) {
-            assertTrue(acceptLanguage.contains(tag));
-            // Ensure Accept-Language also contains the language code by itself.
-            String languageCode;
-            if (tag.length() == 2 || tag.length() == 3) {
-                languageCode = tag;
-            } else if (tag.charAt(2) == '-') {
-                languageCode = tag.substring(0, 2);
-            } else { // length of the language code is 3.
-                languageCode = tag.substring(0, 3);
-            }
-            assertTrue(acceptLanguage.startsWith(languageCode + ",")
-                    || acceptLanguage.contains(languageCode + ";")
-                    || acceptLanguage.equals(languageCode));
-        }
-    }
-
-    @Test
-    public void testLanguageTagIsPrepended() {
-        Locale locale = new Locale("en", "GB");
-        String defaultLocale = LocaleUtils.toLanguageTag(locale);
-        String languageList = "fr-CA,fr-FR,fr";
-
-        // Should prepend the language tag "en-GB" as well as the language code "en".
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(defaultLocale, languageList);
-        assertEquals("en-GB,en,fr-CA,fr-FR,fr", languageListWithTag);
-    }
-
-    @Test
-    public void testLanguageOnlyTagIsPrepended() {
-        Locale locale = new Locale("mas");
-        String defaultLocale = LocaleUtils.toLanguageTag(locale);
-        String languageList = "fr-CA,fr-FR,fr";
-
-        // Should prepend the language code only language tag "aaa".
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(defaultLocale, languageList);
-        assertEquals("mas,fr-CA,fr-FR,fr", languageListWithTag);
-    }
-
-    @Test
-    public void testSpecialLengthCountryCodeIsPrepended() {
-        Locale locale = new Locale("es", "005");
-        String defaultLocale = LocaleUtils.toLanguageTag(locale);
-        String languageList = "fr-CA,fr-FR,fr";
-
-        // Should prepend the language tag "aa-AAA" as well as the language code "aa".
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(defaultLocale, languageList);
-        assertEquals("es-005,es,fr-CA,fr-FR,fr", languageListWithTag);
-    }
-
-    @Test
-    public void testMultipleLanguageTagIsPrepended() {
-        String locale = "jp-JP,is-IS";
-        String languageList = "en-US,en";
-
-        // Should prepend the language tag "aa-AA" as well as the language code "aa".
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(locale, languageList);
-        assertEquals("jp-JP,jp,is-IS,is,en-US,en", languageListWithTag);
-
-        // Make sure the language code is only inserted after the last languageTag that
-        // contains that language.
-        locale = "jp-JP,fr-CA,fr-FR";
-        languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(locale, languageList);
-        assertEquals("jp-JP,jp,fr-CA,fr-FR,fr,en-US,en", languageListWithTag);
-    }
-
-    @Test
-    public void testLanguageTagIsPrependedWhenListContainsLanguageCode() {
-        Locale locale = new Locale("fr", "FR");
-        String defaultLocale = LocaleUtils.toLanguageTag(locale);
-        String languageList = "fr-CA,fr";
-
-        // Should prepend the language tag "xx-XX" but not the language code "xx" as it's already
-        // included at the end of the list.
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(defaultLocale, languageList);
-        assertEquals("fr-FR,fr-CA,fr", languageListWithTag);
-    }
-
-    @Test
-    public void testLanguageTagNotPrependedWhenUnnecessary() {
-        Locale locale = new Locale("fr", "CA");
-        String defaultLocale = LocaleUtils.toLanguageTag(locale);
-        String languageList = "fr-CA,fr-FR,fr";
-
-        // Language list should be unmodified since the tag is already present.
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(defaultLocale, languageList);
-        assertEquals(languageList, languageListWithTag);
-    }
-
-    @Test
-    public void testMultiLanguageTagNotPrependedWhenUnnecessary() {
-        String locale = "fr-FR,is-IS";
-        String languageList = "fr-FR,is-IS,fr,is";
-
-        // Language list should be unmodified since the tag is already present. However, the order
-        // changes because a language-code-only language tag is acceptable now.
-        String languageListWithTag =
-                PwsClientImpl.prependToAcceptLanguagesIfNecessary(locale, languageList);
-        assertEquals(languageList, languageListWithTag);
-    }
-
-    @Test
-    public void testAcceptLanguageQvalues() {
-        String languageList = "en-US,en-GB,en,jp-JP,jp";
-
-        // Should insert q-values for each item except the first which implicitly has q=1.0.
-        String acceptLanguage = PwsClientImpl.generateAcceptLanguageHeader(languageList);
-        assertEquals("en-US,en-GB;q=0.8,en;q=0.6,jp-JP;q=0.4,jp;q=0.2", acceptLanguage);
-
-        // When there are six or more items, the q-value should not go below 0.2.
-        languageList = "mas,es,en,jp,ch,fr";
-        acceptLanguage = PwsClientImpl.generateAcceptLanguageHeader(languageList);
-        assertEquals("mas,es;q=0.8,en;q=0.6,jp;q=0.4,ch;q=0.2,fr;q=0.2", acceptLanguage);
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java
deleted file mode 100644
index 93b9215..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import static org.junit.Assert.assertEquals;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
-
-/**
- * Tests for {@link PwsResult}.
- */
-@RunWith(BlockJUnit4ClassRunner.class)
-public class PwsResultTest {
-    PwsResult mReferencePwsResult = null;
-    JSONObject mReferenceJsonObject = null;
-
-    @Before
-    public void setUp() throws Exception {
-        mReferencePwsResult = new PwsResult("https://shorturl.com", "https://longurl.com",
-                "https://longurl.com/favicon.ico", "This is a page", "Pages are the best",
-                "group1");
-        // Because we can't print JSON sorted by keys, the order is important here.
-        mReferenceJsonObject = new JSONObject("{"
-                + "    \"scannedUrl\": \"https://shorturl.com\","
-                + "    \"resolvedUrl\": \"https://longurl.com\","
-                + "    \"pageInfo\": {"
-                + "        \"icon\": \"https://longurl.com/favicon.ico\","
-                + "        \"title\": \"This is a page\","
-                + "        \"description\": \"Pages are the best\","
-                + "        \"groupId\": \"group1\""
-                + "    }"
-                + "}");
-    }
-
-    @Test
-    public void testJsonSerializeWorks() throws JSONException {
-        assertEquals(
-                mReferenceJsonObject.toString(), mReferencePwsResult.jsonSerialize().toString());
-    }
-
-    @Test
-    public void testJsonDeserializeWorks() throws JSONException {
-        PwsResult pwsResult = PwsResult.jsonDeserialize(mReferenceJsonObject);
-        assertEquals(mReferencePwsResult.requestUrl, pwsResult.requestUrl);
-        assertEquals(mReferencePwsResult.siteUrl, pwsResult.siteUrl);
-        assertEquals(mReferencePwsResult.iconUrl, pwsResult.iconUrl);
-        assertEquals(mReferencePwsResult.title, pwsResult.title);
-        assertEquals(mReferencePwsResult.description, pwsResult.description);
-        assertEquals(mReferencePwsResult.groupId, pwsResult.groupId);
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/UrlInfoTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/UrlInfoTest.java
deleted file mode 100644
index e49ae56..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/physicalweb/UrlInfoTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.physicalweb;
-
-import static org.junit.Assert.assertEquals;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
-
-/**
- * Tests for {@link UrlInfo}.
- */
-@RunWith(BlockJUnit4ClassRunner.class)
-public class UrlInfoTest {
-    private static final String URL = "https://example.com";
-    private static final double EPSILON = .001;
-    UrlInfo mReferenceUrlInfo = null;
-    JSONObject mReferenceJsonObject = null;
-
-    @Before
-    public void setUp() throws JSONException {
-        mReferenceUrlInfo = new UrlInfo(URL, 99.5, 42)
-                .setHasBeenDisplayed()
-                .setDeviceAddress("00:11:22:33:AA:BB");
-        // Because we can't print JSON sorted by keys, the order is important here.
-        mReferenceJsonObject = new JSONObject("{"
-                + "    \"url\": \"" + URL + "\","
-                + "    \"distance\": 99.5,"
-                + "    \"first_seen_timestamp\": 42,"
-                + "    \"device_address\": \"00:11:22:33:AA:BB\","
-                + "    \"has_been_displayed\": true"
-                + "}");
-    }
-
-    @Test
-    public void testJsonSerializeWorks() throws JSONException {
-        assertEquals(mReferenceJsonObject.toString(), mReferenceUrlInfo.jsonSerialize().toString());
-    }
-
-    @Test
-    public void testJsonDeserializeWorks() throws JSONException {
-        UrlInfo urlInfo = UrlInfo.jsonDeserialize(mReferenceJsonObject);
-        assertEquals(mReferenceUrlInfo.getUrl(), urlInfo.getUrl());
-        assertEquals(mReferenceUrlInfo.getDistance(), urlInfo.getDistance(), EPSILON);
-        assertEquals(mReferenceUrlInfo.getFirstSeenTimestamp(), urlInfo.getFirstSeenTimestamp());
-        assertEquals(mReferenceUrlInfo.getDeviceAddress(), urlInfo.getDeviceAddress());
-        assertEquals(mReferenceUrlInfo.hasBeenDisplayed(), urlInfo.hasBeenDisplayed());
-    }
-}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0eeacab..cac10a78 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2226,16 +2226,13 @@
         Pop-ups were blocked on this page.
       </message>
       <message name="IDS_BLOCKED_POPUPS_TITLE" desc="Bubble title when a page is not allowed to display popups.">
-        Pop-ups blocked
+        Pop-ups blocked:
       </message>
-      <message name="IDS_BLOCKED_POPUPS_MESSAGE" desc="Bubble info header text when a page is not allowed to display popups.  This appears above a list of popup titles.">
-        The following pop-ups were blocked on this page:
+      <message name="IDS_BLOCKED_POPUPS_REDIRECTS_UNBLOCK" desc="Radio button choice to unblock a site from showing popups and redirects, displayed in bubble when a page tries to display popups or redirects.">
+        Always allow pop-ups and redirects from <ph name="HOST">$1<ex>mail.google.com</ex></ph>
       </message>
-      <message name="IDS_BLOCKED_POPUPS_UNBLOCK" desc="Radio button choice to unblock a site from showing popups, displayed in bubble when a page tries to display popups.">
-        Always allow pop-ups from <ph name="HOST">$1<ex>mail.google.com</ex></ph>
-      </message>
-      <message name="IDS_BLOCKED_POPUPS_NO_ACTION" desc="Radio button choice to continue blocking a site from showing popups, displayed in bubble when a page tries to display popups.">
-        Continue blocking pop-ups
+      <message name="IDS_BLOCKED_POPUPS_REDIRECTS_NO_ACTION" desc="Radio button choice to continue blocking a site from showing popups and redirects, displayed in bubble when a page tries to display popups or redirects.">
+        Continue blocking
       </message>
       <message name="IDS_BLOCKED_POPUPS_LINK" desc="Link to popups section of content blocking management dialog, displayed in bubble when a page tries to display popups.">
         Manage pop-up blocking...
@@ -5508,18 +5505,6 @@
       <message name="IDS_MEDIA_MENU_NO_DEVICE_TITLE" desc="The title of the media select menu if there is no microphone or camera available on the machine">
         None available
       </message>
-      <message name="IDS_POPUP_TAB_LABEL" desc="Label for Pop-up Windows tab on Content Settings dialog">
-        Pop-ups
-      </message>
-      <message name="IDS_POPUP_HEADER" desc="Header for popup exception management page on Content Settings dialog">
-        Pop-up exceptions
-      </message>
-      <message name="IDS_POPUP_ALLOW_RADIO" desc="A radio button in the Content Settings dialog for allowing pop-up windows in the browser.">
-        Allow all sites to show pop-ups
-      </message>
-      <message name="IDS_POPUP_BLOCK_RADIO" desc="A radio button in the Content Settings dialog for preventing showing pop-up windows on any sites.">
-        Do not allow any site to show pop-ups (recommended)
-      </message>
       <if expr="is_android">
         <message name="IDS_POPUPS_BLOCKED_INFOBAR_BUTTON_SHOW" desc="Pop-up Blocking Show Button [CHAR-LIMIT=32]">
           Always show
@@ -10488,7 +10473,7 @@
     <if expr="not is_android">
       <!-- Android strings are declared in android_chrome_strings.grd. -->
       <message name="IDS_REDIRECT_BLOCKED_MESSAGE" desc="The message stating that a redirect (noun) was blocked on this page. This will be followed on a separate line with the address the user was being redirected to.">
-        Redirect blocked to site
+        Redirect blocked:
       </message>
       <if expr="use_titlecase">
         <message name="IDS_REDIRECT_BLOCKED_GOT_IT" desc="In Title Case: The text of the OK button for the blocked redirect dialog.">
diff --git a/chrome/app/nibs/ContentBlockedPopups.xib b/chrome/app/nibs/ContentBlockedPopups.xib
index 4a1b0b0..b243b33 100644
--- a/chrome/app/nibs/ContentBlockedPopups.xib
+++ b/chrome/app/nibs/ContentBlockedPopups.xib
@@ -87,11 +87,11 @@
                                 </buttonCell>
                                 <cells>
                                     <column>
-                                        <buttonCell type="radio" title="^IDS_BLOCKED_POPUPS_UNBLOCK" imagePosition="left" alignment="left" controlSize="small" tag="1" inset="2" id="10">
+                                        <buttonCell type="radio" title="^IDS_BLOCKED_POPUPS_REDIRECTS_UNBLOCK" imagePosition="left" alignment="left" controlSize="small" tag="1" inset="2" id="10">
                                             <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                         </buttonCell>
-                                        <buttonCell type="radio" title="^IDS_BLOCKED_POPUPS_NO_ACTION" imagePosition="left" alignment="left" controlSize="small" state="on" tag="2" inset="2" id="11">
+                                        <buttonCell type="radio" title="^IDS_BLOCKED_POPUPS_REDIRECTS_NO_ACTION" imagePosition="left" alignment="left" controlSize="small" state="on" tag="2" inset="2" id="11">
                                             <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                         </buttonCell>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 4999301..85eb15a 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2637,8 +2637,8 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_PDF_DOWNLOAD_PDFS" desc="Label for downloading PDF documents instead of automatically opening them in Chrome.">
     Download PDF files instead of automatically opening them in Chrome
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_POPUPS" desc="Label for the popups site settings.">
-    Popups
+  <message name="IDS_SETTINGS_SITE_SETTINGS_POPUPS" desc="Label for the pop-ups and redirects site settings.">
+    Pop-ups and redirects
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT" desc="Label for the protected content site settings.">
     Protected content
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 80b379e..0b6c312 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2637,6 +2637,8 @@
       "resource_coordinator/discard_metrics_lifecycle_unit_observer.cc",
       "resource_coordinator/discard_metrics_lifecycle_unit_observer.h",
       "resource_coordinator/discard_reason.h",
+      "resource_coordinator/leveldb_site_characteristics_database.cc",
+      "resource_coordinator/leveldb_site_characteristics_database.h",
       "resource_coordinator/lifecycle_unit.cc",
       "resource_coordinator/lifecycle_unit.h",
       "resource_coordinator/lifecycle_unit_base.cc",
@@ -2655,9 +2657,15 @@
       "resource_coordinator/local_site_characteristics_data_store.h",
       "resource_coordinator/local_site_characteristics_data_writer.cc",
       "resource_coordinator/local_site_characteristics_data_writer.h",
+      "resource_coordinator/local_site_characteristics_database.h",
       "resource_coordinator/local_site_characteristics_feature_usage.h",
+      "resource_coordinator/local_site_characteristics_non_recording_data_store.cc",
+      "resource_coordinator/local_site_characteristics_non_recording_data_store.h",
+      "resource_coordinator/local_site_characteristics_noop_data_writer.cc",
+      "resource_coordinator/local_site_characteristics_noop_data_writer.h",
       "resource_coordinator/site_characteristics_data_reader.h",
       "resource_coordinator/site_characteristics_data_store.h",
+      "resource_coordinator/site_characteristics_data_writer.h",
       "resource_coordinator/tab_activity_watcher.cc",
       "resource_coordinator/tab_activity_watcher.h",
       "resource_coordinator/tab_features.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2375e9f..3411b7a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1871,29 +1871,12 @@
     {"enable-chrome-duplex", flag_descriptions::kChromeDuplexName,
      flag_descriptions::kChromeDuplexDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kChromeDuplexFeature)},
-    {"enable-chrome-home-bottom-sheet-inactivity-expansion",
-     flag_descriptions::kChromeHomeInactivitySheetExpansionName,
-     flag_descriptions::kChromeHomeInactivitySheetExpansionDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kChromeHomeInactivitySheetExpansion)},
     {"chrome-home-swipe-logic", flag_descriptions::kChromeHomeSwipeLogicName,
      flag_descriptions::kChromeHomeSwipeLogicDescription, kOsAndroid,
      MULTI_VALUE_TYPE(kChromeHomeSwipeLogicChoices)},
-    {"enable-chrome-home-persistent-iph",
-     flag_descriptions::kChromeHomePersistentIphName,
-     flag_descriptions::kChromeHomePersistentIphDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kChromeHomePersistentIph)},
-    {"enable-chrome-home-pull-to-refresh-iph-at-top",
-     flag_descriptions::kChromeHomePullToRefreshIphAtTopName,
-     flag_descriptions::kChromeHomePullToRefreshIphAtTopDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kChromeHomePullToRefreshIphAtTop)},
     {"enable-chrome-memex", flag_descriptions::kChromeMemexName,
      flag_descriptions::kChromeMemexDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kChromeMemexFeature)},
-    {"enable-chrome-home-survey",
-     flag_descriptions::kChromeHomeEnableSurveyName,
-     flag_descriptions::kChromeHomeEnableSurveyDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kChromeHomeSurvey)},
     {"enable-chrome-modern-design", flag_descriptions::kChromeModernDesignName,
      flag_descriptions::kChromeModernDesignDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kChromeModernDesign)},
@@ -2237,6 +2220,9 @@
     {"vr-browsing-in-custom-tab", flag_descriptions::kVrBrowsingInCustomTabName,
      flag_descriptions::kVrBrowsingInCustomTabDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kVrBrowsingInCustomTab)},
+    {"vr-browsing-tabs-view", flag_descriptions::kVrBrowsingTabsViewName,
+     flag_descriptions::kVrBrowsingTabsViewDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kVrBrowsingTabsView)},
     {"vr-icon-in-daydream-home", flag_descriptions::kVrIconInDaydreamHomeName,
      flag_descriptions::kVrIconInDaydreamHomeDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kVrIconInDaydreamHome)},
@@ -2926,7 +2912,7 @@
          kEnableAutofillCreditCardUploadGooglePayOnAndroidBrandingDescription,
      kOsAndroid,
      FEATURE_VALUE_TYPE(
-         autofill::features::kAutofillUpstreamUseGooglePayOnAndroidBranding)},
+         autofill::features::kAutofillUpstreamUseGooglePayBrandingOnMobile)},
     {"enable-autofill-credit-card-upload-send-detected-values",
      flag_descriptions::kEnableAutofillCreditCardUploadSendDetectedValuesName,
      flag_descriptions::
@@ -3573,11 +3559,6 @@
      flag_descriptions::kAshEnablePersistentWindowBoundsName,
      flag_descriptions::kAshEnablePersistentWindowBoundsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kPersistentWindowBounds)},
-
-    {"ash-enable-mode-specific-power-button",
-     flag_descriptions::kAshEnableModeSpecificPowerButtonName,
-     flag_descriptions::kAshEnableModeSpecificPowerButtonDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kModeSpecificPowerButton)},
 #endif  // OS_CHROMEOS
 
     {"clipboard-content-setting",
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index a14b35a..5c15f6621 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -70,9 +70,6 @@
     &kCCTPostMessageAPI,
     &kCCTRedirectPreconnect,
     &kChromeDuplexFeature,
-    &kChromeHomeInactivitySheetExpansion,
-    &kChromeHomePersistentIph,
-    &kChromeHomePullToRefreshIphAtTop,
     &kChromeHomeSwipeLogic,
     &kChromeHomeSwipeLogicVelocity,
     &kChromeSmartSelection,
@@ -200,18 +197,6 @@
 const base::Feature kChromeDuplexFeature{"ChromeDuplex",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kChromeHomeInactivitySheetExpansion{
-    "ChromeHomeInactivitySheetExpansion", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kChromeHomePersistentIph{"ChromeHomePersistentIph",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kChromeHomePullToRefreshIphAtTop{
-    "ChromeHomePullToRefreshIphAtTop", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kChromeHomeSurvey{"ChromeHomeSurvey",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kChromeHomeSwipeLogic{"ChromeHomeSwipeLogic",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -386,6 +371,9 @@
 const base::Feature kVrBrowsingNativeAndroidUi{
     "VrBrowsingNativeAndroidUi", base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kVrBrowsingTabsView{"VrBrowsingTabsView",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kVrIconInDaydreamHome{"VrIconInDaydreamHome",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index b24bba6e..1c101234 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -23,10 +23,6 @@
 extern const base::Feature kCCTPostMessageAPI;
 extern const base::Feature kCCTRedirectPreconnect;
 extern const base::Feature kChromeDuplexFeature;
-extern const base::Feature kChromeHomeInactivitySheetExpansion;
-extern const base::Feature kChromeHomePersistentIph;
-extern const base::Feature kChromeHomePullToRefreshIphAtTop;
-extern const base::Feature kChromeHomeSurvey;
 extern const base::Feature kChromeHomeSwipeLogic;
 extern const base::Feature kChromeHomeSwipeLogicVelocity;
 extern const base::Feature kChromeMemexFeature;
@@ -83,6 +79,7 @@
 extern const base::Feature kVrBrowsingFeedback;
 extern const base::Feature kVrBrowsingInCustomTab;
 extern const base::Feature kVrBrowsingNativeAndroidUi;
+extern const base::Feature kVrBrowsingTabsView;
 extern const base::Feature kVrIconInDaydreamHome;
 extern const base::Feature kWebVrAutopresentFromIntent;
 extern const base::Feature kWebVrCardboardSupport;
diff --git a/chrome/browser/android/preferences/preferences_launcher.cc b/chrome/browser/android/preferences/preferences_launcher.cc
index c2c139a..36b0817 100644
--- a/chrome/browser/android/preferences/preferences_launcher.cc
+++ b/chrome/browser/android/preferences/preferences_launcher.cc
@@ -12,9 +12,10 @@
 namespace chrome {
 namespace android {
 
-void PreferencesLauncher::ShowAutofillSettings() {
+void PreferencesLauncher::ShowAutofillSettings(
+    content::WebContents* web_contents) {
   Java_PreferencesLauncher_showAutofillSettings(
-      base::android::AttachCurrentThread());
+      base::android::AttachCurrentThread(), web_contents->GetJavaWebContents());
 }
 
 void PreferencesLauncher::ShowPasswordSettings() {
diff --git a/chrome/browser/android/preferences/preferences_launcher.h b/chrome/browser/android/preferences/preferences_launcher.h
index 80e8091..1c3b14bf 100644
--- a/chrome/browser/android/preferences/preferences_launcher.h
+++ b/chrome/browser/android/preferences/preferences_launcher.h
@@ -7,13 +7,17 @@
 
 #include "base/macros.h"
 
+namespace content {
+class WebContents;
+}
+
 namespace chrome {
 namespace android {
 
 class PreferencesLauncher {
  public:
   // Opens the autofill settings page.
-  static void ShowAutofillSettings();
+  static void ShowAutofillSettings(content::WebContents* web_contents);
 
   // Opens the password settings page.
   static void ShowPasswordSettings();
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 0d6629d..399313b 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -18,6 +18,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
+#include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/vr/android_ui_gesture_target.h"
 #include "chrome/browser/android/vr/autocomplete_controller.h"
@@ -1350,6 +1351,8 @@
       base::FeatureList::IsEnabled(features::kVrBrowsingExperimentalRendering);
   ui_initial_state.assets_supported = AssetsLoader::AssetsSupported();
   ui_initial_state.is_standalone_vr_device = is_standalone_vr_device;
+  ui_initial_state.create_tabs_view =
+      base::FeatureList::IsEnabled(chrome::android::kVrBrowsingTabsView);
 
   return reinterpret_cast<intptr_t>(new VrShell(
       env, obj, ui_initial_state,
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 8163a71..e967ceab 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -276,6 +276,7 @@
 #include "sandbox/win/src/sandbox_policy.h"
 #elif defined(OS_MACOSX)
 #include "chrome/browser/chrome_browser_main_mac.h"
+#include "services/audio/public/mojom/constants.mojom.h"
 #include "services/video_capture/public/mojom/constants.mojom.h"
 #elif defined(OS_CHROMEOS)
 #include "ash/public/interfaces/constants.mojom.h"
@@ -2099,9 +2100,11 @@
 #endif  // BUILDFLAG(ENABLE_MUS)
 
 #if defined(OS_MACOSX)
-  // On Mac, the video-capture service requires a CFRunLoop, provided by a UI
-  // message loop, to run AVFoundation code. See https://crbug.com/834581
-  if (identity.name() == video_capture::mojom::kServiceName)
+  // On Mac, the video-capture and audio services require a CFRunLoop, provided
+  // by a UI message loop, to run AVFoundation and CoreAudio code.
+  // See https://crbug.com/834581
+  if (identity.name() == video_capture::mojom::kServiceName ||
+      identity.name() == audio::mojom::kServiceName)
     command_line->AppendSwitch(switches::kMessageLoopTypeUi);
 #endif
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 1cb4bcd..d9e30c7 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -21,6 +21,7 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   public_deps = [
+    "//ash/resources",
     "//ash/strings",
     "//chrome:extra_resources",
     "//chrome:resources",
@@ -2179,6 +2180,7 @@
     ":attestation_proto",
     ":test_support",
     "//ash",
+    "//ash/resources",
     "//base",
     "//chrome/common",
     "//chromeos/components/tether:test_support",
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index de58edd4..8912413b 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -170,7 +170,6 @@
     ash::switches::kAshEnablePaletteOnAllDisplays,
     ash::switches::kAshTouchHud,
     ash::switches::kAuraLegacyPowerButton,
-    ash::switches::kForceClamshellPowerButton,
     ash::switches::kShowTaps,
     ash::switches::kShowViewsLogin,
     ash::switches::kShowWebUiLock,
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
index 3ef1e3e..357573f 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
@@ -267,7 +267,7 @@
     power_initial = power_limit;
   }
 
-  client_ = std::make_unique<policy::AutoEnrollmentClient>(
+  client_ = policy::AutoEnrollmentClient::CreateForFRE(
       base::Bind(&AutoEnrollmentController::UpdateState,
                  weak_ptr_factory_.GetWeakPtr()),
       service, g_browser_process->local_state(),
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 800602b..0a1b368 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -814,8 +814,8 @@
  protected:
   WizardControllerDeviceStateTest()
       : install_attributes_(ScopedStubInstallAttributes::CreateUnset()) {
-    fake_statistics_provider_.SetMachineStatistic(system::kSerialNumberKey,
-                                                  "test");
+    fake_statistics_provider_.SetMachineStatistic(
+        system::kSerialNumberKeyForTest, "test");
     fake_statistics_provider_.SetMachineStatistic(system::kActivateDateKey,
                                                   "2000-01");
   }
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.cc b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
index 790fcdf..dbdd947 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/policy/server_backed_device_state.h"
 #include "chrome/common/chrome_content_client.h"
@@ -34,6 +35,9 @@
 
 namespace {
 
+using EnrollmentCheckType =
+    em::DeviceAutoEnrollmentRequest::EnrollmentCheckType;
+
 // UMA histogram names.
 const char kUMAProtocolTime[] = "Enterprise.AutoEnrollmentProtocolTime";
 const char kUMAExtraTime[] = "Enterprise.AutoEnrollmentExtraTime";
@@ -62,7 +66,7 @@
     dict->Remove(pref_path, NULL);
 }
 
-// Converts a restore mode enum value from the DM protocol into the
+// Converts a restore mode enum value from the DM protocol for FRE into the
 // corresponding prefs string constant.
 std::string ConvertRestoreMode(
     em::DeviceStateRetrievalResponse::RestoreMode restore_mode) {
@@ -84,33 +88,278 @@
   return std::string();
 }
 
+// Converts an initial enrollment mode enum value from the DM protocol for
+// initial enrollment into the corresponding prefs string constant. Note that we
+// use the |kDeviceStateRestoreMode*| constants on the client for simplicity,
+// because every initial enrollment mode has a matching restore mode (but not
+// vice versa).
+std::string ConvertInitialEnrollmentMode(
+    em::DeviceInitialEnrollmentStateResponse::InitialEnrollmentMode
+        initial_enrollment_mode) {
+  switch (initial_enrollment_mode) {
+    case em::DeviceInitialEnrollmentStateResponse::INITIAL_ENROLLMENT_MODE_NONE:
+      return std::string();
+    case em::DeviceInitialEnrollmentStateResponse::
+        INITIAL_ENROLLMENT_MODE_ENROLLMENT_ENFORCED:
+      return kDeviceStateRestoreModeReEnrollmentEnforced;
+  }
+}
+
 }  // namespace
 
-AutoEnrollmentClient::AutoEnrollmentClient(
-    const ProgressCallback& callback,
-    DeviceManagementService* service,
+// Subclasses of this class provide an identifier and specify the identifier
+// set for the DeviceAutoEnrollmentRequest,
+class AutoEnrollmentClient::DeviceIdentifierProvider {
+ public:
+  virtual ~DeviceIdentifierProvider() {}
+
+  // Should return the EnrollmentCheckType to be used in the
+  // DeviceAutoEnrollmentRequest. This specifies the identifier set used on
+  // the server.
+  virtual enterprise_management::DeviceAutoEnrollmentRequest::
+      EnrollmentCheckType
+      GetEnrollmentCheckType() const = 0;
+
+  // Should return the hash of this device's identifier. The
+  // DeviceAutoEnrollmentRequest exchange will check if this hash is in the
+  // server-side identifier set specified by |GetEnrollmentCheckType()|
+  virtual const std::string& GetIdHash() const = 0;
+};
+
+// Subclasses of this class generate the request to download the device state
+// (after determining that there is server-side device state) and parse the
+// response.
+class AutoEnrollmentClient::StateDownloadMessageProcessor {
+ public:
+  virtual ~StateDownloadMessageProcessor() {}
+
+  // Returns the request job type. This must match the request filled in
+  // |FillRequest|.
+  virtual DeviceManagementRequestJob::JobType GetJobType() const = 0;
+
+  // Fills the specific request type in |request|.
+  virtual void FillRequest(
+      enterprise_management::DeviceManagementRequest* request) = 0;
+
+  // Parses the |response|. If it is valid, extracts |restore_mode|,
+  // |management_domain| and |disabled_message| and returns true. Otherwise,
+  // returns false.
+  virtual bool ParseResponse(
+      const enterprise_management::DeviceManagementResponse& response,
+      std::string* restore_mode,
+      base::Optional<std::string>* management_domain,
+      base::Optional<std::string>* disabled_message) = 0;
+};
+
+namespace {
+
+// Provides device identifier for Forced Re-Enrollment (FRE), where the
+// server-backed state key is used.
+class DeviceIdentifierProviderFRE
+    : public AutoEnrollmentClient::DeviceIdentifierProvider {
+ public:
+  explicit DeviceIdentifierProviderFRE(
+      const std::string& server_backed_state_key) {
+    CHECK(!server_backed_state_key.empty());
+    server_backed_state_key_hash_ =
+        crypto::SHA256HashString(server_backed_state_key);
+  }
+
+  EnrollmentCheckType GetEnrollmentCheckType() const override {
+    return em::DeviceAutoEnrollmentRequest::ENROLLMENT_CHECK_TYPE_FRE;
+  }
+
+  const std::string& GetIdHash() const override {
+    return server_backed_state_key_hash_;
+  }
+
+ private:
+  // SHA-256 digest of the stable identifier.
+  std::string server_backed_state_key_hash_;
+};
+
+// Provides device identifier for Forced Initial Enrollment, where the brand
+// code and serial number is used.
+class DeviceIdentifierProviderInitialEnrollment
+    : public AutoEnrollmentClient::DeviceIdentifierProvider {
+ public:
+  DeviceIdentifierProviderInitialEnrollment(
+      const std::string& device_serial_number,
+      const std::string& device_brand_code) {
+    CHECK(!device_serial_number.empty());
+    CHECK(!device_brand_code.empty());
+    // The hash for initial enrollment is the first 8 bytes of
+    // SHA256(<brnad_code>_<serial_number>).
+    id_hash_ =
+        crypto::SHA256HashString(device_brand_code + "_" + device_serial_number)
+            .substr(0, 8);
+  }
+
+  EnrollmentCheckType GetEnrollmentCheckType() const override {
+    return em::DeviceAutoEnrollmentRequest::
+        ENROLLMENT_CHECK_TYPE_FORCED_ENROLLMENT;
+  }
+
+  const std::string& GetIdHash() const override { return id_hash_; }
+
+ private:
+  // 8-byte Hash built from serial number and brand code passed to the
+  // constructor.
+  std::string id_hash_;
+};
+
+// Handles DeviceStateRetrievalRequest / DeviceStateRetrievalResponse for
+// Forced Re-Enrollment (FRE).
+class StateDownloadMessageProcessorFRE
+    : public AutoEnrollmentClient::StateDownloadMessageProcessor {
+ public:
+  explicit StateDownloadMessageProcessorFRE(
+      const std::string& server_backed_state_key)
+      : server_backed_state_key_(server_backed_state_key) {}
+
+  DeviceManagementRequestJob::JobType GetJobType() const override {
+    return DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL;
+  }
+
+  void FillRequest(em::DeviceManagementRequest* request) override {
+    request->mutable_device_state_retrieval_request()
+        ->set_server_backed_state_key(server_backed_state_key_);
+  }
+
+  bool ParseResponse(const em::DeviceManagementResponse& response,
+                     std::string* restore_mode,
+                     base::Optional<std::string>* management_domain,
+                     base::Optional<std::string>* disabled_message) override {
+    if (!response.has_device_state_retrieval_response()) {
+      LOG(ERROR) << "Server failed to provide auto-enrollment response.";
+      return false;
+    }
+    const em::DeviceStateRetrievalResponse& state_response =
+        response.device_state_retrieval_response();
+    *restore_mode = ConvertRestoreMode(state_response.restore_mode());
+    if (state_response.has_management_domain())
+      *management_domain = state_response.management_domain();
+    else
+      management_domain->reset();
+
+    if (state_response.has_disabled_state())
+      *disabled_message = state_response.disabled_state().message();
+    else
+      disabled_message->reset();
+
+    // Logging as "WARNING" to make sure it's preserved in the logs.
+    LOG(WARNING) << "Received restore_mode=" << state_response.restore_mode();
+
+    return true;
+  }
+
+ private:
+  // Stable state key.
+  std::string server_backed_state_key_;
+};
+
+// Handles DeviceInitialEnrollmentStateRequest /
+// DeviceInitialEnrollmentStateResponse for Forced Initial Enrollment.
+class StateDownloadMessageProcessorInitialEnrollment
+    : public AutoEnrollmentClient::StateDownloadMessageProcessor {
+ public:
+  StateDownloadMessageProcessorInitialEnrollment(
+      const std::string& device_serial_number,
+      const std::string& device_brand_code)
+      : device_serial_number_(device_serial_number),
+        device_brand_code_(device_brand_code) {}
+
+  DeviceManagementRequestJob::JobType GetJobType() const override {
+    return DeviceManagementRequestJob::TYPE_INITIAL_ENROLLMENT_STATE_RETRIEVAL;
+  }
+
+  void FillRequest(em::DeviceManagementRequest* request) override {
+    auto* inner_request =
+        request->mutable_device_initial_enrollment_state_request();
+    inner_request->set_brand_code(device_brand_code_);
+    inner_request->set_serial_number(device_serial_number_);
+  }
+
+  bool ParseResponse(const em::DeviceManagementResponse& response,
+                     std::string* restore_mode,
+                     base::Optional<std::string>* management_domain,
+                     base::Optional<std::string>* disabled_message) override {
+    if (!response.has_device_initial_enrollment_state_response()) {
+      LOG(ERROR) << "Server failed to provide initial enrollment response.";
+      return false;
+    }
+
+    const em::DeviceInitialEnrollmentStateResponse& state_response =
+        response.device_initial_enrollment_state_response();
+    if (state_response.has_initial_enrollment_mode()) {
+      *restore_mode = ConvertInitialEnrollmentMode(
+          state_response.initial_enrollment_mode());
+    } else {
+      // Unknown initial enrollment mode - treat as no enrollment.
+      *restore_mode = std::string();
+    }
+
+    if (state_response.has_management_domain())
+      *management_domain = state_response.management_domain();
+    else
+      management_domain->reset();
+
+    // Device disabling is not supported in initial forced enrollment.
+    disabled_message->reset();
+
+    // Logging as "WARNING" to make sure it's preserved in the logs.
+    LOG(WARNING) << "Received initial_enrollment_mode="
+                 << state_response.initial_enrollment_mode();
+
+    return true;
+  }
+
+ private:
+  // Serial number of the device.
+  std::string device_serial_number_;
+  // 4-character brand code of the device.
+  std::string device_brand_code_;
+};
+
+}  // namespace
+
+// static
+std::unique_ptr<AutoEnrollmentClient> AutoEnrollmentClient::CreateForFRE(
+    const ProgressCallback& progress_callback,
+    DeviceManagementService* device_management_service,
     PrefService* local_state,
     scoped_refptr<net::URLRequestContextGetter> system_request_context,
     const std::string& server_backed_state_key,
     int power_initial,
-    int power_limit)
-    : progress_callback_(callback),
-      state_(AUTO_ENROLLMENT_STATE_IDLE),
-      has_server_state_(false),
-      device_state_available_(false),
-      device_id_(base::GenerateGUID()),
-      server_backed_state_key_(server_backed_state_key),
-      current_power_(power_initial),
-      power_limit_(power_limit),
-      modulus_updates_received_(0),
-      device_management_service_(service),
-      local_state_(local_state),
-      request_context_(system_request_context) {
-  DCHECK_LE(current_power_, power_limit_);
-  DCHECK(!progress_callback_.is_null());
-  CHECK(!server_backed_state_key_.empty());
-  server_backed_state_key_hash_ =
-      crypto::SHA256HashString(server_backed_state_key_);
+    int power_limit) {
+  return base::WrapUnique(new AutoEnrollmentClient(
+      progress_callback, device_management_service, local_state,
+      system_request_context,
+      std::make_unique<DeviceIdentifierProviderFRE>(server_backed_state_key),
+      std::make_unique<StateDownloadMessageProcessorFRE>(
+          server_backed_state_key),
+      power_initial, power_limit));
+}
+
+// static
+std::unique_ptr<AutoEnrollmentClient>
+AutoEnrollmentClient::CreateForInitialEnrollment(
+    const ProgressCallback& progress_callback,
+    DeviceManagementService* device_management_service,
+    PrefService* local_state,
+    scoped_refptr<net::URLRequestContextGetter> system_request_context,
+    const std::string& device_serial_number,
+    const std::string& device_brand_code,
+    int power_initial,
+    int power_limit) {
+  return base::WrapUnique(new AutoEnrollmentClient(
+      progress_callback, device_management_service, local_state,
+      system_request_context,
+      std::make_unique<DeviceIdentifierProviderInitialEnrollment>(
+          device_serial_number, device_brand_code),
+      std::make_unique<StateDownloadMessageProcessorInitialEnrollment>(
+          device_serial_number, device_brand_code),
+      power_initial, power_limit));
 }
 
 AutoEnrollmentClient::~AutoEnrollmentClient() {
@@ -164,6 +413,34 @@
   }
 }
 
+AutoEnrollmentClient::AutoEnrollmentClient(
+    const ProgressCallback& callback,
+    DeviceManagementService* service,
+    PrefService* local_state,
+    scoped_refptr<net::URLRequestContextGetter> system_request_context,
+    std::unique_ptr<DeviceIdentifierProvider> device_identifier_provider,
+    std::unique_ptr<StateDownloadMessageProcessor>
+        state_download_message_processor,
+    int power_initial,
+    int power_limit)
+    : progress_callback_(callback),
+      state_(AUTO_ENROLLMENT_STATE_IDLE),
+      has_server_state_(false),
+      device_state_available_(false),
+      device_id_(base::GenerateGUID()),
+      current_power_(power_initial),
+      power_limit_(power_limit),
+      modulus_updates_received_(0),
+      device_management_service_(service),
+      local_state_(local_state),
+      request_context_(system_request_context),
+      device_identifier_provider_(std::move(device_identifier_provider)),
+      state_download_message_processor_(
+          std::move(state_download_message_processor)) {
+  DCHECK_LE(current_power_, power_limit_);
+  DCHECK(!progress_callback_.is_null());
+}
+
 bool AutoEnrollmentClient::GetCachedDecision() {
   const PrefService::Preference* has_server_state_pref =
       local_state_->FindPreference(prefs::kShouldAutoEnroll);
@@ -241,11 +518,16 @@
 }
 
 void AutoEnrollmentClient::SendBucketDownloadRequest() {
-  // Only power-of-2 moduli are supported for now. These are computed by taking
-  // the lower |current_power_| bits of the hash.
+  std::string id_hash = device_identifier_provider_->GetIdHash();
+  // Currently AutoEnrollmentClient supports working with hashes that are at
+  // least 8 bytes long. If this is reduced, the computation of the remainder
+  // must also be adapted to handle the case of a shorter hash gracefully.
+  DCHECK_GE(id_hash.size(), 8u);
+
   uint64_t remainder = 0;
+  const size_t last_byte_index = id_hash.size() - 1;
   for (int i = 0; 8 * i < current_power_; ++i) {
-    uint64_t byte = server_backed_state_key_hash_[31 - i] & 0xff;
+    uint64_t byte = id_hash[last_byte_index - i] & 0xff;
     remainder = remainder | (byte << (8 * i));
   }
   remainder = remainder & ((UINT64_C(1) << current_power_) - 1);
@@ -262,6 +544,8 @@
       request_job_->GetRequest()->mutable_auto_enrollment_request();
   request->set_remainder(remainder);
   request->set_modulus(INT64_C(1) << current_power_);
+  request->set_enrollment_check_type(
+      device_identifier_provider_->GetEnrollmentCheckType());
   request_job_->Start(
       base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
                  base::Unretained(this),
@@ -271,15 +555,10 @@
 void AutoEnrollmentClient::SendDeviceStateRequest() {
   ReportProgress(AUTO_ENROLLMENT_STATE_PENDING);
 
-  VLOG(1) << "State request for key: " << server_backed_state_key_;
-  request_job_.reset(
-      device_management_service_->CreateJob(
-          DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL,
-          request_context_.get()));
+  request_job_.reset(device_management_service_->CreateJob(
+      state_download_message_processor_->GetJobType(), request_context_.get()));
   request_job_->SetClientID(device_id_);
-  em::DeviceStateRetrievalRequest* request =
-      request_job_->GetRequest()->mutable_device_state_retrieval_request();
-  request->set_server_backed_state_key(server_backed_state_key_);
+  state_download_message_processor_->FillRequest(request_job_->GetRequest());
   request_job_->Start(
       base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
                  base::Unretained(this),
@@ -377,45 +656,41 @@
 bool AutoEnrollmentClient::OnDeviceStateRequestCompletion(
     DeviceManagementStatus status,
     int net_error,
-    const enterprise_management::DeviceManagementResponse& response) {
-  bool progress = false;
-  if (!response.has_device_state_retrieval_response()) {
-    LOG(ERROR) << "Server failed to provide auto-enrollment response.";
-  } else {
-    const em::DeviceStateRetrievalResponse& state_response =
-        response.device_state_retrieval_response();
-    {
-      DictionaryPrefUpdate dict(local_state_, prefs::kServerBackedDeviceState);
-      UpdateDict(
-          dict.Get(), kDeviceStateManagementDomain,
-          state_response.has_management_domain(),
-          std::make_unique<base::Value>(state_response.management_domain()));
+    const em::DeviceManagementResponse& response) {
+  std::string restore_mode;
+  base::Optional<std::string> management_domain;
+  base::Optional<std::string> disabled_message;
 
-      std::string restore_mode =
-          ConvertRestoreMode(state_response.restore_mode());
-      UpdateDict(dict.Get(), kDeviceStateRestoreMode, !restore_mode.empty(),
-                 std::make_unique<base::Value>(restore_mode));
+  bool progress = state_download_message_processor_->ParseResponse(
+      response, &restore_mode, &management_domain, &disabled_message);
+  if (!progress)
+    return false;
 
-      UpdateDict(dict.Get(), kDeviceStateDisabledMessage,
-                 state_response.has_disabled_state(),
-                 std::make_unique<base::Value>(
-                     state_response.disabled_state().message()));
+  {
+    DictionaryPrefUpdate dict(local_state_, prefs::kServerBackedDeviceState);
+    UpdateDict(dict.Get(), kDeviceStateManagementDomain,
+               management_domain.has_value(),
+               std::make_unique<base::Value>(
+                   management_domain.value_or(std::string())));
 
-      // Logging as "WARNING" to make sure it's preserved in the logs.
-      LOG(WARNING) << "Received restore_mode=" << state_response.restore_mode();
-    }
-    local_state_->CommitPendingWrite();
-    device_state_available_ = true;
-    progress = true;
+    UpdateDict(dict.Get(), kDeviceStateRestoreMode, !restore_mode.empty(),
+               std::make_unique<base::Value>(restore_mode));
+
+    UpdateDict(dict.Get(), kDeviceStateDisabledMessage,
+               disabled_message.has_value(),
+               std::make_unique<base::Value>(
+                   disabled_message.value_or(std::string())));
   }
-
-  return progress;
+  local_state_->CommitPendingWrite();
+  device_state_available_ = true;
+  return true;
 }
 
 bool AutoEnrollmentClient::IsIdHashInProtobuf(
       const google::protobuf::RepeatedPtrField<std::string>& hashes) {
+  std::string id_hash = device_identifier_provider_->GetIdHash();
   for (int i = 0; i < hashes.size(); ++i) {
-    if (hashes.Get(i) == server_backed_state_key_hash_)
+    if (hashes.Get(i) == id_hash)
       return true;
   }
   return false;
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.h b/chrome/browser/chromeos/policy/auto_enrollment_client.h
index 36800d9..1d267df3 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.h
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.h
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/time/time.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "net/base/network_change_notifier.h"
@@ -31,8 +32,8 @@
 
 namespace policy {
 
-class DeviceManagementRequestJob;
 class DeviceManagementService;
+class DeviceManagementRequestJob;
 
 // Indicates the current state of the auto-enrollment check.  (Numeric values
 // are just to make reading of log files easier.)
@@ -64,15 +65,24 @@
   // and the max is 2^62 (when the moduli are restricted to powers-of-2).
   static const int kMaximumPower = 62;
 
+  // Subclasses of this class provide an identifier and specify the identifier
+  // set for the DeviceAutoEnrollmentRequest,
+  class DeviceIdentifierProvider;
+
+  // Subclasses of this class generate the request to download the device state
+  // (after determining that there is server-side device state) and parse the
+  // response.
+  class StateDownloadMessageProcessor;
+
   // Used for signaling progress to a consumer.
-  typedef base::Callback<void(AutoEnrollmentState)> ProgressCallback;
+  typedef base::RepeatingCallback<void(AutoEnrollmentState)> ProgressCallback;
 
   // |progress_callback| will be invoked whenever some significant event happens
   // as part of the protocol, after Start() is invoked.
   // The result of the protocol will be cached in |local_state|.
   // |power_initial| and |power_limit| are exponents of power-of-2 values which
   // will be the initial modulus and the maximum modulus used by this client.
-  AutoEnrollmentClient(
+  static std::unique_ptr<AutoEnrollmentClient> CreateForFRE(
       const ProgressCallback& progress_callback,
       DeviceManagementService* device_management_service,
       PrefService* local_state,
@@ -80,6 +90,22 @@
       const std::string& server_backed_state_key,
       int power_initial,
       int power_limit);
+
+  // |progress_callback| will be invoked whenever some significant event happens
+  // as part of the protocol, after Start() is invoked.
+  // The result of the protocol will be cached in |local_state|.
+  // |power_initial| and |power_limit| are exponents of power-of-2 values which
+  // will be the initial modulus and the maximum modulus used by this client.
+  static std::unique_ptr<AutoEnrollmentClient> CreateForInitialEnrollment(
+      const ProgressCallback& progress_callback,
+      DeviceManagementService* device_management_service,
+      PrefService* local_state,
+      scoped_refptr<net::URLRequestContextGetter> system_request_context,
+      const std::string& device_serial_number,
+      const std::string& device_brand_code,
+      int power_initial,
+      int power_limit);
+
   ~AutoEnrollmentClient() override;
 
   // Registers preferences in local state.
@@ -116,6 +142,17 @@
       int,
       const enterprise_management::DeviceManagementResponse&);
 
+  AutoEnrollmentClient(
+      const ProgressCallback& progress_callback,
+      DeviceManagementService* device_management_service,
+      PrefService* local_state,
+      scoped_refptr<net::URLRequestContextGetter> system_request_context,
+      std::unique_ptr<DeviceIdentifierProvider> device_identifier_provider,
+      std::unique_ptr<StateDownloadMessageProcessor>
+          state_download_message_processor,
+      int power_initial,
+      int power_limit);
+
   // Tries to load the result of a previous execution of the protocol from
   // local state. Returns true if that decision has been made and is valid.
   bool GetCachedDecision();
@@ -157,7 +194,8 @@
       int net_error,
       const enterprise_management::DeviceManagementResponse& response);
 
-  // Returns true if |server_backed_state_key_hash_| is contained in |hashes|.
+  // Returns true if the identifier hash provided by
+  // |device_identifier_provider_| is contained in |hashes|.
   bool IsIdHashInProtobuf(
       const google::protobuf::RepeatedPtrField<std::string>& hashes);
 
@@ -181,10 +219,6 @@
   // Randomly generated device id for the auto-enrollment requests.
   std::string device_id_;
 
-  // Stable state key and its SHA-256 digest.
-  std::string server_backed_state_key_;
-  std::string server_backed_state_key_hash_;
-
   // Power-of-2 modulus to try next.
   int current_power_;
 
@@ -206,6 +240,14 @@
   // The request context to use to perform the auto enrollment request.
   scoped_refptr<net::URLRequestContextGetter> request_context_;
 
+  // Specifies the identifier set and the hash of the device's current
+  // identifier.
+  std::unique_ptr<DeviceIdentifierProvider> device_identifier_provider_;
+
+  // Fills and parses state retrieval request / response.
+  std::unique_ptr<StateDownloadMessageProcessor>
+      state_download_message_processor_;
+
   // Times used to determine the duration of the protocol, and the extra time
   // needed to complete after the signin was complete.
   // If |time_start_| is not null, the protocol is still running.
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
index 0b83cd4..b7f56a5 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
@@ -41,12 +41,22 @@
     "\xb3\x4a\x5e\xff\x73\x7e\x92\xd9\xf8\x6e\x72\x44\xd0\x97\xc3\xe6";
 const char kDisabledMessage[] = "This device has been disabled.";
 
+const char kSerialNumber[] = "SN123456";
+const char kBrandCode[] = "AABC";
+const char kInitialEnrollmentIdHash[] = "\x30\x18\xb7\x0f\x76\x09\xc5\xc7";
+
+const int kInitialEnrollmentIdHashLength = 8;
+
 using ::testing::InSequence;
 using ::testing::Mock;
 using ::testing::SaveArg;
 using ::testing::_;
 
-class AutoEnrollmentClientTest : public testing::Test {
+enum class AutoEnrollmentProtocol { kFRE, kInitialEnrollment };
+
+class AutoEnrollmentClientTest
+    : public testing::Test,
+      public ::testing::WithParamInterface<AutoEnrollmentProtocol> {
  protected:
   AutoEnrollmentClientTest()
       : scoped_testing_local_state_(
@@ -55,7 +65,7 @@
         state_(AUTO_ENROLLMENT_STATE_PENDING) {}
 
   void SetUp() override {
-    CreateClient(kStateKey, 4, 8);
+    CreateClient(4, 8);
     ASSERT_FALSE(local_state_->GetUserPref(prefs::kShouldAutoEnroll));
     ASSERT_FALSE(local_state_->GetUserPref(prefs::kAutoEnrollmentPowerLimit));
   }
@@ -65,19 +75,25 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  void CreateClient(const std::string& state_key,
-                    int power_initial,
-                    int power_limit) {
+  void CreateClient(int power_initial, int power_limit) {
     state_ = AUTO_ENROLLMENT_STATE_PENDING;
     service_.reset(new MockDeviceManagementService());
     EXPECT_CALL(*service_, StartJob(_, _, _, _, _, _))
         .WillRepeatedly(SaveArg<5>(&last_request_));
-    client_.reset(new AutoEnrollmentClient(
-        base::Bind(&AutoEnrollmentClientTest::ProgressCallback,
-                   base::Unretained(this)),
-        service_.get(), local_state_, new net::TestURLRequestContextGetter(
-                                          base::ThreadTaskRunnerHandle::Get()),
-        state_key, power_initial, power_limit));
+    auto progress_callback = base::BindRepeating(
+        &AutoEnrollmentClientTest::ProgressCallback, base::Unretained(this));
+    auto* url_request_context_getter = new net::TestURLRequestContextGetter(
+        base::ThreadTaskRunnerHandle::Get());
+    if (GetParam() == AutoEnrollmentProtocol::kFRE) {
+      client_ = AutoEnrollmentClient::CreateForFRE(
+          progress_callback, service_.get(), local_state_,
+          url_request_context_getter, kStateKey, power_initial, power_limit);
+    } else {
+      client_ = AutoEnrollmentClient::CreateForInitialEnrollment(
+          progress_callback, service_.get(), local_state_,
+          url_request_context_getter, kSerialNumber, kBrandCode, power_initial,
+          power_limit);
+    }
   }
 
   void ProgressCallback(AutoEnrollmentState state) {
@@ -100,23 +116,75 @@
     if (with_hashes) {
       for (int i = 0; i < 10; ++i) {
         std::string state_key = base::StringPrintf("state_key %d", i);
-        std::string hash = crypto::SHA256HashString(state_key);
+        std::string hash_full = crypto::SHA256HashString(state_key);
+        std::string hash =
+            GetParam() == AutoEnrollmentProtocol::kFRE
+                ? hash_full
+                : hash_full.substr(0, kInitialEnrollmentIdHashLength);
         enrollment_response->mutable_hash()->Add()->assign(hash);
       }
     }
     if (with_id_hash) {
-      enrollment_response->mutable_hash()->Add()->assign(kStateKeyHash,
-                                                         crypto::kSHA256Length);
+      if (GetParam() == AutoEnrollmentProtocol::kFRE) {
+        enrollment_response->mutable_hash()->Add()->assign(
+            kStateKeyHash, crypto::kSHA256Length);
+      } else {
+        enrollment_response->mutable_hash()->Add()->assign(
+            kInitialEnrollmentIdHash, kInitialEnrollmentIdHashLength);
+      }
     }
     EXPECT_CALL(*service_,
                 CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT, _))
         .WillOnce(service_->SucceedJob(response));
   }
 
+  em::DeviceInitialEnrollmentStateResponse::InitialEnrollmentMode
+  MapRestoreModeToInitialEnrollmentMode(
+      em::DeviceStateRetrievalResponse::RestoreMode restore_mode) {
+    using DeviceStateRetrieval = em::DeviceStateRetrievalResponse;
+    using DeviceInitialEnrollmentState =
+        em::DeviceInitialEnrollmentStateResponse;
+
+    switch (restore_mode) {
+      case DeviceStateRetrieval::RESTORE_MODE_NONE:
+        return DeviceInitialEnrollmentState::INITIAL_ENROLLMENT_MODE_NONE;
+      case DeviceStateRetrieval::RESTORE_MODE_REENROLLMENT_REQUESTED:
+        return DeviceInitialEnrollmentState::INITIAL_ENROLLMENT_MODE_NONE;
+      case DeviceStateRetrieval::RESTORE_MODE_REENROLLMENT_ENFORCED:
+        return DeviceInitialEnrollmentState::
+            INITIAL_ENROLLMENT_MODE_ENROLLMENT_ENFORCED;
+      case DeviceStateRetrieval::RESTORE_MODE_DISABLED:
+        return DeviceInitialEnrollmentState::INITIAL_ENROLLMENT_MODE_NONE;
+      case DeviceStateRetrieval::RESTORE_MODE_REENROLLMENT_ZERO_TOUCH:
+        return DeviceInitialEnrollmentState::INITIAL_ENROLLMENT_MODE_NONE;
+    }
+  }
+
   void ServerWillSendState(
       const std::string& management_domain,
       em::DeviceStateRetrievalResponse::RestoreMode restore_mode,
       const std::string& device_disabled_message) {
+    if (GetParam() == AutoEnrollmentProtocol::kFRE) {
+      ServerWillSendFREState(management_domain, restore_mode,
+                             device_disabled_message);
+    } else {
+      ServerWillSendInitialEnrollmentState(
+          management_domain,
+          MapRestoreModeToInitialEnrollmentMode(restore_mode));
+    }
+  }
+
+  DeviceManagementRequestJob::JobType GetStateRetrievalJobType() {
+    return GetParam() == AutoEnrollmentProtocol::kFRE
+               ? DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL
+               : DeviceManagementRequestJob::
+                     TYPE_INITIAL_ENROLLMENT_STATE_RETRIEVAL;
+  }
+
+  void ServerWillSendFREState(
+      const std::string& management_domain,
+      em::DeviceStateRetrievalResponse::RestoreMode restore_mode,
+      const std::string& device_disabled_message) {
     em::DeviceManagementResponse response;
     em::DeviceStateRetrievalResponse* state_response =
         response.mutable_device_state_retrieval_response();
@@ -124,9 +192,20 @@
     state_response->set_management_domain(management_domain);
     state_response->mutable_disabled_state()->set_message(
         device_disabled_message);
-    EXPECT_CALL(
-        *service_,
-        CreateJob(DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL, _))
+    EXPECT_CALL(*service_, CreateJob(GetStateRetrievalJobType(), _))
+        .WillOnce(service_->SucceedJob(response));
+  }
+
+  void ServerWillSendInitialEnrollmentState(
+      const std::string& management_domain,
+      em::DeviceInitialEnrollmentStateResponse::InitialEnrollmentMode
+          initial_enrollment_mode) {
+    em::DeviceManagementResponse response;
+    em::DeviceInitialEnrollmentStateResponse* state_response =
+        response.mutable_device_initial_enrollment_state_response();
+    state_response->set_initial_enrollment_mode(initial_enrollment_mode);
+    state_response->set_management_domain(management_domain);
+    EXPECT_CALL(*service_, CreateJob(GetStateRetrievalJobType(), _))
         .WillOnce(service_->SucceedJob(response));
   }
 
@@ -178,9 +257,14 @@
     }
 
     std::string actual_disabled_message;
-    EXPECT_TRUE(state_dict->GetString(kDeviceStateDisabledMessage,
-                                      &actual_disabled_message));
-    EXPECT_EQ(expected_disabled_message, actual_disabled_message);
+    if (GetParam() == AutoEnrollmentProtocol::kFRE) {
+      EXPECT_TRUE(state_dict->GetString(kDeviceStateDisabledMessage,
+                                        &actual_disabled_message));
+      EXPECT_EQ(expected_disabled_message, actual_disabled_message);
+    } else {
+      EXPECT_FALSE(state_dict->GetString(kDeviceStateDisabledMessage,
+                                         &actual_disabled_message));
+    }
   }
 
   const em::DeviceAutoEnrollmentRequest& auto_enrollment_request() {
@@ -199,7 +283,7 @@
   DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentClientTest);
 };
 
-TEST_F(AutoEnrollmentClientTest, NetworkFailure) {
+TEST_P(AutoEnrollmentClientTest, NetworkFailure) {
   ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_);
@@ -207,7 +291,7 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, EmptyReply) {
+TEST_P(AutoEnrollmentClientTest, EmptyReply) {
   ServerWillReply(-1, false, false);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
@@ -215,7 +299,7 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, ClientUploadsRightBits) {
+TEST_P(AutoEnrollmentClientTest, ClientUploadsRightBits) {
   ServerWillReply(-1, false, false);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
@@ -223,12 +307,17 @@
   EXPECT_TRUE(auto_enrollment_request().has_remainder());
   EXPECT_TRUE(auto_enrollment_request().has_modulus());
   EXPECT_EQ(16, auto_enrollment_request().modulus());
-  EXPECT_EQ(kStateKeyHash[31] & 0xf, auto_enrollment_request().remainder());
+  if (GetParam() == AutoEnrollmentProtocol::kFRE) {
+    EXPECT_EQ(kStateKeyHash[31] & 0xf, auto_enrollment_request().remainder());
+  } else {
+    EXPECT_EQ(kInitialEnrollmentIdHash[7] & 0xf,
+              auto_enrollment_request().remainder());
+  }
   VerifyCachedResult(false, 8);
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, AskForMoreThenFail) {
+TEST_P(AutoEnrollmentClientTest, AskForMoreThenFail) {
   InSequence sequence;
   ServerWillReply(32, false, false);
   ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
@@ -238,7 +327,7 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, AskForMoreThenEvenMore) {
+TEST_P(AutoEnrollmentClientTest, AskForMoreThenEvenMore) {
   InSequence sequence;
   ServerWillReply(32, false, false);
   ServerWillReply(64, false, false);
@@ -248,7 +337,7 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, AskForLess) {
+TEST_P(AutoEnrollmentClientTest, AskForLess) {
   InSequence sequence;
   ServerWillReply(8, false, false);
   ServerWillReply(-1, true, true);
@@ -264,7 +353,7 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, AskForSame) {
+TEST_P(AutoEnrollmentClientTest, AskForSame) {
   InSequence sequence;
   ServerWillReply(16, false, false);
   ServerWillReply(-1, true, true);
@@ -280,7 +369,7 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, AskForSameTwice) {
+TEST_P(AutoEnrollmentClientTest, AskForSameTwice) {
   InSequence sequence;
   ServerWillReply(16, false, false);
   ServerWillReply(16, false, false);
@@ -290,7 +379,7 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, AskForTooMuch) {
+TEST_P(AutoEnrollmentClientTest, AskForTooMuch) {
   ServerWillReply(512, false, false);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_);
@@ -298,7 +387,7 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, AskNonPowerOf2) {
+TEST_P(AutoEnrollmentClientTest, AskNonPowerOf2) {
   InSequence sequence;
   ServerWillReply(100, false, false);
   ServerWillReply(-1, false, false);
@@ -307,12 +396,17 @@
   EXPECT_TRUE(auto_enrollment_request().has_remainder());
   EXPECT_TRUE(auto_enrollment_request().has_modulus());
   EXPECT_EQ(128, auto_enrollment_request().modulus());
-  EXPECT_EQ(kStateKeyHash[31] & 0x7f, auto_enrollment_request().remainder());
+  if (GetParam() == AutoEnrollmentProtocol::kFRE) {
+    EXPECT_EQ(kStateKeyHash[31] & 0x7f, auto_enrollment_request().remainder());
+  } else {
+    EXPECT_EQ(kInitialEnrollmentIdHash[7] & 0x7f,
+              auto_enrollment_request().remainder());
+  }
   VerifyCachedResult(false, 8);
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, ConsumerDevice) {
+TEST_P(AutoEnrollmentClientTest, ConsumerDevice) {
   ServerWillReply(-1, true, false);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
@@ -325,7 +419,7 @@
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
 }
 
-TEST_F(AutoEnrollmentClientTest, ForcedReEnrollment) {
+TEST_P(AutoEnrollmentClientTest, ForcedReEnrollment) {
   ServerWillReply(-1, true, true);
   ServerWillSendState(
       "example.com",
@@ -344,7 +438,11 @@
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_);
 }
 
-TEST_F(AutoEnrollmentClientTest, ForcedReEnrollmentZeroTouch) {
+TEST_P(AutoEnrollmentClientTest, ForcedReEnrollmentZeroTouch) {
+  // Zero-Touch is currently not supported in the initial-enrollment exchange.
+  if (GetParam() == AutoEnrollmentProtocol::kInitialEnrollment)
+    return;
+
   ServerWillReply(-1, true, true);
   ServerWillSendState(
       "example.com",
@@ -363,7 +461,12 @@
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ZERO_TOUCH, state_);
 }
 
-TEST_F(AutoEnrollmentClientTest, RequestedReEnrollment) {
+TEST_P(AutoEnrollmentClientTest, RequestedReEnrollment) {
+  // Requesting re-enrollment is currently not supported in the
+  // initial-enrollment exchange.
+  if (GetParam() == AutoEnrollmentProtocol::kInitialEnrollment)
+    return;
+
   ServerWillReply(-1, true, true);
   ServerWillSendState(
       "example.com",
@@ -377,12 +480,15 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, DeviceDisabled) {
+TEST_P(AutoEnrollmentClientTest, DeviceDisabled) {
+  // Disabling is currently not supported in the initial-enrollment exchange.
+  if (GetParam() == AutoEnrollmentProtocol::kInitialEnrollment)
+    return;
+
   ServerWillReply(-1, true, true);
-  ServerWillSendState(
-      "example.com",
-      em::DeviceStateRetrievalResponse::RESTORE_MODE_DISABLED,
-      kDisabledMessage);
+  ServerWillSendState("example.com",
+                      em::DeviceStateRetrievalResponse::RESTORE_MODE_DISABLED,
+                      kDisabledMessage);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
   VerifyCachedResult(true, 8);
@@ -391,8 +497,8 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, NoBitsUploaded) {
-  CreateClient(kStateKey, 0, 0);
+TEST_P(AutoEnrollmentClientTest, NoBitsUploaded) {
+  CreateClient(0, 0);
   ServerWillReply(-1, false, false);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
@@ -404,10 +510,12 @@
   EXPECT_FALSE(HasServerBackedState());
 }
 
-TEST_F(AutoEnrollmentClientTest, ManyBitsUploaded) {
-  int64_t bottom62 = INT64_C(0x386e7244d097c3e6);
+TEST_P(AutoEnrollmentClientTest, ManyBitsUploaded) {
+  int64_t bottom62 = GetParam() == AutoEnrollmentProtocol::kFRE
+                         ? INT64_C(0x386e7244d097c3e6)
+                         : INT64_C(0x3018b70f7609c5c7);
   for (int i = 0; i <= 62; ++i) {
-    CreateClient(kStateKey, i, i);
+    CreateClient(i, i);
     ServerWillReply(-1, false, false);
     client_->Start();
     EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
@@ -421,8 +529,8 @@
   }
 }
 
-TEST_F(AutoEnrollmentClientTest, MoreThan32BitsUploaded) {
-  CreateClient(kStateKey, 10, 37);
+TEST_P(AutoEnrollmentClientTest, MoreThan32BitsUploaded) {
+  CreateClient(10, 37);
   InSequence sequence;
   ServerWillReply(INT64_C(1) << 37, false, false);
   ServerWillReply(-1, true, true);
@@ -438,7 +546,7 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, ReuseCachedDecision) {
+TEST_P(AutoEnrollmentClientTest, ReuseCachedDecision) {
   // No bucket download requests should be issued.
   EXPECT_CALL(*service_,
               CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT, _))
@@ -463,12 +571,12 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, RetryIfPowerLargerThanCached) {
+TEST_P(AutoEnrollmentClientTest, RetryIfPowerLargerThanCached) {
   local_state_->SetUserPref(prefs::kShouldAutoEnroll,
                             std::make_unique<base::Value>(false));
   local_state_->SetUserPref(prefs::kAutoEnrollmentPowerLimit,
                             std::make_unique<base::Value>(8));
-  CreateClient(kStateKey, 5, 10);
+  CreateClient(5, 10);
   ServerWillReply(-1, true, true);
   ServerWillSendState(
       "example.com",
@@ -481,7 +589,7 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, NetworkChangeRetryAfterErrors) {
+TEST_P(AutoEnrollmentClientTest, NetworkChangeRetryAfterErrors) {
   ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
   client_->Start();
   // Don't invoke the callback if there was a network failure.
@@ -518,7 +626,7 @@
                           kDisabledMessage);
 }
 
-TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonWithPendingRequest) {
+TEST_P(AutoEnrollmentClientTest, CancelAndDeleteSoonWithPendingRequest) {
   MockDeviceManagementJob* job = NULL;
   ServerWillReplyAsync(&job);
   EXPECT_FALSE(job);
@@ -539,7 +647,7 @@
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_);
 }
 
-TEST_F(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) {
+TEST_P(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) {
   MockDeviceManagementJob* job = NULL;
   ServerWillReplyAsync(&job);
   EXPECT_FALSE(job);
@@ -569,7 +677,7 @@
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_);
 }
 
-TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) {
+TEST_P(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) {
   ServerWillReply(-1, true, true);
   ServerWillSendState(
       "example.com",
@@ -588,7 +696,7 @@
   EXPECT_TRUE(base::MessageLoopCurrent::Get()->IsIdleForTesting());
 }
 
-TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterNetworkFailure) {
+TEST_P(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterNetworkFailure) {
   ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
   client_->Start();
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_);
@@ -600,7 +708,7 @@
   EXPECT_TRUE(base::MessageLoopCurrent::Get()->IsIdleForTesting());
 }
 
-TEST_F(AutoEnrollmentClientTest, NetworkFailureThenRequireUpdatedModulus) {
+TEST_P(AutoEnrollmentClientTest, NetworkFailureThenRequireUpdatedModulus) {
   // This test verifies that if the first request fails due to a network
   // problem then the second request will correctly handle an updated
   // modulus request from the server.
@@ -637,5 +745,13 @@
   Mock::VerifyAndClearExpectations(service_.get());
 }
 
+INSTANTIATE_TEST_CASE_P(FRE,
+                        AutoEnrollmentClientTest,
+                        testing::Values(AutoEnrollmentProtocol::kFRE));
+INSTANTIATE_TEST_CASE_P(
+    InitialEnrollment,
+    AutoEnrollmentClientTest,
+    testing::Values(AutoEnrollmentProtocol::kInitialEnrollment));
+
 }  // namespace
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
index d4c79c0..c0f5fbd 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
@@ -50,7 +50,7 @@
             &statistics_provider_) {
     RegisterLocalState(local_state_.registry());
     statistics_provider_.SetMachineStatistic(
-        chromeos::system::kSerialNumberKey, "fake-serial");
+        chromeos::system::kSerialNumberKeyForTest, "fake-serial");
     statistics_provider_.SetMachineStatistic(
         chromeos::system::kHardwareClassKey, "fake-hardware");
   }
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index a1d832eb..8ecf4c6 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -120,7 +120,7 @@
         state_keys_broker_(&fake_session_manager_client_),
         store_(NULL) {
     fake_statistics_provider_.SetMachineStatistic(
-        chromeos::system::kSerialNumberKey, "test_sn");
+        chromeos::system::kSerialNumberKeyForTest, "test_sn");
     fake_statistics_provider_.SetMachineStatistic(
         chromeos::system::kHardwareClassKey, "test_hw");
     std::vector<std::string> state_keys;
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
index a5c1bbb..14aeda3 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -239,7 +239,7 @@
 
   void SetUp() override {
     fake_statistics_provider_.SetMachineStatistic(
-        chromeos::system::kSerialNumberKey, kFakeSerialNumber);
+        chromeos::system::kSerialNumberKeyForTest, kFakeSerialNumber);
 
     EXPECT_CALL(provider_, IsInitializationComplete(_))
         .WillRepeatedly(Return(false));
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
index 4ee9b0b..c923b2d6 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
@@ -84,7 +84,7 @@
  public:
   EnterpriseDeviceAttributesTest() {
     fake_statistics_provider_.SetMachineStatistic(
-        chromeos::system::kSerialNumberKey, kSerialNumber);
+        chromeos::system::kSerialNumberKeyForTest, kSerialNumber);
     set_exit_when_last_browser_closes(false);
     set_chromeos_user_ = false;
   }
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 7ee175d..21ba554e 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -74,18 +74,6 @@
 
 namespace extensions {
 
-namespace {
-
-// Used in histograms; do not change order.
-enum OffStoreInstallDecision {
-  OnStoreInstall,
-  OffStoreInstallAllowed,
-  OffStoreInstallDisallowed,
-  NumOffStoreInstallDecision
-};
-
-}  // namespace
-
 // static
 scoped_refptr<CrxInstaller> CrxInstaller::CreateSilent(
     ExtensionService* frontend) {
@@ -395,34 +383,17 @@
         l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_NOT_ENABLED));
   }
 
-  if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD) {
-    // TODO(devlin): It appears that these histograms are never logged. We
-    // should either add them to histograms.xml or delete them.
-    const char kHistogramName[] = "Extensions.OffStoreInstallDecisionHard";
-    if (is_gallery_install()) {
-      UMA_HISTOGRAM_ENUMERATION(kHistogramName,
-                                OffStoreInstallDecision::OnStoreInstall,
-                                NumOffStoreInstallDecision);
-    } else if (off_store_install_allow_reason_ != OffStoreInstallDisallowed) {
-      UMA_HISTOGRAM_ENUMERATION(kHistogramName,
-                                OffStoreInstallDecision::OffStoreInstallAllowed,
-                                NumOffStoreInstallDecision);
-      UMA_HISTOGRAM_ENUMERATION("Extensions.OffStoreInstallAllowReason",
-                                off_store_install_allow_reason_,
-                                NumOffStoreInstallAllowReasons);
-    } else {
-      UMA_HISTOGRAM_ENUMERATION(
-          kHistogramName, OffStoreInstallDecision::OffStoreInstallDisallowed,
-          NumOffStoreInstallDecision);
-      // Don't delete source in this case so that the user can install
-      // manually if they want.
-      delete_source_ = false;
-      did_handle_successfully_ = false;
+  if (install_cause_ == extension_misc::INSTALL_CAUSE_USER_DOWNLOAD &&
+      !is_gallery_install() &&
+      off_store_install_allow_reason_ == OffStoreInstallDisallowed) {
+    // Don't delete source in this case so that the user can install
+    // manually if they want.
+    delete_source_ = false;
+    did_handle_successfully_ = false;
 
-      return CrxInstallError(
-          CrxInstallError::ERROR_OFF_STORE,
-          l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE));
-    }
+    return CrxInstallError(
+        CrxInstallError::ERROR_OFF_STORE,
+        l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_DISALLOWED_ON_SITE));
   }
 
   if (extension_->is_app()) {
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc
index 9620496e..08fc33b 100644
--- a/chrome/browser/extensions/extension_service_sync_unittest.cc
+++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/extensions/extension_sync_data.h"
 #include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/test_blacklist.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -78,7 +77,6 @@
 using extensions::ExtensionSystem;
 using extensions::Manifest;
 using extensions::PermissionSet;
-using extensions::ScriptingPermissionsModifier;
 using extensions::WebstorePrivateIsPendingCustodianApprovalFunction;
 using syncer::SyncChange;
 using syncer::SyncChangeList;
@@ -101,9 +99,8 @@
   bool incognito_enabled = false;
   bool remote_install = false;
   bool installed_by_custodian = false;
-  base::Optional<bool> has_all_urls;
   return ExtensionSyncData(extension, enabled, disable_reasons,
-                           incognito_enabled, remote_install, has_all_urls,
+                           incognito_enabled, remote_install,
                            installed_by_custodian);
 }
 
@@ -112,10 +109,9 @@
   bool incognito_enabled = false;
   bool remote_install = false;
   bool installed_by_custodian = false;
-  base::Optional<bool> has_all_urls;
   return ExtensionSyncData(
       extension, enabled, extensions::disable_reason::DISABLE_NONE,
-      incognito_enabled, remote_install, has_all_urls, installed_by_custodian);
+      incognito_enabled, remote_install, installed_by_custodian);
 }
 
 SyncChangeList MakeSyncChangeList(const std::string& id,
@@ -371,7 +367,7 @@
   // Then sync data arrives telling us to disable |good0|.
   ExtensionSyncData disable_good_crx(
       *extension, false, extensions::disable_reason::DISABLE_USER_ACTION, false,
-      false, base::nullopt, false);
+      false, false);
   SyncChangeList list(
       1, disable_good_crx.GetSyncChange(SyncChange::ACTION_UPDATE));
   extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
@@ -565,10 +561,10 @@
   // Now sync data comes in that says to disable good0 and enable good2.
   ExtensionSyncData disable_good0(
       *extension0, false, extensions::disable_reason::DISABLE_USER_ACTION,
-      false, false, base::nullopt, false);
+      false, false, false);
   ExtensionSyncData enable_good2(*extension2, true,
                                  extensions::disable_reason::DISABLE_NONE,
-                                 false, false, base::nullopt, false);
+                                 false, false, false);
   syncer::SyncDataList sync_data;
   sync_data.push_back(disable_good0.GetSyncData());
   sync_data.push_back(enable_good2.GetSyncData());
@@ -620,7 +616,7 @@
     // Disable the extension.
     ExtensionSyncData data(*extension, false,
                            extensions::disable_reason::DISABLE_USER_ACTION,
-                           false, false, base::nullopt, false);
+                           false, false, false);
     SyncChangeList list(1, data.GetSyncChange(SyncChange::ACTION_UPDATE));
 
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
@@ -635,7 +631,7 @@
     // Set incognito enabled to true.
     ExtensionSyncData data(*extension, false,
                            extensions::disable_reason::DISABLE_NONE, true,
-                           false, base::nullopt, false);
+                           false, false);
     SyncChangeList list(1, data.GetSyncChange(SyncChange::ACTION_UPDATE));
 
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
@@ -652,7 +648,7 @@
         *extension, false,
         extensions::disable_reason::DISABLE_USER_ACTION |
             extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE,
-        false, false, base::nullopt, false);
+        false, false, false);
     SyncChangeList list(1, data.GetSyncChange(SyncChange::ACTION_UPDATE));
 
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
@@ -669,7 +665,7 @@
         *extension, false,
         extensions::disable_reason::DISABLE_USER_ACTION |
             extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE,
-        false, false, base::nullopt, false);
+        false, false, false);
     SyncChangeList list(1, data.GetSyncChange(SyncChange::ACTION_DELETE));
 
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
@@ -700,7 +696,6 @@
   EXPECT_EQ(service()->IsExtensionEnabled(good_crx), data->enabled());
   EXPECT_EQ(extensions::util::IsIncognitoEnabled(good_crx, profile()),
             data->incognito_enabled());
-  EXPECT_EQ(base::nullopt, data->all_urls_enabled());
   EXPECT_EQ(data->version(), extension->version());
   EXPECT_EQ(extensions::ManifestURL::GetUpdateURL(extension),
             data->update_url());
@@ -808,7 +803,6 @@
   EXPECT_EQ(service()->IsExtensionEnabled(good_crx), data->enabled());
   EXPECT_EQ(extensions::util::IsIncognitoEnabled(good_crx, profile()),
             data->incognito_enabled());
-  EXPECT_EQ(base::nullopt, data->all_urls_enabled());
   EXPECT_EQ(data->version(), extension->version());
   EXPECT_EQ(extensions::ManifestURL::GetUpdateURL(extension),
             data->update_url());
@@ -851,7 +845,6 @@
     ASSERT_TRUE(data.get());
     EXPECT_TRUE(data->enabled());
     EXPECT_FALSE(data->incognito_enabled());
-    EXPECT_EQ(base::nullopt, data->all_urls_enabled());
   }
 
   service()->DisableExtension(good_crx,
@@ -865,14 +858,9 @@
     ASSERT_TRUE(data.get());
     EXPECT_FALSE(data->enabled());
     EXPECT_FALSE(data->incognito_enabled());
-    EXPECT_EQ(base::nullopt, data->all_urls_enabled());
   }
 
   extensions::util::SetIsIncognitoEnabled(good_crx, profile(), true);
-  ScriptingPermissionsModifier permissions_modifier(
-      profile(), registry()->GetExtensionById(
-                     good_crx, extensions::ExtensionRegistry::EVERYTHING));
-  permissions_modifier.SetAllowedOnAllUrls(false);
   {
     syncer::SyncDataList list =
         extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
@@ -882,11 +870,9 @@
     ASSERT_TRUE(data.get());
     EXPECT_FALSE(data->enabled());
     EXPECT_TRUE(data->incognito_enabled());
-    EXPECT_EQ(base::Optional<bool>(false), data->all_urls_enabled());
   }
 
   service()->EnableExtension(good_crx);
-  permissions_modifier.SetAllowedOnAllUrls(true);
   {
     syncer::SyncDataList list =
         extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
@@ -896,7 +882,6 @@
     ASSERT_TRUE(data.get());
     EXPECT_TRUE(data->enabled());
     EXPECT_TRUE(data->incognito_enabled());
-    EXPECT_EQ(base::Optional<bool>(true), data->all_urls_enabled());
   }
 }
 
@@ -1146,19 +1131,6 @@
   InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
   EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
   EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
-  // Returns a ScriptingPermissionsModifier for the extension. We use this
-  // because various parts of this test reload the extension, making keeping a
-  // ptr to it inviable.
-  auto get_permissions_modifier = [this]() {
-    const Extension* extension = registry()->GetExtensionById(
-        good_crx, extensions::ExtensionRegistry::EVERYTHING);
-    return std::make_unique<ScriptingPermissionsModifier>(profile(), extension);
-  };
-  EXPECT_FALSE(get_permissions_modifier()->HasSetAllowedOnAllUrls());
-  const bool kDefaultAllowedScripting =
-      ScriptingPermissionsModifier::DefaultAllowedOnAllUrls();
-  EXPECT_EQ(kDefaultAllowedScripting,
-            get_permissions_modifier()->IsAllowedOnAllUrls());
 
   sync_pb::EntitySpecifics specifics;
   sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
@@ -1174,9 +1146,6 @@
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_FALSE(service()->IsExtensionEnabled(good_crx));
     EXPECT_FALSE(extensions::util::IsIncognitoEnabled(good_crx, profile()));
-    EXPECT_FALSE(get_permissions_modifier()->HasSetAllowedOnAllUrls());
-    EXPECT_EQ(kDefaultAllowedScripting,
-              get_permissions_modifier()->IsAllowedOnAllUrls());
   }
 
   {
@@ -1205,29 +1174,12 @@
 
   {
     ext_specifics->set_enabled(true);
-    ext_specifics->set_all_urls_enabled(!kDefaultAllowedScripting);
 
     SyncChangeList list =
         MakeSyncChangeList(good_crx, specifics, SyncChange::ACTION_UPDATE);
 
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
     EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
-    EXPECT_TRUE(get_permissions_modifier()->HasSetAllowedOnAllUrls());
-    EXPECT_EQ(!kDefaultAllowedScripting,
-              get_permissions_modifier()->IsAllowedOnAllUrls());
-  }
-
-  {
-    ext_specifics->set_all_urls_enabled(kDefaultAllowedScripting);
-
-    SyncChangeList list =
-        MakeSyncChangeList(good_crx, specifics, SyncChange::ACTION_UPDATE);
-
-    extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
-    EXPECT_TRUE(service()->IsExtensionEnabled(good_crx));
-    EXPECT_TRUE(get_permissions_modifier()->HasSetAllowedOnAllUrls());
-    EXPECT_EQ(kDefaultAllowedScripting,
-              get_permissions_modifier()->IsAllowedOnAllUrls());
   }
 
   EXPECT_FALSE(service()->pending_extension_manager()->IsIdPending(good_crx));
@@ -2563,47 +2515,6 @@
       registry()->GenerateInstalledExtensionsSet()->Contains(extension_ids[1]));
 }
 
-TEST_F(ExtensionServiceSyncTest, SyncExtensionHasAllhostsWithheld) {
-  InitializeEmptyExtensionService();
-  StartSyncing(syncer::EXTENSIONS);
-
-  // Create an extension that needs all-hosts.
-  const std::string kName("extension");
-  scoped_refptr<const Extension> extension =
-      extensions::ExtensionBuilder(kName)
-          .SetLocation(Manifest::INTERNAL)
-          .AddPermission("*://*/*")
-          .Build();
-
-  // Install and enable it.
-  service()->AddExtension(extension.get());
-  service()->GrantPermissionsAndEnableExtension(extension.get());
-  const std::string id = extension->id();
-  EXPECT_TRUE(registry()->enabled_extensions().GetByID(id));
-
-  // Simulate a sync node coming in where the extension had all-hosts withheld.
-  // This means that it should have all-hosts withheld on this machine, too.
-  sync_pb::EntitySpecifics specifics;
-  sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
-  ext_specifics->set_id(id);
-  ext_specifics->set_name(kName);
-  ext_specifics->set_version("1.0");
-  ext_specifics->set_all_urls_enabled(false);
-  ext_specifics->set_enabled(true);
-
-  SyncChangeList list =
-      MakeSyncChangeList(id, specifics, SyncChange::ACTION_UPDATE);
-
-  extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
-
-  const Extension* enabled_extension =
-      registry()->enabled_extensions().GetByID(id);
-  ASSERT_TRUE(enabled_extension);
-  ScriptingPermissionsModifier modifier(profile(), enabled_extension);
-  EXPECT_FALSE(modifier.IsAllowedOnAllUrls());
-  EXPECT_TRUE(modifier.HasSetAllowedOnAllUrls());
-}
-
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 // Tests sync behavior in the case of an item that starts out as an app and
diff --git a/chrome/browser/extensions/extension_sync_data.cc b/chrome/browser/extensions/extension_sync_data.cc
index f6b4ed0..2b24159 100644
--- a/chrome/browser/extensions/extension_sync_data.cc
+++ b/chrome/browser/extensions/extension_sync_data.cc
@@ -87,14 +87,12 @@
                                      int disable_reasons,
                                      bool incognito_enabled,
                                      bool remote_install,
-                                     base::Optional<bool> all_urls_enabled,
                                      bool installed_by_custodian)
     : ExtensionSyncData(extension,
                         enabled,
                         disable_reasons,
                         incognito_enabled,
                         remote_install,
-                        all_urls_enabled,
                         installed_by_custodian,
                         StringOrdinal(),
                         StringOrdinal(),
@@ -105,7 +103,6 @@
                                      int disable_reasons,
                                      bool incognito_enabled,
                                      bool remote_install,
-                                     base::Optional<bool> all_urls_enabled,
                                      bool installed_by_custodian,
                                      const StringOrdinal& app_launch_ordinal,
                                      const StringOrdinal& page_ordinal,
@@ -118,7 +115,6 @@
       disable_reasons_(disable_reasons),
       incognito_enabled_(incognito_enabled),
       remote_install_(remote_install),
-      all_urls_enabled_(all_urls_enabled),
       installed_by_custodian_(installed_by_custodian),
       version_(extension.from_bookmark() ? base::Version("0")
                                          : extension.version()),
@@ -196,8 +192,6 @@
     specifics->set_disable_reasons(disable_reasons_);
   specifics->set_incognito_enabled(incognito_enabled_);
   specifics->set_remote_install(remote_install_);
-  if (all_urls_enabled_.has_value())
-    specifics->set_all_urls_enabled(*all_urls_enabled_);
   specifics->set_installed_by_custodian(installed_by_custodian_);
   specifics->set_name(name_);
 }
@@ -278,13 +272,6 @@
   supports_disable_reasons_ = specifics.has_disable_reasons();
   disable_reasons_ = specifics.disable_reasons();
   incognito_enabled_ = specifics.incognito_enabled();
-  if (specifics.has_all_urls_enabled()) {
-    all_urls_enabled_ = specifics.all_urls_enabled();
-  } else {
-    // Set this explicitly (even though it's the default) on the offchance
-    // that someone is re-using an ExtensionSyncData object.
-    all_urls_enabled_ = base::nullopt;
-  }
   remote_install_ = specifics.remote_install();
   installed_by_custodian_ = specifics.installed_by_custodian();
   name_ = specifics.name();
diff --git a/chrome/browser/extensions/extension_sync_data.h b/chrome/browser/extensions/extension_sync_data.h
index 9a17b64..9f79c87 100644
--- a/chrome/browser/extensions/extension_sync_data.h
+++ b/chrome/browser/extensions/extension_sync_data.h
@@ -49,7 +49,6 @@
                     int disable_reasons,
                     bool incognito_enabled,
                     bool remote_install,
-                    base::Optional<bool> all_urls_enabled,
                     bool installed_by_custodian);
   // App constructor.
   ExtensionSyncData(const Extension& extension,
@@ -57,7 +56,6 @@
                     int disable_reasons,
                     bool incognito_enabled,
                     bool remote_install,
-                    base::Optional<bool> all_urls_enabled,
                     bool installed_by_custodian,
                     const syncer::StringOrdinal& app_launch_ordinal,
                     const syncer::StringOrdinal& page_ordinal,
@@ -90,7 +88,6 @@
   int disable_reasons() const { return disable_reasons_; }
   bool incognito_enabled() const { return incognito_enabled_; }
   bool remote_install() const { return remote_install_; }
-  base::Optional<bool> all_urls_enabled() const { return all_urls_enabled_; }
   bool installed_by_custodian() const { return installed_by_custodian_; }
 
   // Version-dependent properties (i.e., should be used only when the
@@ -156,7 +153,6 @@
   int disable_reasons_;
   bool incognito_enabled_;
   bool remote_install_;
-  base::Optional<bool> all_urls_enabled_;
   bool installed_by_custodian_;
   base::Version version_;
   GURL update_url_;
diff --git a/chrome/browser/extensions/extension_sync_data_unittest.cc b/chrome/browser/extensions/extension_sync_data_unittest.cc
index a823bddc..ba465d0 100644
--- a/chrome/browser/extensions/extension_sync_data_unittest.cc
+++ b/chrome/browser/extensions/extension_sync_data_unittest.cc
@@ -59,9 +59,6 @@
   EXPECT_EQ(input.incognito_enabled(), output.incognito_enabled());
   EXPECT_EQ(input.remote_install(), output.remote_install());
   EXPECT_EQ(input.installed_by_custodian(), output.installed_by_custodian());
-  EXPECT_EQ(input.has_all_urls_enabled(), output.has_all_urls_enabled());
-  if (input.has_all_urls_enabled())
-    EXPECT_EQ(input.all_urls_enabled(), output.all_urls_enabled());
 }
 
 // Serializes an ExtensionSyncData into a protobuf structure and back again, and
@@ -78,7 +75,6 @@
   EXPECT_EQ(input.incognito_enabled(), output->incognito_enabled());
   EXPECT_EQ(input.remote_install(), output->remote_install());
   EXPECT_EQ(input.installed_by_custodian(), output->installed_by_custodian());
-  EXPECT_EQ(input.all_urls_enabled(), output->all_urls_enabled());
   EXPECT_EQ(input.version(), output->version());
   EXPECT_EQ(input.update_url(), output->update_url());
   EXPECT_EQ(input.name(), output->name());
@@ -100,7 +96,6 @@
   extension_specifics->set_incognito_enabled(true);
   extension_specifics->set_remote_install(false);
   extension_specifics->set_installed_by_custodian(false);
-  extension_specifics->set_all_urls_enabled(true);
   extension_specifics->set_version(kVersion);
   extension_specifics->set_name(kName);
 
@@ -117,35 +112,21 @@
   EXPECT_FALSE(extension_sync_data.enabled());
   EXPECT_EQ(true, extension_sync_data.incognito_enabled());
   EXPECT_FALSE(extension_sync_data.remote_install());
-  EXPECT_EQ(base::Optional<bool>(true), extension_sync_data.all_urls_enabled());
   EXPECT_EQ(base::Version(kVersion), extension_sync_data.version());
   EXPECT_EQ(std::string(kName), extension_sync_data.name());
 
   // Check the serialize-deserialize process for ExtensionSyncData to proto.
   SyncDataToProtobufEqual(extension_sync_data);
 
-  // The most important thing to test is the "all urls" bit, since it is a
-  // tri-state boolean (and thus has more logic). Also flip another bit for a
-  // sanity check.
-  extension_specifics->set_all_urls_enabled(false);
+  // Flip a bit and verify the result is correct.
   extension_specifics->set_incognito_enabled(false);
   ProtobufToSyncDataEqual(entity);
 
   extension_sync_data.PopulateFromExtensionSpecifics(*extension_specifics);
-  EXPECT_EQ(base::Optional<bool>(false),
-            extension_sync_data.all_urls_enabled());
   EXPECT_FALSE(extension_sync_data.incognito_enabled());
 
   SyncDataToProtobufEqual(extension_sync_data);
-
-  extension_specifics->clear_all_urls_enabled();
   ProtobufToSyncDataEqual(entity);
-
-  extension_sync_data.PopulateFromExtensionSpecifics(*extension_specifics);
-  EXPECT_FALSE(extension_specifics->has_all_urls_enabled());
-  EXPECT_FALSE(extension_sync_data.all_urls_enabled().has_value());
-
-  SyncDataToProtobufEqual(extension_sync_data);
 }
 
 class AppSyncDataTest : public testing::Test {
@@ -162,7 +143,6 @@
     extension_specifics->set_disable_reasons(kValidDisableReasons);
     extension_specifics->set_incognito_enabled(true);
     extension_specifics->set_remote_install(false);
-    extension_specifics->set_all_urls_enabled(true);
     extension_specifics->set_installed_by_custodian(false);
     extension_specifics->set_name(kName);
   }
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 9784710..57c43bb 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/extensions/extension_sync_service_factory.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/launch_util.h"
-#include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/glue/sync_start_util.h"
 #include "chrome/common/buildflags.h"
@@ -51,26 +50,6 @@
 
 namespace {
 
-// Returns the pref value for "all urls enabled" for the given extension id.
-base::Optional<bool> GetAllowedOnAllUrlsValue(
-    const Extension& extension,
-    content::BrowserContext* context) {
-  extensions::ScriptingPermissionsModifier permissions_modifier(context,
-                                                                &extension);
-  bool allowed_on_all_urls = permissions_modifier.IsAllowedOnAllUrls();
-  // If the extension is not allowed on all urls (which is not the default),
-  // then we have to sync the preference.
-  if (!allowed_on_all_urls)
-    return false;
-
-  // If the user has explicitly set a value, then we sync it.
-  if (permissions_modifier.HasSetAllowedOnAllUrls())
-    return true;
-
-  // Otherwise, unset.
-  return base::nullopt;
-}
-
 // Returns true if the sync type of |extension| matches |type|.
 bool IsCorrectSyncType(const Extension& extension, syncer::ModelType type) {
   return (type == syncer::EXTENSIONS && extension.is_extension()) ||
@@ -271,23 +250,21 @@
   bool incognito_enabled = extensions::util::IsIncognitoEnabled(id, profile_);
   bool remote_install = extension_prefs->HasDisableReason(
       id, extensions::disable_reason::DISABLE_REMOTE_INSTALL);
-  base::Optional<bool> allowed_on_all_url =
-      GetAllowedOnAllUrlsValue(extension, profile_);
   bool installed_by_custodian =
       extensions::util::WasInstalledByCustodian(id, profile_);
   AppSorting* app_sorting = ExtensionSystem::Get(profile_)->app_sorting();
 
-  ExtensionSyncData result = extension.is_app()
-      ? ExtensionSyncData(
-            extension, enabled, disable_reasons, incognito_enabled,
-            remote_install, allowed_on_all_url,
-            installed_by_custodian,
-            app_sorting->GetAppLaunchOrdinal(id),
-            app_sorting->GetPageOrdinal(id),
-            extensions::GetLaunchTypePrefValue(extension_prefs, id))
-      : ExtensionSyncData(
-            extension, enabled, disable_reasons, incognito_enabled,
-            remote_install, allowed_on_all_url, installed_by_custodian);
+  ExtensionSyncData result =
+      extension.is_app()
+          ? ExtensionSyncData(
+                extension, enabled, disable_reasons, incognito_enabled,
+                remote_install, installed_by_custodian,
+                app_sorting->GetAppLaunchOrdinal(id),
+                app_sorting->GetPageOrdinal(id),
+                extensions::GetLaunchTypePrefValue(extension_prefs, id))
+          : ExtensionSyncData(extension, enabled, disable_reasons,
+                              incognito_enabled, remote_install,
+                              installed_by_custodian);
 
   // If there's a pending update, send the new version to sync instead of the
   // installed one.
@@ -481,13 +458,6 @@
       id, profile_, extension_sync_data.incognito_enabled());
   extension = nullptr;  // No longer safe to use.
 
-  // Update the all urls flag.
-  if (extension_sync_data.all_urls_enabled().has_value()) {
-    bool allowed = *extension_sync_data.all_urls_enabled();
-    extensions::ScriptingPermissionsModifier::SetAllowedOnAllUrlsForSync(
-        allowed, profile_, id);
-  }
-
   // Set app-specific data.
   if (extension_sync_data.is_app()) {
     if (extension_sync_data.app_launch_ordinal().IsValid() &&
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
index efa3be4..12c12d8 100644
--- a/chrome/browser/extensions/extension_sync_service.h
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -42,8 +42,7 @@
 
   // Notifies Sync (if needed) of a newly-installed extension or a change to
   // an existing extension. Call this when you change an extension setting that
-  // is synced as part of ExtensionSyncData (e.g. incognito_enabled or
-  // all_urls_enabled).
+  // is synced as part of ExtensionSyncData (e.g. incognito_enabled).
   void SyncExtensionChangeIfNeeded(const extensions::Extension& extension);
 
   // Returns whether the extension with the given |id| will be re-enabled once
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 38f1910..00ce7a6 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1927,27 +1927,6 @@
 const char kChromeDuplexDescription[] =
     "Enables Chrome Duplex, split toolbar Chrome Home, on Android.";
 
-const char kChromeHomeEnableSurveyName[] = "Enable Chrome Home survey";
-const char kChromeHomeEnableSurveyDescription[] =
-    "If enabled, the survey process will allow surveys using sample "
-    "parameters.";
-
-const char kChromeHomeInactivitySheetExpansionName[] =
-    "Expansion of Chrome Home bottom sheet on startup";
-const char kChromeHomeInactivitySheetExpansionDescription[] =
-    "Expand bottom sheet on startup in Chrome Home after a period of"
-    " inactivity.";
-
-const char kChromeHomePersistentIphName[] = "Chrome Home Persistent Iph";
-const char kChromeHomePersistentIphDescription[] =
-    "Wait to dismiss the Chrome Home IPH until the user inteacts with the "
-    "toolbar or a timer expires.";
-
-const char kChromeHomePullToRefreshIphAtTopName[] =
-    "Chrome Home Pull-To-Refresh Iph At Top";
-const char kChromeHomePullToRefreshIphAtTopDescription[] =
-    "Show the Chrome Home pull-to-refresh help bubble at the top of the screen";
-
 const char kChromeHomeSwipeLogicName[] = "Chrome Home Swipe Logic";
 const char kChromeHomeSwipeLogicDescription[] =
     "Various swipe logic options for Chrome Home for sheet expansion.";
@@ -2386,6 +2365,10 @@
 const char kVrBrowsingNativeAndroidUiDescription[] =
     "Enable Android UI elements in VR.";
 
+const char kVrBrowsingTabsViewName[] = "VR browsing tabs view";
+const char kVrBrowsingTabsViewDescription[] =
+    "Enable tab overview (tab switcher) in VR.";
+
 const char kThirdPartyDoodlesName[] =
     "Enable Doodles for third-party search engines";
 const char kThirdPartyDoodlesDescription[] =
@@ -3170,12 +3153,6 @@
 const char kAshEnablePersistentWindowBoundsDescription[] =
     "Enable persistent window bounds in multi-displays scenario.";
 
-const char kAshEnableModeSpecificPowerButtonName[] =
-    "Enable mode-specific power button behavior.";
-const char kAshEnableModeSpecificPowerButtonDescription[] =
-    "Enable mode-specific power button behavior. While in tablet mode, tapping "
-    "the power button turns the display off.";
-
 const char kAshEnableTrilinearFilteringName[] = "Enable trilinear filtering.";
 const char kAshEnableTrilinearFilteringDescription[] =
     "Enable trilinear filtering.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c6461aee..d328309 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1178,18 +1178,6 @@
 extern const char kChromeDuplexName[];
 extern const char kChromeDuplexDescription[];
 
-extern const char kChromeHomeEnableSurveyName[];
-extern const char kChromeHomeEnableSurveyDescription[];
-
-extern const char kChromeHomeInactivitySheetExpansionName[];
-extern const char kChromeHomeInactivitySheetExpansionDescription[];
-
-extern const char kChromeHomePersistentIphName[];
-extern const char kChromeHomePersistentIphDescription[];
-
-extern const char kChromeHomePullToRefreshIphAtTopName[];
-extern const char kChromeHomePullToRefreshIphAtTopDescription[];
-
 extern const char kChromeHomeSwipeLogicName[];
 extern const char kChromeHomeSwipeLogicDescription[];
 extern const char kChromeHomeSwipeLogicRestrictArea[];
@@ -1448,6 +1436,9 @@
 extern const char kVrBrowsingNativeAndroidUiName[];
 extern const char kVrBrowsingNativeAndroidUiDescription[];
 
+extern const char kVrBrowsingTabsViewName[];
+extern const char kVrBrowsingTabsViewDescription[];
+
 extern const char kThirdPartyDoodlesName[];
 extern const char kThirdPartyDoodlesDescription[];
 
@@ -1951,9 +1942,6 @@
 extern const char kAshEnablePersistentWindowBoundsName[];
 extern const char kAshEnablePersistentWindowBoundsDescription[];
 
-extern const char kAshEnableModeSpecificPowerButtonName[];
-extern const char kAshEnableModeSpecificPowerButtonDescription[];
-
 extern const char kAshEnableTrilinearFilteringName[];
 extern const char kAshEnableTrilinearFilteringDescription[];
 
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index e47c404..4397c4a 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -803,9 +803,15 @@
 }
 
 IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, Playback_Encryption_CBCS) {
+  // 'cbcs' decryption is only supported on CDM 10 or later as long as
+  // the appropriate buildflag is enabled.
+  std::string expected_result =
+      GetCdmInterfaceVersion() >= 10 && BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME)
+          ? media::kEnded
+          : media::kError;
   TestMp4EncryptionPlayback(kExternalClearKeyKeySystem,
                             "bear-640x360-v_frag-cbcs.mp4", kMp4Avc1VideoOnly,
-                            media::kError);
+                            expected_result);
 }
 
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index 1d281b0..f649626 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -606,6 +606,124 @@
   }
 }
 
+// Test certs cannot currently be installed on OSX with the network service
+// enabled.
+// TODO(mmenke): Once that is fixed, enable this test on OSX.
+// See https://crbug.com/757088
+#if !defined(OS_MACOSX)
+
+// Visits a URL with an HSTS header, and makes sure it is respected.
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, PRE_Hsts) {
+  net::test_server::EmbeddedTestServer ssl_server(
+      net::test_server::EmbeddedTestServer::TYPE_HTTPS);
+  ssl_server.SetSSLConfig(
+      net::test_server::EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
+  ssl_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  ASSERT_TRUE(ssl_server.Start());
+
+  // Make a request whose response has an STS header.
+  std::unique_ptr<network::ResourceRequest> request =
+      std::make_unique<network::ResourceRequest>();
+  request->url = ssl_server.GetURL(
+      "/set-header?Strict-Transport-Security: max-age%3D600000");
+
+  content::SimpleURLLoaderTestHelper simple_loader_helper;
+  std::unique_ptr<network::SimpleURLLoader> simple_loader =
+      network::SimpleURLLoader::Create(std::move(request),
+                                       TRAFFIC_ANNOTATION_FOR_TESTS);
+  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      loader_factory(), simple_loader_helper.GetCallback());
+  simple_loader_helper.WaitForCallback();
+
+  EXPECT_EQ(net::OK, simple_loader->NetError());
+  ASSERT_TRUE(simple_loader->ResponseInfo()->headers);
+  EXPECT_TRUE(simple_loader->ResponseInfo()->headers->HasHeaderValue(
+      "Strict-Transport-Security", "max-age=600000"));
+
+  // Make a cache-only request to make sure the HSTS entry is respected. Using a
+  // cache-only request both prevents the result from being cached, and makes
+  // the check identical to the one in the next test, which is run after the
+  // test server has been shut down.
+  GURL exected_ssl_url = ssl_server.base_url();
+  GURL::Replacements replacements;
+  replacements.SetSchemeStr("http");
+  GURL start_url = exected_ssl_url.ReplaceComponents(replacements);
+
+  request = std::make_unique<network::ResourceRequest>();
+  request->url = start_url;
+  request->load_flags = net::LOAD_ONLY_FROM_CACHE;
+
+  content::SimpleURLLoaderTestHelper simple_loader_helper2;
+  simple_loader = network::SimpleURLLoader::Create(
+      std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS);
+  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      loader_factory(), simple_loader_helper2.GetCallback());
+  simple_loader_helper2.WaitForCallback();
+  EXPECT_FALSE(simple_loader_helper2.response_body());
+  EXPECT_EQ(exected_ssl_url, simple_loader->GetFinalURL());
+
+  // Write the URL with HSTS information to a file, so it can be loaded in the
+  // next test. Have to use a file for this, since the server's port is random.
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  base::FilePath save_url_file_path = browser()->profile()->GetPath().Append(
+      FILE_PATH_LITERAL("url_for_test.txt"));
+  std::string file_data = start_url.spec();
+  ASSERT_EQ(
+      static_cast<int>(file_data.length()),
+      base::WriteFile(save_url_file_path, file_data.data(), file_data.size()));
+}
+
+// Checks if the HSTS information from the last test is still available after a
+// restart.
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, Hsts) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  base::FilePath save_url_file_path = browser()->profile()->GetPath().Append(
+      FILE_PATH_LITERAL("url_for_test.txt"));
+  std::string file_data;
+  ASSERT_TRUE(ReadFileToString(save_url_file_path, &file_data));
+  GURL start_url = GURL(file_data);
+
+  // Unfortunately, loading HSTS information is loaded asynchronously from
+  // disk, so there's no way to guarantee it has loaded by the time a
+  // request is made. As a result, may have to try multiple times to verify that
+  // cached HSTS information has been loaded, when it's stored on disk.
+  while (true) {
+    std::unique_ptr<network::ResourceRequest> request =
+        std::make_unique<network::ResourceRequest>();
+    request->url = start_url;
+    request->load_flags = net::LOAD_ONLY_FROM_CACHE;
+
+    content::SimpleURLLoaderTestHelper simple_loader_helper;
+    std::unique_ptr<network::SimpleURLLoader> simple_loader =
+        network::SimpleURLLoader::Create(std::move(request),
+                                         TRAFFIC_ANNOTATION_FOR_TESTS);
+    simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+        loader_factory(), simple_loader_helper.GetCallback());
+    simple_loader_helper.WaitForCallback();
+    EXPECT_FALSE(simple_loader_helper.response_body());
+
+    // HSTS information is currently stored on disk if-and-only-if there's an
+    // on-disk HTTP cache.
+    if (GetHttpCacheType() == StorageType::kDisk) {
+      GURL::Replacements replacements;
+      replacements.SetSchemeStr("https");
+      GURL expected_https_url = start_url.ReplaceComponents(replacements);
+      // The file may not have been loaded yet, so if the cached HSTS
+      // information was not respected, try again.
+      if (expected_https_url != simple_loader->GetFinalURL())
+        continue;
+      EXPECT_EQ(expected_https_url, simple_loader->GetFinalURL());
+      break;
+    } else {
+      EXPECT_EQ(start_url, simple_loader->GetFinalURL());
+      break;
+    }
+  }
+}
+
+#endif  // !defined(OS_MACOSX)
+
 IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest, ProxyConfig) {
   SetProxyPref(embedded_test_server()->host_port_pair());
   TestProxyConfigured();
@@ -968,6 +1086,7 @@
 }
 
 // |NetworkServiceTestHelper| doesn't work on browser_tests on OSX.
+// See https://crbug.com/757088
 #if defined(OS_MACOSX)
 // Instiates tests with a prefix indicating which NetworkContext is being
 // tested, and a suffix of "/0" if the network service is disabled and "/1" if
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 5de3140..707cb4e 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -209,6 +209,8 @@
       network_context_params->restore_old_session_cookies = false;
       network_context_params->persist_session_cookies = false;
     }
+
+    network_context_params->transport_security_persister_path = path;
   }
 
   // NOTE(mmenke): Keep these protocol handlers and
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 80411b4..842dc8b 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -1632,6 +1632,61 @@
 
 #endif  // defined(OS_MACOSX)
 
+IN_PROC_BROWSER_TEST_P(PDFExtensionHitTestTest, MouseLeave) {
+  GURL url = embedded_test_server()->GetURL("/pdf/pdf_embed.html");
+
+  // Load page with embedded PDF and make sure it succeeds.
+  ASSERT_TRUE(LoadPdf(url));
+  WebContents* guest_contents = nullptr;
+  WebContents* embedder_contents = GetActiveWebContents();
+  content::BrowserPluginGuestManager* guest_manager =
+      embedder_contents->GetBrowserContext()->GetGuestManager();
+  ASSERT_NO_FATAL_FAILURE(guest_manager->ForEachGuest(
+      embedder_contents, base::Bind(&GetGuestCallback, &guest_contents)));
+  ASSERT_NE(nullptr, guest_contents);
+#if defined(USE_AURA)
+  // TODO(wjmaclean): In theory this should be used to make sure the hit testing
+  // for routing to the guest process works as intended. Not sure if not having
+  // this on Mac is an issue.
+  content::WaitForGuestSurfaceReady(guest_contents);
+#endif
+  gfx::Point point_in_parent(250, 25);
+  gfx::Point point_in_pdf(250, 250);
+
+  // Inject script to count MouseLeaves in the PDF.
+  ASSERT_TRUE(content::ExecuteScript(
+      guest_contents,
+      "var enter_count = 0;\n"
+      "var leave_count = 0;\n"
+      "document.addEventListener('mouseenter', function (){\n"
+      "  enter_count++;"
+      "});\n"
+      "document.addEventListener('mouseleave', function (){\n"
+      "  leave_count++;"
+      "});"));
+
+  // Inject some MouseMoves to invoke a MouseLeave in the PDF.
+  content::SimulateRoutedMouseEvent(
+      embedder_contents, blink::WebInputEvent::kMouseMove, point_in_parent);
+  content::SimulateRoutedMouseEvent(
+      embedder_contents, blink::WebInputEvent::kMouseMove, point_in_pdf);
+  content::SimulateRoutedMouseEvent(
+      embedder_contents, blink::WebInputEvent::kMouseMove, point_in_parent);
+
+  // Verify MouseEnter, MouseLeave received.
+  int leave_count = 0;
+  do {
+    ASSERT_TRUE(ExecuteScriptAndExtractInt(
+        guest_contents, "window.domAutomationController.send(leave_count);",
+        &leave_count));
+  } while (!leave_count);
+  int enter_count = 0;
+  ASSERT_TRUE(ExecuteScriptAndExtractInt(
+      guest_contents, "window.domAutomationController.send(enter_count);",
+      &enter_count));
+  EXPECT_EQ(1, enter_count);
+}
+
 IN_PROC_BROWSER_TEST_P(PDFExtensionHitTestTest, ContextMenuCoordinates) {
   GURL url = embedded_test_server()->GetURL("/pdf/pdf_embed.html");
 
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index bd9dd3e..38f4a7b3 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -1101,9 +1101,6 @@
 
   io_thread->SetUpProxyService(builder.get());
 
-  if (!IsOffTheRecord())
-    builder->set_transport_security_persister_path(profile_params_->path);
-
   // Take ownership over these parameters.
   cookie_settings_ = profile_params_->cookie_settings;
   host_content_settings_map_ = profile_params_->host_content_settings_map;
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc
new file mode 100644
index 0000000..2991e1d
--- /dev/null
+++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.cc
@@ -0,0 +1,129 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "third_party/leveldatabase/env_chromium.h"
+#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+// Try to open a database (creates it if necessary).
+// TODO(sebmarchand): Turn this into a callback that runs in TaskScheduler with
+// MayBlock().
+std::unique_ptr<leveldb::DB> OpenDatabase(const base::FilePath& db_path) {
+  base::AssertBlockingAllowed();
+  leveldb_env::Options options;
+  options.create_if_missing = true;
+  std::unique_ptr<leveldb::DB> db;
+  leveldb::Status status =
+      leveldb_env::OpenDB(options, db_path.AsUTF8Unsafe(), &db);
+  // TODO(sebmarchand): Do more validation here, try to repair the database if
+  // it's corrupt and report some metrics.
+  if (!status.ok()) {
+    LOG(ERROR) << "Unable to open the Site Characteristics database: "
+               << status.ToString();
+    return nullptr;
+  }
+  return db;
+}
+
+}  // namespace
+
+// static:
+std::unique_ptr<LevelDBSiteCharacteristicsDatabase>
+LevelDBSiteCharacteristicsDatabase::OpenOrCreateDatabase(
+    const base::FilePath& db_path) {
+  std::unique_ptr<leveldb::DB> db = OpenDatabase(db_path);
+  if (!db)
+    return nullptr;
+  LevelDBSiteCharacteristicsDatabase* characteristics_db =
+      new LevelDBSiteCharacteristicsDatabase(std::move(db), db_path);
+  return base::WrapUnique(characteristics_db);
+}
+
+LevelDBSiteCharacteristicsDatabase::~LevelDBSiteCharacteristicsDatabase() =
+    default;
+
+void LevelDBSiteCharacteristicsDatabase::ReadSiteCharacteristicsFromDB(
+    const std::string& site_origin,
+    LocalSiteCharacteristicsDatabase::ReadSiteCharacteristicsFromDBCallback
+        callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::AssertBlockingAllowed();
+  std::string protobuf_value;
+  // TODO(sebmarchand): Move this to a separate thread as this is blocking.
+  leveldb::Status s = db_->Get(read_options_, site_origin, &protobuf_value);
+  base::Optional<SiteCharacteristicsProto> site_characteristic_proto;
+  if (s.ok()) {
+    site_characteristic_proto = SiteCharacteristicsProto();
+    if (!site_characteristic_proto->ParseFromString(protobuf_value)) {
+      site_characteristic_proto = base::nullopt;
+      LOG(ERROR) << "Error while trying to parse a SiteCharacteristicsProto "
+                 << "protobuf.";
+    }
+  }
+  std::move(callback).Run(std::move(site_characteristic_proto));
+}
+
+void LevelDBSiteCharacteristicsDatabase::WriteSiteCharacteristicsIntoDB(
+    const std::string& site_origin,
+    const SiteCharacteristicsProto& site_characteristic_proto) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::AssertBlockingAllowed();
+  // TODO(sebmarchand): Move this to a separate thread as this is blocking.
+  leveldb::Status s = db_->Put(write_options_, site_origin,
+                               site_characteristic_proto.SerializeAsString());
+  if (!s.ok()) {
+    LOG(ERROR) << "Error while inserting an element in the site characteristic "
+               << "database: " << s.ToString();
+  }
+}
+
+void LevelDBSiteCharacteristicsDatabase::RemoveSiteCharacteristicsFromDB(
+    const std::vector<std::string>& site_origins) {
+  base::AssertBlockingAllowed();
+  // TODO(sebmarchand): Move this to a separate thread as this is blocking.
+  leveldb::WriteBatch batch;
+  for (const auto iter : site_origins)
+    batch.Delete(iter);
+  leveldb::Status status = db_->Write(write_options_, &batch);
+  if (!status.ok()) {
+    LOG(WARNING) << "Failed to remove some entries from the site "
+                 << "characteristics database: " << status.ToString();
+  }
+}
+
+void LevelDBSiteCharacteristicsDatabase::ClearDatabase() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::AssertBlockingAllowed();
+  // TODO(sebmarchand): Move this to a separate thread as this is blocking.
+  leveldb_env::Options options;
+  db_.reset();
+  leveldb::Status status = leveldb::DestroyDB(db_path_.AsUTF8Unsafe(), options);
+  if (status.ok()) {
+    db_ = OpenDatabase(db_path_);
+  } else {
+    LOG(WARNING) << "Failed to destroy the site characteristics database: "
+                 << status.ToString();
+  }
+}
+
+LevelDBSiteCharacteristicsDatabase::LevelDBSiteCharacteristicsDatabase(
+    std::unique_ptr<leveldb::DB> db,
+    const base::FilePath& db_path)
+    : db_(std::move(db)), db_path_(db_path) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Setting |sync| to false might cause some data loss if the system crashes
+  // but it'll make the write operations faster (no data will be loss if only
+  // the process crashes).
+  write_options_.sync = false;
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h
new file mode 100644
index 0000000..280cbfe
--- /dev/null
+++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_LEVELDB_SITE_CHARACTERISTICS_DATABASE_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_LEVELDB_SITE_CHARACTERISTICS_DATABASE_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_database.h"
+#include "third_party/leveldatabase/src/include/leveldb/db.h"
+
+namespace resource_coordinator {
+
+// Manages a LevelDB database used by a site characteristic data store.
+// TODO(sebmarchand):
+//   - Constraint the size of the database: Use a background task to trim the
+//     database if it becomes too big and ensure that this fail nicely when the
+//     disk is full.
+//   - Batch the write operations to reduce the number of I/O events.
+//   - Move the I/O operations to a different thread.
+//
+// All the DB operations need to be done on the I/O thread.
+class LevelDBSiteCharacteristicsDatabase
+    : public LocalSiteCharacteristicsDatabase {
+ public:
+  // Initialize the database, create it if it doesn't exist or just open it if
+  // it does. The on-disk database will be stored in |db_path|.
+  static std::unique_ptr<LevelDBSiteCharacteristicsDatabase>
+  OpenOrCreateDatabase(const base::FilePath& db_path);
+
+  ~LevelDBSiteCharacteristicsDatabase() override;
+
+  // LocalSiteCharacteristicDatabase:
+  void ReadSiteCharacteristicsFromDB(
+      const std::string& site_origin,
+      LocalSiteCharacteristicsDatabase::ReadSiteCharacteristicsFromDBCallback
+          callback) override;
+  void WriteSiteCharacteristicsIntoDB(
+      const std::string& site_origin,
+      const SiteCharacteristicsProto& site_characteristic_proto) override;
+  void RemoveSiteCharacteristicsFromDB(
+      const std::vector<std::string>& site_origin) override;
+  void ClearDatabase() override;
+
+ private:
+  LevelDBSiteCharacteristicsDatabase(std::unique_ptr<leveldb::DB> db,
+                                     const base::FilePath& db_path);
+
+  // The connection to the LevelDB database.
+  std::unique_ptr<leveldb::DB> db_;
+  // The options to be used for all database read operations.
+  leveldb::ReadOptions read_options_;
+  // The options to be used for all database write operations.
+  leveldb::WriteOptions write_options_;
+
+  // The on disk location of the database.
+  const base::FilePath db_path_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  DISALLOW_COPY_AND_ASSIGN(LevelDBSiteCharacteristicsDatabase);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_LEVELDB_SITE_CHARACTERISTICS_DATABASE_H_
diff --git a/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc
new file mode 100644
index 0000000..2362938
--- /dev/null
+++ b/chrome/browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/resource_coordinator/site_characteristics.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+const char kOrigin1[] = "foo.com";
+
+// Initialize a SiteCharacteristicsProto object with a test value (the same
+// value is used to initialize all fields).
+void InitSiteCharacteristicProto(SiteCharacteristicsProto* proto,
+                                 ::google::protobuf::int64 test_value) {
+  proto->set_last_loaded(test_value);
+
+  SiteCharacteristicsFeatureProto feature_proto;
+  feature_proto.set_observation_duration(test_value);
+  feature_proto.set_use_timestamp(test_value);
+
+  proto->mutable_updates_favicon_in_background()->CopyFrom(feature_proto);
+  proto->mutable_updates_title_in_background()->CopyFrom(feature_proto);
+  proto->mutable_uses_notifications_in_background()->CopyFrom(feature_proto);
+  proto->mutable_uses_audio_in_background()->CopyFrom(feature_proto);
+}
+
+}  // namespace
+
+class LevelDBSiteCharacteristicsDatabaseTest : public ::testing::Test {
+ public:
+  LevelDBSiteCharacteristicsDatabaseTest() {}
+
+  void SetUp() override {
+    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+    db_ = LevelDBSiteCharacteristicsDatabase::OpenOrCreateDatabase(
+        temp_dir_.GetPath());
+    EXPECT_TRUE(db_);
+  }
+
+  void TearDown() override {
+    db_.reset();
+    EXPECT_TRUE(temp_dir_.Delete());
+  }
+
+ protected:
+  // Try to read an entry from the database, returns true if the entry is
+  // present and false otherwise. |receiving_proto| will receive the protobuf
+  // corresponding to this entry on success.
+  bool ReadFromDB(const std::string& origin,
+                  SiteCharacteristicsProto* receiving_proto) {
+    EXPECT_TRUE(receiving_proto);
+    bool success = false;
+    bool init_called = false;
+    auto init_callback = base::BindOnce(
+        [](SiteCharacteristicsProto* proto, bool* res, bool* init_called,
+           base::Optional<SiteCharacteristicsProto> proto_opt) {
+          *res = proto_opt.has_value();
+          *init_called = true;
+          if (proto_opt)
+            proto->CopyFrom(proto_opt.value());
+        },
+        base::Unretained(receiving_proto), base::Unretained(&success),
+        base::Unretained(&init_called));
+    db_->ReadSiteCharacteristicsFromDB(origin, std::move(init_callback));
+    EXPECT_TRUE(init_called);
+    return success;
+  }
+
+  base::ScopedTempDir temp_dir_;
+  std::unique_ptr<LevelDBSiteCharacteristicsDatabase> db_;
+};
+
+TEST_F(LevelDBSiteCharacteristicsDatabaseTest, InitAndStoreSiteCharacteristic) {
+  // Initializing an entry that doesn't exist in the database should fail.
+  SiteCharacteristicsProto early_read_proto;
+  EXPECT_FALSE(ReadFromDB(kOrigin1, &early_read_proto));
+
+  // Add an entry to the database and make sure that we can read it back.
+  ::google::protobuf::int64 test_value = 42;
+  SiteCharacteristicsProto stored_proto;
+  InitSiteCharacteristicProto(&stored_proto, test_value);
+  db_->WriteSiteCharacteristicsIntoDB(kOrigin1, stored_proto);
+  SiteCharacteristicsProto read_proto;
+  EXPECT_TRUE(ReadFromDB(kOrigin1, &read_proto));
+  EXPECT_TRUE(read_proto.IsInitialized());
+  EXPECT_EQ(stored_proto.SerializeAsString(), read_proto.SerializeAsString());
+}
+
+TEST_F(LevelDBSiteCharacteristicsDatabaseTest, RemoveEntries) {
+  // Add multiple origins to the database.
+  const size_t kEntryCount = 10;
+  SiteCharacteristicsProto protos[kEntryCount];
+  std::vector<std::string> site_origins;
+  for (size_t i = 0; i < kEntryCount; ++i) {
+    std::string site_origin = base::StringPrintf("%zu.com", i);
+    InitSiteCharacteristicProto(&protos[i],
+                                static_cast<::google::protobuf::int64>(i));
+    db_->WriteSiteCharacteristicsIntoDB(site_origin, protos[i]);
+    site_origins.emplace_back(site_origin);
+  }
+
+  for (size_t i = 0; i < kEntryCount; ++i)
+    EXPECT_TRUE(protos[i].IsInitialized());
+
+  // Remove half the origins from the database.
+  std::vector<std::string> site_origins_to_remove(
+      site_origins.begin(), site_origins.begin() + kEntryCount / 2);
+  db_->RemoveSiteCharacteristicsFromDB(site_origins_to_remove);
+
+  // Verify that the origins were removed correctly.
+  SiteCharacteristicsProto proto_temp;
+  for (const auto& iter : site_origins_to_remove)
+    EXPECT_FALSE(ReadFromDB(iter, &proto_temp));
+
+  for (auto iter = site_origins.begin() + kEntryCount / 2;
+       iter != site_origins.end(); ++iter) {
+    EXPECT_TRUE(ReadFromDB(*iter, &proto_temp));
+  }
+
+  // Clear the database.
+  db_->ClearDatabase();
+
+  // Verify that no origin remains.
+  for (auto iter : site_origins)
+    EXPECT_FALSE(ReadFromDB(iter, &proto_temp));
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.cc
index 3131fe3..1f30f54a 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.cc
@@ -7,6 +7,8 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/bind.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_database.h"
 #include "chrome/browser/resource_coordinator/time.h"
 
 namespace resource_coordinator {
@@ -123,12 +125,36 @@
 
 LocalSiteCharacteristicsDataImpl::LocalSiteCharacteristicsDataImpl(
     const std::string& origin_str,
-    OnDestroyDelegate* delegate)
+    OnDestroyDelegate* delegate,
+    LocalSiteCharacteristicsDatabase* database)
     : origin_str_(origin_str),
       active_webcontents_count_(0U),
-      delegate_(delegate) {
+      database_(database),
+      delegate_(delegate),
+      weak_factory_(this) {
   DCHECK_NE(nullptr, delegate_);
-  InitWithDefaultValues();
+  DCHECK_NE(nullptr, database_);
+  DCHECK(!site_characteristics_.IsInitialized());
+  database_->ReadSiteCharacteristicsFromDB(
+      origin_str_,
+      base::BindOnce(&LocalSiteCharacteristicsDataImpl::OnInitCallback,
+                     weak_factory_.GetWeakPtr()));
+}
+
+LocalSiteCharacteristicsDataImpl::~LocalSiteCharacteristicsDataImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // It's currently required that the site gets unloaded before destroying this
+  // object.
+  // TODO(sebmarchand): Check if this is a valid assumption.
+  DCHECK(!IsLoaded());
+
+  DCHECK_NE(nullptr, delegate_);
+  delegate_->OnLocalSiteCharacteristicsDataImplDestroyed(this);
+
+  if (site_characteristics_.IsInitialized()) {
+    database_->WriteSiteCharacteristicsIntoDB(origin_str_,
+                                              site_characteristics_);
+  }
 }
 
 base::TimeDelta LocalSiteCharacteristicsDataImpl::FeatureObservationDuration(
@@ -153,22 +179,12 @@
   return observation_time_for_feature;
 }
 
-LocalSiteCharacteristicsDataImpl::~LocalSiteCharacteristicsDataImpl() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // It's currently required that the site gets unloaded before destroying this
-  // object.
-  // TODO(sebmarchand): Check if this is a valid assumption.
-  DCHECK(!IsLoaded());
-
-  DCHECK_NE(nullptr, delegate_);
-  delegate_->OnLocalSiteCharacteristicsDataImplDestroyed(this);
-}
-
 // static:
 void LocalSiteCharacteristicsDataImpl::IncrementFeatureObservationDuration(
     SiteCharacteristicsFeatureProto* feature_proto,
     base::TimeDelta extra_observation_duration) {
-  if (InternalRepresentationToTimeDelta(feature_proto->use_timestamp())
+  if (!feature_proto->has_use_timestamp() ||
+      InternalRepresentationToTimeDelta(feature_proto->use_timestamp())
           .is_zero()) {
     feature_proto->set_observation_duration(TimeDeltaToInternalRepresentation(
         InternalRepresentationToTimeDelta(
@@ -186,20 +202,26 @@
   proto->set_use_timestamp(kZeroIntervalInternalRepresentation);
 }
 
-void LocalSiteCharacteristicsDataImpl::InitWithDefaultValues() {
+void LocalSiteCharacteristicsDataImpl::InitWithDefaultValues(
+    bool only_init_uninitialized_fields) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Initialize the feature elements with the default value, this is required
   // because some fields might otherwise never be initialized.
-  for (auto* iter : GetAllFeaturesFromProto(&site_characteristics_))
-    InitSiteCharacteristicsFeatureProtoWithDefaultValues(iter);
+  for (auto* iter : GetAllFeaturesFromProto(&site_characteristics_)) {
+    if (!only_init_uninitialized_fields || !iter->IsInitialized())
+      InitSiteCharacteristicsFeatureProtoWithDefaultValues(iter);
+  }
 
-  site_characteristics_.set_last_loaded(kZeroIntervalInternalRepresentation);
+  if (!only_init_uninitialized_fields ||
+      !site_characteristics_.has_last_loaded()) {
+    site_characteristics_.set_last_loaded(kZeroIntervalInternalRepresentation);
+  }
 }
 
 void LocalSiteCharacteristicsDataImpl::ClearObservations() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Reset all the observations.
-  InitWithDefaultValues();
+  InitWithDefaultValues(false);
 
   // Set the last loaded time to the current time if there's some loaded
   // instances of this site.
@@ -214,6 +236,9 @@
     const base::TimeDelta min_obs_time) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  if (!feature_proto.IsInitialized())
+    return SiteFeatureUsage::kSiteFeatureUsageUnknown;
+
   // Checks if this feature has already been observed.
   // TODO(sebmarchand): Check the timestamp and reset features that haven't been
   // observed in a long time, https://crbug.com/826446.
@@ -238,5 +263,58 @@
   feature_proto->set_observation_duration(kZeroIntervalInternalRepresentation);
 }
 
+void LocalSiteCharacteristicsDataImpl::OnInitCallback(
+    base::Optional<SiteCharacteristicsProto> db_site_characteristics) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Check if the initialization has succeeded.
+  if (db_site_characteristics) {
+    // If so, iterates over all the features and initialize them.
+    auto this_features = GetAllFeaturesFromProto(&site_characteristics_);
+    auto db_features =
+        GetAllFeaturesFromProto(&db_site_characteristics.value());
+    auto this_features_iter = this_features.begin();
+    auto db_features_iter = db_features.begin();
+    for (; this_features_iter != this_features.end() &&
+           db_features_iter != db_features.end();
+         ++this_features_iter, ++db_features_iter) {
+      // If the |use_timestamp| field is set for the in-memory entry for this
+      // feature then there's nothing to do, otherwise update it with the values
+      // from the database.
+      if (!(*this_features_iter)->has_use_timestamp()) {
+        if ((*db_features_iter)->has_use_timestamp()) {
+          // Keep the use timestamp from the database, if any.
+          (*this_features_iter)
+              ->set_use_timestamp((*db_features_iter)->use_timestamp());
+          (*this_features_iter)
+              ->set_observation_duration(kZeroIntervalInternalRepresentation);
+        } else {
+          // Else, add the observation duration from the database to the
+          // in-memory observation duration.
+          if (!(*this_features_iter)->has_observation_duration()) {
+            (*this_features_iter)
+                ->set_observation_duration(kZeroIntervalInternalRepresentation);
+          }
+          IncrementFeatureObservationDuration(
+              (*this_features_iter),
+              InternalRepresentationToTimeDelta(
+                  (*db_features_iter)->observation_duration()));
+        }
+      }
+    }
+    // Only update the last loaded field if we haven't updated it since the
+    // creation of this object.
+    if (!site_characteristics_.has_last_loaded()) {
+      site_characteristics_.set_last_loaded(
+          db_site_characteristics->last_loaded());
+    }
+  } else {
+    // Init all the fields that haven't been initialized with a default value.
+    InitWithDefaultValues(true /* only_init_uninitialized_fields */);
+  }
+
+  DCHECK(site_characteristics_.IsInitialized());
+}
+
 }  // namespace internal
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h b/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h
index 53396c7..99a5429 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h
@@ -9,14 +9,17 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_database.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_feature_usage.h"
 #include "chrome/browser/resource_coordinator/site_characteristics.pb.h"
 #include "chrome/browser/resource_coordinator/tab_manager_features.h"
 
 namespace resource_coordinator {
 
+class LocalSiteCharacteristicsDatabase;
 class LocalSiteCharacteristicsDataStore;
 class LocalSiteCharacteristicsDataReaderTest;
 class LocalSiteCharacteristicsDataWriterTest;
@@ -88,7 +91,10 @@
   friend class resource_coordinator::LocalSiteCharacteristicsDataWriterTest;
 
   LocalSiteCharacteristicsDataImpl(const std::string& origin_str,
-                                   OnDestroyDelegate* delegate);
+                                   OnDestroyDelegate* delegate,
+                                   LocalSiteCharacteristicsDatabase* database);
+
+  virtual ~LocalSiteCharacteristicsDataImpl();
 
   // Helper functions to convert from/to the internal representation that is
   // used to store TimeDelta values in the |SiteCharacteristicsProto| protobuf.
@@ -100,8 +106,6 @@
     return delta.InSeconds();
   }
 
-  virtual ~LocalSiteCharacteristicsDataImpl();
-
   // Returns for how long a given feature has been observed, this is the sum of
   // the recorded observation duration and the current observation duration
   // since this site has been loaded (if applicable). If a feature has been
@@ -123,10 +127,13 @@
   static void InitSiteCharacteristicsFeatureProtoWithDefaultValues(
       SiteCharacteristicsFeatureProto* proto);
 
-  // Initialize this object with default values.
+  // Initialize this object with default values. If
+  // |only_init_uninitialized_fields| is set to true then only the fields that
+  // haven't yet been initialized will be initialized, otherwise everything will
+  // be overriden with default values.
   // NOTE: Do not call this directly while the site is loaded as this will not
   // properly update the last_loaded time, instead call |ClearObservations|.
-  void InitWithDefaultValues();
+  void InitWithDefaultValues(bool only_init_uninitialized_fields);
 
   // Clear all the past observations about this site.
   void ClearObservations();
@@ -144,6 +151,11 @@
 
   bool IsLoaded() const { return active_webcontents_count_ > 0U; }
 
+  // Callback that needs to be called by the database once it has finished
+  // trying to read the protobuf.
+  void OnInitCallback(
+      base::Optional<SiteCharacteristicsProto> site_characteristic_proto);
+
   // This site's characteristics, contains the features and other values are
   // measured.
   SiteCharacteristicsProto site_characteristics_;
@@ -155,13 +167,24 @@
   // same origin might share the same instance of this object, this counter
   // will allow to properly update the observation time (starts when the first
   // tab gets loaded, stops when the last one gets unloaded).
+  //
+  // TODO(sebmarchand): Also track the number of tabs that are in background for
+  // this origin and use this to update the observation windows. The number of
+  // active WebContents doesn't tell anything about the background/foreground
+  // state of a tab.
   size_t active_webcontents_count_;
 
+  // The database used to store the site characteristics.
+  LocalSiteCharacteristicsDatabase* database_;
+
   // The delegate that should get notified when this object is about to get
   // destroyed.
   OnDestroyDelegate* const delegate_;
 
   SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<LocalSiteCharacteristicsDataImpl> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsDataImpl);
 };
 
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_impl_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_impl_unittest.cc
index 35a01e66..ff64f521c 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_impl_unittest.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_impl_unittest.cc
@@ -31,8 +31,9 @@
 
   explicit TestLocalSiteCharacteristicsDataImpl(
       const std::string& origin_str,
-      LocalSiteCharacteristicsDataImpl::OnDestroyDelegate* delegate)
-      : LocalSiteCharacteristicsDataImpl(origin_str, delegate) {}
+      LocalSiteCharacteristicsDataImpl::OnDestroyDelegate* delegate,
+      LocalSiteCharacteristicsDatabase* database)
+      : LocalSiteCharacteristicsDataImpl(origin_str, delegate, database) {}
 
   base::TimeDelta FeatureObservationTimestamp(
       const SiteCharacteristicsFeatureProto& feature_proto) {
@@ -43,6 +44,47 @@
   ~TestLocalSiteCharacteristicsDataImpl() override {}
 };
 
+class MockLocalSiteCharacteristicsDatabase
+    : public testing::NoopLocalSiteCharacteristicsDatabase {
+ public:
+  MockLocalSiteCharacteristicsDatabase() = default;
+  ~MockLocalSiteCharacteristicsDatabase() = default;
+
+  // Note: As move-only parameters (e.g. OnceCallback) aren't supported by mock
+  // methods, add On... methods to pass a non-const reference to OnceCallback.
+  void ReadSiteCharacteristicsFromDB(
+      const std::string& origin_str,
+      LocalSiteCharacteristicsDatabase::ReadSiteCharacteristicsFromDBCallback
+          callback) override {
+    OnReadSiteCharacteristicsFromDB(origin_str, callback);
+  }
+  MOCK_METHOD2(OnReadSiteCharacteristicsFromDB,
+               void(const std::string&,
+                    LocalSiteCharacteristicsDatabase::
+                        ReadSiteCharacteristicsFromDBCallback&));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockLocalSiteCharacteristicsDatabase);
+};
+
+// Returns a SiteCharacteristicsFeatureProto that indicates that a feature
+// hasn't been used.
+SiteCharacteristicsFeatureProto GetUnusedFeatureProto() {
+  SiteCharacteristicsFeatureProto unused_feature_proto;
+  unused_feature_proto.set_observation_duration(1U);
+  unused_feature_proto.set_use_timestamp(0U);
+  return unused_feature_proto;
+}
+
+// Returns a SiteCharacteristicsFeatureProto that indicates that a feature
+// has been used.
+SiteCharacteristicsFeatureProto GetUsedFeatureProto() {
+  SiteCharacteristicsFeatureProto used_feature_proto;
+  used_feature_proto.set_observation_duration(0U);
+  used_feature_proto.set_use_timestamp(1U);
+  return used_feature_proto;
+}
+
 }  // namespace
 
 class LocalSiteCharacteristicsDataImplTest : public ::testing::Test {
@@ -65,12 +107,17 @@
   ::testing::NiceMock<
       testing::MockLocalSiteCharacteristicsDataImplOnDestroyDelegate>
       destroy_delegate_;
+
+  testing::NoopLocalSiteCharacteristicsDatabase database_;
 };
 
 TEST_F(LocalSiteCharacteristicsDataImplTest, BasicTestEndToEnd) {
   auto local_site_data =
       base::MakeRefCounted<TestLocalSiteCharacteristicsDataImpl>(
-          kDummyOrigin, &destroy_delegate_);
+          kDummyOrigin, &destroy_delegate_, &database_);
+
+  EXPECT_TRUE(
+      local_site_data->site_characteristics_for_testing().IsInitialized());
 
   local_site_data->NotifySiteLoaded();
 
@@ -126,7 +173,7 @@
 TEST_F(LocalSiteCharacteristicsDataImplTest, LastLoadedTime) {
   auto local_site_data =
       base::MakeRefCounted<TestLocalSiteCharacteristicsDataImpl>(
-          kDummyOrigin, &destroy_delegate_);
+          kDummyOrigin, &destroy_delegate_, &database_);
   // Create a second instance of this object, simulates having several tab
   // owning it.
   auto local_site_data2(local_site_data);
@@ -157,7 +204,7 @@
 TEST_F(LocalSiteCharacteristicsDataImplTest, GetFeatureUsageForUnloadedSite) {
   auto local_site_data =
       base::MakeRefCounted<TestLocalSiteCharacteristicsDataImpl>(
-          kDummyOrigin, &destroy_delegate_);
+          kDummyOrigin, &destroy_delegate_, &database_);
 
   local_site_data->NotifySiteLoaded();
   local_site_data->NotifyUsesAudioInBackground();
@@ -210,7 +257,7 @@
   // for all the features being tracked.
   auto local_site_data =
       base::MakeRefCounted<TestLocalSiteCharacteristicsDataImpl>(
-          kDummyOrigin, &destroy_delegate_);
+          kDummyOrigin, &destroy_delegate_, &database_);
 
   const base::TimeDelta kInterval = base::TimeDelta::FromSeconds(1);
   const auto kIntervalInternalRepresentation =
@@ -266,6 +313,7 @@
   expected_proto.mutable_uses_audio_in_background()->CopyFrom(
       used_feature_proto);
 
+  EXPECT_TRUE(expected_proto.IsInitialized());
   EXPECT_TRUE(
       local_site_data->site_characteristics_for_testing().IsInitialized());
   EXPECT_EQ(
@@ -282,12 +330,110 @@
   {
     auto local_site_data =
         base::MakeRefCounted<TestLocalSiteCharacteristicsDataImpl>(
-            kDummyOrigin, &strict_delegate);
+            kDummyOrigin, &strict_delegate, &database_);
     EXPECT_CALL(strict_delegate, OnLocalSiteCharacteristicsDataImplDestroyed(
                                      local_site_data.get()));
   }
   ::testing::Mock::VerifyAndClear(&strict_delegate);
 }
 
+TEST_F(LocalSiteCharacteristicsDataImplTest,
+       OnInitCallbackMergePreviousObservations) {
+  // Use a mock database to intercept the initialization callback and save it
+  // locally so it can be run later. This simulates an asynchronous
+  // initialization of this object and is used to test that the observations
+  // made between the time this object has been created and the callback is
+  // called get properly merged.
+  ::testing::StrictMock<MockLocalSiteCharacteristicsDatabase> mock_db;
+  LocalSiteCharacteristicsDatabase::ReadSiteCharacteristicsFromDBCallback
+      read_cb;
+  auto read_from_db_mock_impl =
+      [&](const std::string& site_origin,
+          LocalSiteCharacteristicsDatabase::
+              ReadSiteCharacteristicsFromDBCallback& callback) {
+        read_cb = std::move(callback);
+      };
+
+  EXPECT_CALL(mock_db,
+              OnReadSiteCharacteristicsFromDB(::testing::_, ::testing::_))
+      .WillOnce(::testing::Invoke(read_from_db_mock_impl));
+  auto local_site_data =
+      base::MakeRefCounted<TestLocalSiteCharacteristicsDataImpl>(
+          kDummyOrigin, &destroy_delegate_, &mock_db);
+  ::testing::Mock::VerifyAndClear(&mock_db);
+
+  // Simulates audio in background usage before the callback gets called.
+  local_site_data->NotifySiteLoaded();
+  local_site_data->NotifyUsesAudioInBackground();
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureInUse,
+            local_site_data->UsesAudioInBackground());
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            local_site_data->UsesNotificationsInBackground());
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            local_site_data->UpdatesFaviconInBackground());
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            local_site_data->UpdatesTitleInBackground());
+
+  // Unload the site and save the last loaded time to make sure the
+  // initialization doesn't overwrite it.
+  test_clock_.Advance(base::TimeDelta::FromSeconds(1));
+  local_site_data->NotifySiteUnloaded();
+  test_clock_.Advance(base::TimeDelta::FromSeconds(1));
+  auto last_loaded = local_site_data->last_loaded_time_for_testing();
+
+  // This protobuf should have a valid |last_loaded| field and valid observation
+  // durations for each features, but the |use_timestamp| field shouldn't have
+  // been initialized for the features that haven't been used.
+  EXPECT_FALSE(
+      local_site_data->site_characteristics_for_testing().IsInitialized());
+  EXPECT_TRUE(
+      local_site_data->site_characteristics_for_testing().has_last_loaded());
+  EXPECT_TRUE(local_site_data->site_characteristics_for_testing()
+                  .uses_audio_in_background()
+                  .IsInitialized());
+  EXPECT_FALSE(local_site_data->site_characteristics_for_testing()
+                   .uses_notifications_in_background()
+                   .IsInitialized());
+  EXPECT_FALSE(local_site_data->site_characteristics_for_testing()
+                   .uses_notifications_in_background()
+                   .has_use_timestamp());
+  EXPECT_TRUE(local_site_data->site_characteristics_for_testing()
+                  .uses_notifications_in_background()
+                  .has_observation_duration());
+
+  // Initialize a fake protobuf that indicates that this site updates its title
+  // while in background and set a fake last loaded time (this should be
+  // overriden once the callback runs).
+  base::Optional<SiteCharacteristicsProto> test_proto =
+      SiteCharacteristicsProto();
+  SiteCharacteristicsFeatureProto unused_feature_proto =
+      GetUnusedFeatureProto();
+  test_proto->mutable_updates_title_in_background()->CopyFrom(
+      GetUsedFeatureProto());
+  test_proto->mutable_updates_favicon_in_background()->CopyFrom(
+      unused_feature_proto);
+  test_proto->mutable_uses_audio_in_background()->CopyFrom(
+      unused_feature_proto);
+  test_proto->mutable_uses_notifications_in_background()->CopyFrom(
+      unused_feature_proto);
+  test_proto->set_last_loaded(42);
+
+  // Run the callback to indicate that the initialization has completed.
+  std::move(read_cb).Run(test_proto);
+
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureInUse,
+            local_site_data->UsesAudioInBackground());
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureInUse,
+            local_site_data->UpdatesTitleInBackground());
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            local_site_data->UpdatesFaviconInBackground());
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            local_site_data->UsesNotificationsInBackground());
+  EXPECT_EQ(last_loaded, local_site_data->last_loaded_time_for_testing());
+
+  EXPECT_TRUE(
+      local_site_data->site_characteristics_for_testing().IsInitialized());
+}
+
 }  // namespace internal
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_reader_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_reader_unittest.cc
index 405ca28..3585c4d 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_reader_unittest.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_reader_unittest.cc
@@ -21,10 +21,10 @@
   // LocalSiteCharacteristicsDataImpl is protected and not visible to
   // base::MakeRefCounted.
   LocalSiteCharacteristicsDataReaderTest()
-      : scoped_set_tick_clock_for_testing_(&test_clock_),
-        test_impl_(base::WrapRefCounted(
-            new internal::LocalSiteCharacteristicsDataImpl("foo.com",
-                                                           &delegate_))) {
+      : scoped_set_tick_clock_for_testing_(&test_clock_) {
+    test_impl_ =
+        base::WrapRefCounted(new internal::LocalSiteCharacteristicsDataImpl(
+            "foo.com", &delegate_, &database_));
     test_impl_->NotifySiteLoaded();
     LocalSiteCharacteristicsDataReader* reader =
         new LocalSiteCharacteristicsDataReader(test_impl_.get());
@@ -52,6 +52,8 @@
   // to create this object.
   std::unique_ptr<LocalSiteCharacteristicsDataReader> reader_;
 
+  testing::NoopLocalSiteCharacteristicsDatabase database_;
+
   DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsDataReaderTest);
 };
 
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
index 178d10a..696b071b 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.cc
@@ -8,14 +8,24 @@
 #include "base/stl_util.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/leveldb_site_characteristics_database.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_reader.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h"
 #include "components/history/core/browser/history_service.h"
 
 namespace resource_coordinator {
 
+namespace {
+constexpr char kSiteCharacteristicsDirectoryName[] =
+    "Site Characteristics Database";
+}
+
 LocalSiteCharacteristicsDataStore::LocalSiteCharacteristicsDataStore(
     Profile* profile)
     : history_observer_(this) {
+  database_ = LevelDBSiteCharacteristicsDatabase::OpenOrCreateDatabase(
+      profile->GetPath().AppendASCII(kSiteCharacteristicsDirectoryName));
+
   history::HistoryService* history =
       HistoryServiceFactory::GetForProfileWithoutCreating(profile);
   if (history)
@@ -36,7 +46,7 @@
   return base::WrapUnique(data_reader);
 }
 
-std::unique_ptr<LocalSiteCharacteristicsDataWriter>
+std::unique_ptr<SiteCharacteristicsDataWriter>
 LocalSiteCharacteristicsDataStore::GetWriterForOrigin(
     const std::string& origin_str) {
   internal::LocalSiteCharacteristicsDataImpl* impl =
@@ -57,7 +67,8 @@
 
   // If not create a new one and add it to the map.
   internal::LocalSiteCharacteristicsDataImpl* site_characteristic_data =
-      new internal::LocalSiteCharacteristicsDataImpl(origin_str, this);
+      new internal::LocalSiteCharacteristicsDataImpl(origin_str, this,
+                                                     database_.get());
   // internal::LocalSiteCharacteristicsDataImpl is a ref-counted object, it's
   // safe to store a raw pointer to it here as this class will get notified when
   // it's about to be destroyed and it'll be removed from the map.
@@ -90,21 +101,25 @@
 void LocalSiteCharacteristicsDataStore::OnURLsDeleted(
     history::HistoryService* history_service,
     const history::DeletionInfo& deletion_info) {
-  // TODO(sebmarchand): Removes these entry from the on-disk database once it's
-  // implemented.
+  // TODO(sebmarchand): Invalidates all the pending read/write operations to the
+  // database once it's asynchronous.
   if (deletion_info.IsAllHistory()) {
     for (auto iter = origin_data_map_.begin();
          iter != origin_data_map_.end();) {
       iter = ResetLocalSiteCharacteristicsEntry(iter);
     }
+    database_->ClearDatabase();
   } else {
-    for (const auto& deleted_row : deletion_info.deleted_rows()) {
+    std::vector<std::string> entries_to_remove;
+    for (auto deleted_row : deletion_info.deleted_rows()) {
       auto map_iter =
           origin_data_map_.find(deleted_row.url().GetOrigin().GetContent());
       if (map_iter != origin_data_map_.end()) {
         ResetLocalSiteCharacteristicsEntry(map_iter);
+        entries_to_remove.emplace_back(map_iter->first);
       }
     }
+    database_->RemoveSiteCharacteristicsFromDB(entries_to_remove);
   }
 }
 
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.h b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.h
index 39436c05..689b370 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_store.h
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_store.h
@@ -12,16 +12,21 @@
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h"
-#include "chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h"
 #include "chrome/browser/resource_coordinator/site_characteristics_data_store.h"
+#include "chrome/browser/resource_coordinator/site_characteristics_data_writer.h"
 #include "components/history/core/browser/history_service_observer.h"
 
 class Profile;
 
 namespace resource_coordinator {
 
+class LocalSiteCharacteristicsDatabase;
+
 // Implementation of a SiteCharacteristicsDataStore that use the local site
 // characteristics database as a backend.
+//
+// TODO(sebmarchand): Expose a method to receive a dummy writer that doesn't
+// record anything, for use in incognito sessions.
 class LocalSiteCharacteristicsDataStore
     : public SiteCharacteristicsDataStore,
       public internal::LocalSiteCharacteristicsDataImpl::OnDestroyDelegate,
@@ -37,13 +42,21 @@
   std::unique_ptr<SiteCharacteristicsDataReader> GetReaderForOrigin(
       const std::string& origin_str) override;
 
-  std::unique_ptr<LocalSiteCharacteristicsDataWriter> GetWriterForOrigin(
-      const std::string& origin_str);
+  std::unique_ptr<SiteCharacteristicsDataWriter> GetWriterForOrigin(
+      const std::string& origin_str) override;
 
   const LocalSiteCharacteristicsMap& origin_data_map_for_testing() const {
     return origin_data_map_;
   }
 
+  // NOTE: This should be called before creating any
+  // LocalSiteCharacteristicsDataImpl object (this doesn't update the database
+  // used by these objects).
+  void SetDatabaseForTesting(
+      std::unique_ptr<LocalSiteCharacteristicsDatabase> database) {
+    database_ = std::move(database);
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(LocalSiteCharacteristicsDataStoreTest, EndToEnd);
   FRIEND_TEST_ALL_PREFIXES(LocalSiteCharacteristicsDataStoreTest,
@@ -76,6 +89,8 @@
   ScopedObserver<history::HistoryService, LocalSiteCharacteristicsDataStore>
       history_observer_;
 
+  std::unique_ptr<LocalSiteCharacteristicsDatabase> database_;
+
   DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsDataStore);
 };
 
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_store_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_store_unittest.cc
index bebbd1d0..6754b13 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_store_unittest.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_store_unittest.cc
@@ -7,18 +7,36 @@
 #include "base/macros.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h"
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/url_row.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace resource_coordinator {
 
 namespace {
+
 const char kTestOrigin[] = "http://www.foo.com";
 const char kTestOrigin2[] = "http://www.bar.com";
+
+class MockLocalSiteCharacteristicsDatabase
+    : public testing::NoopLocalSiteCharacteristicsDatabase {
+ public:
+  MockLocalSiteCharacteristicsDatabase() = default;
+  ~MockLocalSiteCharacteristicsDatabase() = default;
+
+  MOCK_METHOD1(RemoveSiteCharacteristicsFromDB,
+               void(const std::vector<std::string>& site_origin));
+  MOCK_METHOD0(ClearDatabase, void());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockLocalSiteCharacteristicsDatabase);
+};
+
 }  // namespace
 
 class LocalSiteCharacteristicsDataStoreTest : public ::testing::Test {
@@ -72,11 +90,17 @@
 }
 
 TEST_F(LocalSiteCharacteristicsDataStoreTest, HistoryServiceObserver) {
+  // Mock the database to ensure that the delete events get propagated properly.
+  ::testing::StrictMock<MockLocalSiteCharacteristicsDatabase>* mock_db =
+      new ::testing::StrictMock<MockLocalSiteCharacteristicsDatabase>();
+  data_store_.SetDatabaseForTesting(base::WrapUnique(mock_db));
+
   // Load a first origin, and then make use of a feature on it.
 
   const std::string kOrigin1Url = GURL(kTestOrigin).GetOrigin().GetContent();
   auto reader = data_store_.GetReaderForOrigin(kOrigin1Url);
   EXPECT_TRUE(reader);
+
   auto writer = data_store_.GetWriterForOrigin(kOrigin1Url);
   EXPECT_TRUE(writer);
 
@@ -104,8 +128,8 @@
   internal::LocalSiteCharacteristicsDataImpl* data2 =
       data_store_.origin_data_map_for_testing().find(kOrigin2Url)->second;
   EXPECT_NE(nullptr, data2);
-  writer2->NotifySiteLoaded();
-  writer2->NotifyUpdatesFaviconInBackground();
+  data2->NotifySiteLoaded();
+  data2->NotifyUpdatesFaviconInBackground();
 
   // This site hasn'be been unloaded yet, so the last loaded time shouldn't have
   // changed.
@@ -114,8 +138,11 @@
   history::URLRows urls_to_delete = {
       history::URLRow(GURL(kTestOrigin)),
       history::URLRow(GURL("http://www.url-not-in-map.com"))};
+  EXPECT_CALL(*mock_db, RemoveSiteCharacteristicsFromDB(::testing::ContainerEq(
+                            std::vector<std::string>({kOrigin1Url}))));
   data_store_.OnURLsDeleted(nullptr, history::DeletionInfo::ForUrls(
                                          urls_to_delete, std::set<GURL>()));
+  ::testing::Mock::VerifyAndClear(mock_db);
 
   // The information for this site have been reset, so the last loaded time
   // should now be equal to the current time and the title update feature
@@ -132,7 +159,9 @@
   test_clock_.Advance(kDelay);
 
   // Delete all the information stored in the data store.
+  EXPECT_CALL(*mock_db, ClearDatabase());
   data_store_.OnURLsDeleted(nullptr, history::DeletionInfo::ForAllHistory());
+  ::testing::Mock::VerifyAndClear(mock_db);
 
   EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
             reader2->UpdatesFaviconInBackground());
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc
index 8e79238..502f5ec 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc
@@ -12,5 +12,24 @@
 MockLocalSiteCharacteristicsDataImplOnDestroyDelegate::
     ~MockLocalSiteCharacteristicsDataImplOnDestroyDelegate() = default;
 
+NoopLocalSiteCharacteristicsDatabase::NoopLocalSiteCharacteristicsDatabase() =
+    default;
+NoopLocalSiteCharacteristicsDatabase::~NoopLocalSiteCharacteristicsDatabase() {}
+
+void NoopLocalSiteCharacteristicsDatabase::ReadSiteCharacteristicsFromDB(
+    const std::string& site_origin,
+    ReadSiteCharacteristicsFromDBCallback callback) {
+  std::move(callback).Run(base::nullopt);
+}
+
+void NoopLocalSiteCharacteristicsDatabase::WriteSiteCharacteristicsIntoDB(
+    const std::string& site_origin,
+    const SiteCharacteristicsProto& site_characteristic_proto) {}
+
+void NoopLocalSiteCharacteristicsDatabase::RemoveSiteCharacteristicsFromDB(
+    const std::vector<std::string>& site_origins) {}
+
+void NoopLocalSiteCharacteristicsDatabase::ClearDatabase() {}
+
 }  // namespace testing
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h b/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h
index f14e5a8..327dd107 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_impl.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_database.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace resource_coordinator {
@@ -26,6 +27,29 @@
       MockLocalSiteCharacteristicsDataImplOnDestroyDelegate);
 };
 
+// An implementation of a LocalSiteCharacteristicsDatabase that doesn't record
+// anything.
+class NoopLocalSiteCharacteristicsDatabase
+    : public LocalSiteCharacteristicsDatabase {
+ public:
+  NoopLocalSiteCharacteristicsDatabase();
+  ~NoopLocalSiteCharacteristicsDatabase() override;
+
+  // LocalSiteCharacteristicsDatabase:
+  void ReadSiteCharacteristicsFromDB(
+      const std::string& site_origin,
+      ReadSiteCharacteristicsFromDBCallback callback) override;
+  void WriteSiteCharacteristicsIntoDB(
+      const std::string& site_origin,
+      const SiteCharacteristicsProto& site_characteristic_proto) override;
+  void RemoveSiteCharacteristicsFromDB(
+      const std::vector<std::string>& site_origins) override;
+  void ClearDatabase() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoopLocalSiteCharacteristicsDatabase);
+};
+
 }  // namespace testing
 }  // namespace resource_coordinator
 
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h b/chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h
index b149aa9..68160628 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/browser/resource_coordinator/site_characteristics_data_writer.h"
 
 namespace resource_coordinator {
 
@@ -14,21 +15,20 @@
 class LocalSiteCharacteristicsDataImpl;
 }  // namespace internal
 
-// Used to record local characteristics usage observations in the local
-// database.
-class LocalSiteCharacteristicsDataWriter {
+// Specialization of a SiteCharacteristicsDataWriter that delegates to a
+// LocalSiteCharacteristicsDataImpl.
+class LocalSiteCharacteristicsDataWriter
+    : public SiteCharacteristicsDataWriter {
  public:
-  ~LocalSiteCharacteristicsDataWriter();
+  ~LocalSiteCharacteristicsDataWriter() override;
 
-  // Records tab load/unload events.
-  void NotifySiteLoaded();
-  void NotifySiteUnloaded();
-
-  // Records feature usage.
-  void NotifyUpdatesFaviconInBackground();
-  void NotifyUpdatesTitleInBackground();
-  void NotifyUsesAudioInBackground();
-  void NotifyUsesNotificationsInBackground();
+  // SiteCharacteristicsDataWriter:
+  void NotifySiteLoaded() override;
+  void NotifySiteUnloaded() override;
+  void NotifyUpdatesFaviconInBackground() override;
+  void NotifyUpdatesTitleInBackground() override;
+  void NotifyUsesAudioInBackground() override;
+  void NotifyUsesNotificationsInBackground() override;
 
  private:
   friend class LocalSiteCharacteristicsDataWriterTest;
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_data_writer_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_data_writer_unittest.cc
index 659030b..9629625 100644
--- a/chrome/browser/resource_coordinator/local_site_characteristics_data_writer_unittest.cc
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_data_writer_unittest.cc
@@ -22,7 +22,8 @@
   LocalSiteCharacteristicsDataWriterTest()
       : test_impl_(base::WrapRefCounted(
             new internal::LocalSiteCharacteristicsDataImpl("foo.com",
-                                                           &delegate_))) {
+                                                           &delegate_,
+                                                           &database_))) {
     LocalSiteCharacteristicsDataWriter* writer =
         new LocalSiteCharacteristicsDataWriter(test_impl_.get());
     writer_ = base::WrapUnique(writer);
@@ -30,6 +31,8 @@
 
   ~LocalSiteCharacteristicsDataWriterTest() override = default;
 
+  bool TabIsLoaded() { return test_impl_->IsLoaded(); }
+
   // The mock delegate used by the LocalSiteCharacteristicsDataImpl objects
   // created by this class, NiceMock is used to avoid having to set
   // expectations in test cases that don't care about this.
@@ -37,6 +40,8 @@
       testing::MockLocalSiteCharacteristicsDataImplOnDestroyDelegate>
       delegate_;
 
+  testing::NoopLocalSiteCharacteristicsDatabase database_;
+
   // The LocalSiteCharacteristicsDataImpl object used in these tests.
   scoped_refptr<internal::LocalSiteCharacteristicsDataImpl> test_impl_;
 
@@ -44,8 +49,6 @@
   // to create this object.
   std::unique_ptr<LocalSiteCharacteristicsDataWriter> writer_;
 
-  bool TabIsLoaded() { return test_impl_->IsLoaded(); }
-
   DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsDataWriterTest);
 };
 
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_database.h b/chrome/browser/resource_coordinator/local_site_characteristics_database.h
new file mode 100644
index 0000000..d41d62c
--- /dev/null
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_database.h
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_DATABASE_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_DATABASE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "chrome/browser/resource_coordinator/site_characteristics.pb.h"
+
+class SiteCharacteristicsProto;
+
+namespace resource_coordinator {
+
+// Interface for a local site characteristic database.
+class LocalSiteCharacteristicsDatabase {
+ public:
+  // Callback to call once the initialization from the database has completed,
+  // |site_characteristic_proto| should be equal to base::nullopt if the
+  // initialization has failed.
+  using ReadSiteCharacteristicsFromDBCallback = base::OnceCallback<void(
+      base::Optional<SiteCharacteristicsProto> site_characteristic_proto)>;
+
+  LocalSiteCharacteristicsDatabase() = default;
+  virtual ~LocalSiteCharacteristicsDatabase() {}
+
+  // Checks the if there's an entry with the key |site_origin| and if so use it
+  // to initialize |site_characteristic_proto|. Calls |callback| to indicate
+  // whether or not the initialization has been successful.
+  virtual void ReadSiteCharacteristicsFromDB(
+      const std::string& site_origin,
+      ReadSiteCharacteristicsFromDBCallback callback) = 0;
+
+  // Store an entry in the database, create it if it doesn't exist and update it
+  // if it does.
+  virtual void WriteSiteCharacteristicsIntoDB(
+      const std::string& site_origin,
+      const SiteCharacteristicsProto& site_characteristic_proto) = 0;
+
+  // Removes some entries from the database.
+  virtual void RemoveSiteCharacteristicsFromDB(
+      const std::vector<std::string>& site_origins) = 0;
+
+  // Clear the database, removes every entries that it contains.
+  virtual void ClearDatabase() = 0;
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_DATABASE_H_
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.cc b/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.cc
new file mode 100644
index 0000000..a90caec
--- /dev/null
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.cc
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.h"
+
+namespace resource_coordinator {
+
+LocalSiteCharacteristicsNonRecordingDataStore::
+    LocalSiteCharacteristicsNonRecordingDataStore(
+        SiteCharacteristicsDataStore* data_store_for_readers)
+    : data_store_for_readers_(data_store_for_readers) {
+  DCHECK(data_store_for_readers_);
+}
+
+LocalSiteCharacteristicsNonRecordingDataStore::
+    ~LocalSiteCharacteristicsNonRecordingDataStore() = default;
+
+std::unique_ptr<SiteCharacteristicsDataReader>
+LocalSiteCharacteristicsNonRecordingDataStore::GetReaderForOrigin(
+    const std::string& origin_str) {
+  return data_store_for_readers_->GetReaderForOrigin(origin_str);
+}
+
+std::unique_ptr<SiteCharacteristicsDataWriter>
+LocalSiteCharacteristicsNonRecordingDataStore::GetWriterForOrigin(
+    const std::string& origin_str) {
+  // Return a fake data writer.
+  SiteCharacteristicsDataWriter* writer =
+      new LocalSiteCharacteristicsNoopDataWriter();
+  return base::WrapUnique(writer);
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.h b/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.h
new file mode 100644
index 0000000..83a0aae
--- /dev/null
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_NON_RECORDING_DATA_STORE_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_NON_RECORDING_DATA_STORE_H_
+
+#include "base/macros.h"
+#include "chrome/browser/resource_coordinator/site_characteristics_data_store.h"
+
+namespace resource_coordinator {
+
+// Specialization of a SiteCharacteristicsDataStore whose
+// SiteCharacteristicsDataWriters don't persist observations and whose
+// SiteCharacteristicsDataReader are obtained from another
+// SiteCharacteristicsDataStore.
+class LocalSiteCharacteristicsNonRecordingDataStore
+    : public SiteCharacteristicsDataStore {
+ public:
+  // |data_store_for_readers| should outlive this object.
+  explicit LocalSiteCharacteristicsNonRecordingDataStore(
+      SiteCharacteristicsDataStore* data_store_for_readers);
+  ~LocalSiteCharacteristicsNonRecordingDataStore() override;
+
+  // SiteCharacteristicDataStore:
+  std::unique_ptr<SiteCharacteristicsDataReader> GetReaderForOrigin(
+      const std::string& origin_str) override;
+  std::unique_ptr<SiteCharacteristicsDataWriter> GetWriterForOrigin(
+      const std::string& origin_str) override;
+
+ private:
+  // The data store to use to create the readers served by this data store. E.g.
+  // during an incognito session it should point to the data store used by the
+  // parent session.
+  SiteCharacteristicsDataStore* data_store_for_readers_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsNonRecordingDataStore);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_NON_RECORDING_DATA_STORE_H_
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store_unittest.cc
new file mode 100644
index 0000000..578fe91
--- /dev/null
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/local_site_characteristics_non_recording_data_store.h"
+
+#include "chrome/browser/resource_coordinator/local_site_characteristics_data_store.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace resource_coordinator {
+
+using LocalSiteCharacteristicsNonRecordingDataStoreTest = ::testing::Test;
+
+TEST_F(LocalSiteCharacteristicsNonRecordingDataStoreTest, EndToEnd) {
+  content::TestBrowserThreadBundle test_browser_thread_bundle;
+  TestingProfile profile;
+  const char kTestOrigin[] = "http://www.foo.com";
+  LocalSiteCharacteristicsDataStore recording_data_store(&profile);
+  LocalSiteCharacteristicsNonRecordingDataStore non_recording_data_store(
+      &recording_data_store);
+
+  // Ensures that the observation made via a writer created by the non
+  // recording data store aren't recorded.
+
+  auto reader = non_recording_data_store.GetReaderForOrigin(kTestOrigin);
+  EXPECT_TRUE(reader);
+  auto fake_writer = non_recording_data_store.GetWriterForOrigin(kTestOrigin);
+  EXPECT_TRUE(fake_writer);
+  auto real_writer = recording_data_store.GetWriterForOrigin(kTestOrigin);
+  EXPECT_TRUE(real_writer);
+
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            reader->UpdatesTitleInBackground());
+  fake_writer->NotifySiteLoaded();
+  fake_writer->NotifyUpdatesTitleInBackground();
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureUsageUnknown,
+            reader->UpdatesTitleInBackground());
+
+  real_writer->NotifySiteLoaded();
+  real_writer->NotifyUpdatesTitleInBackground();
+  EXPECT_EQ(SiteFeatureUsage::kSiteFeatureInUse,
+            reader->UpdatesTitleInBackground());
+
+  // These unload events shouldn't be registered, make sure that they aren't by
+  // unloading the site more time than it has been loaded.
+  fake_writer->NotifySiteUnloaded();
+  fake_writer->NotifySiteUnloaded();
+
+  real_writer->NotifySiteUnloaded();
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.cc b/chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.cc
new file mode 100644
index 0000000..38bf8760
--- /dev/null
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.h"
+
+namespace resource_coordinator {
+
+LocalSiteCharacteristicsNoopDataWriter::
+    LocalSiteCharacteristicsNoopDataWriter() = default;
+LocalSiteCharacteristicsNoopDataWriter::
+    ~LocalSiteCharacteristicsNoopDataWriter() = default;
+
+void LocalSiteCharacteristicsNoopDataWriter::NotifySiteLoaded() {}
+
+void LocalSiteCharacteristicsNoopDataWriter::NotifySiteUnloaded() {}
+
+void LocalSiteCharacteristicsNoopDataWriter::
+    NotifyUpdatesFaviconInBackground() {}
+
+void LocalSiteCharacteristicsNoopDataWriter::NotifyUpdatesTitleInBackground() {}
+
+void LocalSiteCharacteristicsNoopDataWriter::NotifyUsesAudioInBackground() {}
+
+void LocalSiteCharacteristicsNoopDataWriter::
+    NotifyUsesNotificationsInBackground() {}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.h b/chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.h
new file mode 100644
index 0000000..c106d16
--- /dev/null
+++ b/chrome/browser/resource_coordinator/local_site_characteristics_noop_data_writer.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_NOOP_DATA_WRITER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_NOOP_DATA_WRITER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/resource_coordinator/site_characteristics_data_writer.h"
+
+namespace resource_coordinator {
+
+// Specialization of a SiteCharacteristicsDataWriter that doesn't record
+// anyting.
+class LocalSiteCharacteristicsNoopDataWriter
+    : public SiteCharacteristicsDataWriter {
+ public:
+  LocalSiteCharacteristicsNoopDataWriter();
+  ~LocalSiteCharacteristicsNoopDataWriter() override;
+
+  // SiteCharacteristicsDataWriter:
+  void NotifySiteLoaded() override;
+  void NotifySiteUnloaded() override;
+  void NotifyUpdatesFaviconInBackground() override;
+  void NotifyUpdatesTitleInBackground() override;
+  void NotifyUsesAudioInBackground() override;
+  void NotifyUsesNotificationsInBackground() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsNoopDataWriter);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_LOCAL_SITE_CHARACTERISTICS_NOOP_DATA_WRITER_H_
diff --git a/chrome/browser/resource_coordinator/site_characteristics_data_store.h b/chrome/browser/resource_coordinator/site_characteristics_data_store.h
index ebca4e4..970dc11 100644
--- a/chrome/browser/resource_coordinator/site_characteristics_data_store.h
+++ b/chrome/browser/resource_coordinator/site_characteristics_data_store.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/resource_coordinator/site_characteristics_data_reader.h"
+#include "chrome/browser/resource_coordinator/site_characteristics_data_writer.h"
 
 namespace resource_coordinator {
 
@@ -23,6 +24,10 @@
   virtual std::unique_ptr<SiteCharacteristicsDataReader> GetReaderForOrigin(
       const std::string& origin) = 0;
 
+  // Returns a SiteCharacteristicsDataWriter for the given origin.
+  virtual std::unique_ptr<SiteCharacteristicsDataWriter> GetWriterForOrigin(
+      const std::string& origin_str) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SiteCharacteristicsDataStore);
 };
diff --git a/chrome/browser/resource_coordinator/site_characteristics_data_writer.h b/chrome/browser/resource_coordinator/site_characteristics_data_writer.h
new file mode 100644
index 0000000..00f07823
--- /dev/null
+++ b/chrome/browser/resource_coordinator/site_characteristics_data_writer.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_SITE_CHARACTERISTICS_DATA_WRITER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_SITE_CHARACTERISTICS_DATA_WRITER_H_
+
+namespace resource_coordinator {
+
+// Pure virtual interface to record the observations made for an origin.
+class SiteCharacteristicsDataWriter {
+ public:
+  SiteCharacteristicsDataWriter() = default;
+  virtual ~SiteCharacteristicsDataWriter() {}
+
+  // Records tab load/unload events.
+  virtual void NotifySiteLoaded() = 0;
+  virtual void NotifySiteUnloaded() = 0;
+
+  // Records feature usage.
+  virtual void NotifyUpdatesFaviconInBackground() = 0;
+  virtual void NotifyUpdatesTitleInBackground() = 0;
+  virtual void NotifyUsesAudioInBackground() = 0;
+  virtual void NotifyUsesNotificationsInBackground() = 0;
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_SITE_CHARACTERISTICS_DATA_WRITER_H_
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.css b/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
index ad8d4af..c825d9e 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.css
@@ -20,6 +20,7 @@
   padding: 0;
 }
 
+.arc-tos-disable-skip #arc-tos-skip-button,
 .arc-tos-loaded .arc-tos-loading,
 .arc-tos-loaded .arc-tos-error,
 .arc-tos-loaded #arc-tos-retry-button,
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
index c77a14c..f198d1c 100644
--- a/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
+++ b/chrome/browser/resources/chromeos/login/screen_arc_terms_of_service.js
@@ -10,7 +10,7 @@
   return {
     EXTERNAL_API: [
       'setMetricsMode', 'setBackupAndRestoreMode', 'setLocationServicesMode',
-      'loadPlayStoreToS', 'setArcManaged'
+      'loadPlayStoreToS', 'setArcManaged', 'hideSkipButton'
     ],
 
     /** @override */
@@ -168,6 +168,13 @@
     },
 
     /**
+     * Hides the "Skip" button in the ToS screen.
+     */
+    hideSkipButton: function() {
+      this.addClass_('arc-tos-disable-skip');
+    },
+
+    /**
      * Loads Play Store ToS in case country code has been changed or previous
      * attempt failed.
      * @param {string} countryCode Country code based on current timezone.
@@ -306,7 +313,7 @@
     },
 
     /**
-     * Handles Retry button click.
+     * Handles Skip button click.
      */
     onSkip: function() {
       this.enableButtons_(false);
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
index a5d8368..088ad8ca 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
@@ -699,6 +699,8 @@
         this.recordSelectToSpeakStateChangeEvent_(
             StateChangeEvent.CANCEL_SELECTION);
     }
+    this.onStateChangeRequestedCallbackForTest_ &&
+        this.onStateChangeRequestedCallbackForTest_();
   },
 
   /**
@@ -1310,9 +1312,9 @@
   },
 
   /**
-   * Fires a mock state change request.
+   * Function to be called when a state change request is received from the
+   * accessibilityPrivate API.
+   * @type {?function()}
    */
-  fireMockStateChangeRequest: function() {
-    this.onStateChangeRequested_();
-  },
+  onStateChangeRequestedCallbackForTest_: null,
 };
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_e2e_test_base.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_e2e_test_base.js
index 49c264b..909da1f 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_e2e_test_base.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_e2e_test_base.js
@@ -87,8 +87,8 @@
    * |this.newCallback| if passed to asynchonous calls.  Otherwise, the test
    * will be finished prematurely.
    * @param {string} url Url to load and wait for.
-   * @param {function(chrome.automation.AutomationNode)} callback
-   *     Called once the document is ready.
+   * @param {function(chrome.automation.AutomationNode)} callback Called with
+   *     the desktop node once the document is ready.
    */
   runWithLoadedTree: function(url, callback) {
     callback = this.newCallback(callback);
@@ -99,7 +99,7 @@
 
         r.removeEventListener('focus', listener, true);
         r.removeEventListener('loadComplete', listener, true);
-        callback && callback(evt.target);
+        callback && callback(r);
         callback = null;
       };
       r.addEventListener('focus', listener, true);
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_mouse_selection_test.extjs b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_mouse_selection_test.extjs
index 1fe758a..b54be63 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_mouse_selection_test.extjs
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_mouse_selection_test.extjs
@@ -33,6 +33,19 @@
       selectToSpeak.fireMockKeyUpEvent(
           {keyCode: SelectToSpeak.SEARCH_KEY_CODE});
    },
+
+   tapTrayButton(desktop, callback) {
+     let button = desktop.find({roleType: 'button', attributes:
+         {className: SELECT_TO_SPEAK_TRAY_CLASS_NAME}
+     });
+     callback = this.newCallback(callback);
+     selectToSpeak.onStateChangeRequestedCallbackForTest_ =
+         this.newCallback(() => {
+           selectToSpeak.onStateChangeRequestedCallbackForTest_ = null;
+           callback();
+         });
+     button.doDefault();
+   },
 }
 
 TEST_F('SelectToSpeakMouseSelectionTest', 'SpeaksNodeWhenClicked',
@@ -124,7 +137,7 @@
 });
 
 TEST_F('SelectToSpeakMouseSelectionTest',
-    'SpeaksNodeWhenInSelectionModeAndClicked', function() {
+    'SpeaksNodeAfterTrayTapAndMouseClick', function() {
   this.runWithLoadedTree('data:text/html;charset=utf-8,' +
       '<p>This is some text</p>',
       function(desktop) {
@@ -144,9 +157,10 @@
                      screenY: textNode.location.top + 1};
         // A state change request should shift us into 'selecting' state from
         // 'inactive'.
-        selectToSpeak.fireMockStateChangeRequest();
-        selectToSpeak.fireMockMouseDownEvent(event);
-        selectToSpeak.fireMockMouseUpEvent(event);
+        this.tapTrayButton(desktop, () => {
+          selectToSpeak.fireMockMouseDownEvent(event);
+          selectToSpeak.fireMockMouseUpEvent(event);
+        });
       }
   );
 });
@@ -161,20 +175,20 @@
                      screenY: textNode.location.top + 1};
         // A state change request should shift us into 'selecting' state from
         // 'inactive'.
-        selectToSpeak.fireMockStateChangeRequest();
-        selectToSpeak.fireMockMouseDownEvent(event);
-        assertEquals(chrome.accessibilityPrivate.SelectToSpeakState.SELECTING,
-            selectToSpeak.state_);
+        this.tapTrayButton(desktop, () => {
+          selectToSpeak.fireMockMouseDownEvent(event);
+          assertEquals(SelectToSpeakState.SELECTING, selectToSpeak.state_);
 
-        // Another state change puts us back in 'inactive'.
-        selectToSpeak.fireMockStateChangeRequest();
-        assertEquals(chrome.accessibilityPrivate.SelectToSpeakState.INACTIVE,
-            selectToSpeak.state_);
+          // Another state change puts us back in 'inactive'.
+          this.tapTrayButton(desktop, () => {
+            assertEquals(SelectToSpeakState.INACTIVE, selectToSpeak.state_);
+          });
+        });
       }
   );
 });
 
-TEST_F('SelectToSpeakMouseSelectionTest', 'CancelsSpeechWithStateChange',
+TEST_F('SelectToSpeakMouseSelectionTest', 'CancelsSpeechWithTrayTap',
     function() {
   this.runWithLoadedTree('data:text/html;charset=utf-8,' +
       '<p>This is some text</p>',
@@ -187,15 +201,14 @@
               assertTrue(this.mockTts.currentlySpeaking());
               assertEquals(this.mockTts.pendingUtterances().length, 1);
               this.assertEqualsCollapseWhitespace(
-              this.mockTts.pendingUtterances()[0], 'This is some text');
+                  this.mockTts.pendingUtterances()[0], 'This is some text');
 
               // Cancel speech and make sure state resets to INACTIVE.
-              selectToSpeak.fireMockStateChangeRequest();
-              assertFalse(this.mockTts.currentlySpeaking());
-              assertEquals(this.mockTts.pendingUtterances().length, 0);
-              assertEquals(
-                  chrome.accessibilityPrivate.SelectToSpeakState.INACTIVE,
-                  selectToSpeak.state_);
+              this.tapTrayButton(desktop, () => {
+                assertFalse(this.mockTts.currentlySpeaking());
+                assertEquals(this.mockTts.pendingUtterances().length, 0);
+                assertEquals(SelectToSpeakState.INACTIVE, selectToSpeak.state_);
+              });
             }
         )]);
         let textNode = this.findTextNode(desktop, 'This is some text');
@@ -204,4 +217,38 @@
         this.selectRangeForSpeech(event, event);
       }
   );
-});
\ No newline at end of file
+});
+
+TEST_F('SelectToSpeakMouseSelectionTest', 'DoesNotSpeakOnlyTheTrayButton',
+    function() {
+  // The tray button itself should not be spoken when clicked in selection mode
+  // per UI review (but if more elements are being verbalized than just the STS
+  // tray button, it may be spoken). This is similar to how the stylus may
+  // act as a laser pointer unless it taps on the stylus options button, which
+  // always opens on a tap regardless of the stylus behavior selected.
+  chrome.automation.getDesktop(this.newCallback((desktop) => {
+    this.tapTrayButton(desktop, () => {
+      assertEquals(selectToSpeak.state_, SelectToSpeakState.SELECTING);
+      let button = desktop.find({roleType: 'button', attributes:
+          {className: SELECT_TO_SPEAK_TRAY_CLASS_NAME}
+      });
+
+      // Use the same automation callbacks as Select-to-Speak to make
+      // sure we actually don't start speech after the hittest and focus
+      // callbacks are used to check which nodes should be spoken.
+      desktop.addEventListener(
+        EventType.MOUSE_RELEASED, this.newCallback((evt) => {
+          chrome.automation.getFocus(this.newCallback((node) => {
+            assertEquals(selectToSpeak.state_, SelectToSpeakState.INACTIVE);
+            assertFalse(this.mockTts.currentlySpeaking());
+            assertEquals(this.mockTts.pendingUtterances().length, 0);
+          }));
+        }), true);
+
+      let event = {screenX: button.location.left + 1,
+                   screenY: button.location.top + 1};
+      selectToSpeak.fireMockMouseDownEvent(event);
+      selectToSpeak.fireMockMouseUpEvent(event);
+    });
+  }));
+});
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index 7f5e06f..cdba9162 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -94,13 +94,6 @@
         -webkit-margin-start: calc(var(--cr-button-edge-spacing) * -1);
       }
 
-      paper-toggle-button {
-        @apply --settings-actionable;
-        height: var(--settings-row-min-height);
-        user-select: none;  /* Prevents text selection while dragging. */
-        width: 36px;
-      }
-
       span ~ a {
         -webkit-margin-start: 4px;
       }
diff --git a/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc b/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc
index b6e8704..044bd04 100644
--- a/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc
+++ b/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc
@@ -36,11 +36,12 @@
   // |*destroyed_tracker| is set to true in the destructor.
   TestSSLBlockingPage(content::WebContents* web_contents,
                       GURL request_url,
+                      net::SSLInfo ssl_info,
                       bool* destroyed_tracker)
       : SSLBlockingPage(
             web_contents,
             net::ERR_CERT_CONTAINS_ERRORS,
-            net::SSLInfo(),
+            ssl_info,
             request_url,
             0,
             base::Time::NowFromSystemTime(),
@@ -72,9 +73,13 @@
   // corresponding blocking page is destroyed.
   void CreateAssociatedBlockingPage(content::NavigationHandle* handle,
                                     bool* destroyed_tracker) {
+    net::SSLInfo ssl_info;
+    ssl_info.cert =
+        net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+
     SSLErrorTabHelper::AssociateBlockingPage(
         web_contents(), handle->GetNavigationId(),
-        std::make_unique<TestSSLBlockingPage>(web_contents(), GURL(),
+        std::make_unique<TestSSLBlockingPage>(web_contents(), GURL(), ssl_info,
                                               destroyed_tracker));
   }
 };
diff --git a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
index 0fc5ec4..4ce9167 100644
--- a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
@@ -367,7 +367,6 @@
       original_data.disable_reasons(),
       original_data.incognito_enabled(),
       original_data.remote_install(),
-      original_data.all_urls_enabled(),
       original_data.installed_by_custodian(),
       original_data.app_launch_ordinal(),
       original_data.page_ordinal(),
diff --git a/chrome/browser/ui/android/ssl_client_certificate_request.cc b/chrome/browser/ui/android/ssl_client_certificate_request.cc
index ec5be1f..f53076a 100644
--- a/chrome/browser/ui/android/ssl_client_certificate_request.cc
+++ b/chrome/browser/ui/android/ssl_client_certificate_request.cc
@@ -160,7 +160,7 @@
 }
 
 static void NotifyClientCertificatesChanged() {
-  net::CertDatabase::GetInstance()->OnAndroidKeyStoreChanged();
+  net::CertDatabase::GetInstance()->NotifyObserversCertDBChanged();
 }
 
 static void
diff --git a/chrome/browser/ui/app_list/DEPS b/chrome/browser/ui/app_list/DEPS
index 53de606b..226b2da1 100644
--- a/chrome/browser/ui/app_list/DEPS
+++ b/chrome/browser/ui/app_list/DEPS
@@ -6,3 +6,10 @@
 
   "+ash/public",
 ]
+
+specific_include_rules = {
+  # TODO(733662): Remove when app_list is migrated.
+  "crostini_app_model_builder\.cc": [
+    "+ash/resources/grit/ash_resources.h",
+  ],
+}
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
index cd9517b..446fb5d 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/app_list/crostini/crostini_app_model_builder.h"
 
+#include "ash/resources/grit/ash_resources.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
@@ -11,9 +12,11 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/crostini/crostini_app_item.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
 #include "components/crx_file/id_util.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
 
 CrostiniAppModelBuilder::CrostiniAppModelBuilder(
     AppListControllerDelegate* controller)
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index c46297a..077d7cd 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -145,7 +145,7 @@
 
 void ChromeAutofillClient::ShowAutofillSettings() {
 #if defined(OS_ANDROID)
-  chrome::android::PreferencesLauncher::ShowAutofillSettings();
+  chrome::android::PreferencesLauncher::ShowAutofillSettings(web_contents());
 #else
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (browser)
diff --git a/chrome/browser/ui/cocoa/applescript/apple_event_util.mm b/chrome/browser/ui/cocoa/applescript/apple_event_util.mm
index bce3d2d..16d6856 100644
--- a/chrome/browser/ui/cocoa/applescript/apple_event_util.mm
+++ b/chrome/browser/ui/cocoa/applescript/apple_event_util.mm
@@ -102,6 +102,7 @@
 }
 
 bool IsJavaScriptEnabledForProfile(Profile* profile) {
+  DCHECK(profile);
   if (!base::FeatureList::IsEnabled(
           features::kAppleScriptExecuteJavaScriptMenuItem))
     return YES;
diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
index 33216fe..f0a489a0 100644
--- a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
@@ -105,6 +105,7 @@
   webContents_ = webContents;
   SessionTabHelper* session_tab_helper =
       SessionTabHelper::FromWebContents(webContents);
+  profile_ = Profile::FromBrowserContext(webContents->GetBrowserContext());
   base::scoped_nsobject<NSNumber> numID(
       [[NSNumber alloc] initWithInt:session_tab_helper->session_id().id()]);
   [self setUniqueID:numID];
@@ -127,6 +128,14 @@
 }
 
 - (void)setURL:(NSString*)aURL {
+  // If a scripter sets a URL before |webContents_| or |profile_| is set, save
+  // it at a temporary location. Once they're set, -setURL: will be call again
+  // with the temporary URL.
+  if (!profile_ || !webContents_) {
+    [self setTempURL:aURL];
+    return;
+  }
+
   GURL url(base::SysNSStringToUTF8(aURL));
   if (!chrome::mac::IsJavaScriptEnabledForProfile(profile_) &&
       url.SchemeIs(url::kJavaScriptScheme)) {
@@ -134,13 +143,6 @@
     return;
   }
 
-  // If a scripter sets a URL before the node is added save it at a temporary
-  // location.
-  if (!webContents_) {
-    [self setTempURL:aURL];
-    return;
-  }
-
   // check for valid url.
   if (!url.is_empty() && !url.is_valid()) {
     AppleScript::SetError(AppleScript::errInvalidURL);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index 5236891..4ff77a0 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -1999,7 +1999,7 @@
   }
   hasInsertionPos_ = NO;
   BookmarkButton* draggedButton = [BookmarkButton draggedButton];
-  if (!draggedButton) {
+  if (!draggedButton || [draggedButton bookmarkNode] == nullptr) {
     [self applyLayout:layout_ animated:YES];
     return;
   }
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 98f9472..0443afe 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -169,7 +169,7 @@
       {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_MESSAGE},
       {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_MESSAGE},
       {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_MESSAGE},
-      {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_MESSAGE},
+      // {CONTENT_SETTINGS_TYPE_POPUPS, No message. intentionally left out},
       {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
        IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
       {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_MESSAGE},
@@ -801,7 +801,7 @@
       {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
       {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK},
       {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK},
-      {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK},
+      {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_REDIRECTS_UNBLOCK},
       {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK},
       {CONTENT_SETTINGS_TYPE_SOUND, IDS_BLOCKED_SOUND_UNBLOCK},
       {CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_BLOCKED_CLIPBOARD_UNBLOCK},
@@ -829,7 +829,7 @@
       {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
       {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION},
       {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION},
-      {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION},
+      {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_REDIRECTS_NO_ACTION},
       {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION},
       {CONTENT_SETTINGS_TYPE_SOUND, IDS_BLOCKED_SOUND_NO_ACTION},
       {CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_BLOCKED_CLIPBOARD_NO_ACTION},
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc
index 77c5011..0934fee 100644
--- a/chrome/browser/ui/page_info/page_info_ui.cc
+++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -112,13 +112,7 @@
     {CONTENT_SETTINGS_TYPE_COOKIES, 0},
     {CONTENT_SETTINGS_TYPE_IMAGES, IDS_PAGE_INFO_TYPE_IMAGES},
     {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_PAGE_INFO_TYPE_JAVASCRIPT},
-#if defined(OS_ANDROID)
     {CONTENT_SETTINGS_TYPE_POPUPS, IDS_PAGE_INFO_TYPE_POPUPS_REDIRECTS},
-#else
-    // TODO(csharrison,ericrobinson): Use IDS_PAGE_INFO_TYPE_POPUPS_REDIRECTS on
-    // desktop as well.
-    {CONTENT_SETTINGS_TYPE_POPUPS, IDS_PAGE_INFO_TYPE_POPUPS},
-#endif
 #if BUILDFLAG(ENABLE_PLUGINS)
     {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_PAGE_INFO_TYPE_FLASH},
 #endif
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 f9629a6..d4a0932 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
@@ -329,7 +329,19 @@
     frame_header_->SchedulePaintForTitle();
 }
 
-void BrowserNonClientFrameViewAsh::SizeConstraintsChanged() {
+void BrowserNonClientFrameViewAsh::SizeConstraintsChanged() {}
+
+void BrowserNonClientFrameViewAsh::ActivationChanged(bool active) {
+  BrowserNonClientFrameView::ActivationChanged(active);
+
+  const bool should_paint_as_active = ShouldPaintAsActive();
+  frame_header_->SetPaintAsActive(should_paint_as_active);
+
+  if (hosted_app_button_container_)
+    hosted_app_button_container_->SetPaintAsActive(should_paint_as_active);
+
+  if (frame_header_origin_text_)
+    frame_header_origin_text_->SetPaintAsActive(should_paint_as_active);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -339,20 +351,11 @@
   if (!ShouldPaint())
     return;
 
-  const bool should_paint_as_active = ShouldPaintAsActive();
-  frame_header_->SetPaintAsActive(should_paint_as_active);
-
   const ash::FrameHeader::Mode header_mode =
-      should_paint_as_active ? ash::FrameHeader::MODE_ACTIVE
-                             : ash::FrameHeader::MODE_INACTIVE;
+      ShouldPaintAsActive() ? ash::FrameHeader::MODE_ACTIVE
+                            : ash::FrameHeader::MODE_INACTIVE;
   frame_header_->PaintHeader(canvas, header_mode);
 
-  if (hosted_app_button_container_)
-    hosted_app_button_container_->SetPaintAsActive(should_paint_as_active);
-
-  if (frame_header_origin_text_)
-    frame_header_origin_text_->SetPaintAsActive(should_paint_as_active);
-
   if (browser_view()->IsToolbarVisible() &&
       !browser_view()->toolbar()->GetPreferredSize().IsEmpty() &&
       browser_view()->IsTabStripVisible()) {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
index 80dfc1f9..d3073ad 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -70,6 +70,7 @@
   void UpdateWindowIcon() override;
   void UpdateWindowTitle() override;
   void SizeConstraintsChanged() override;
+  void ActivationChanged(bool active) override;
 
   // views::View:
   void OnPaint(gfx::Canvas* canvas) override;
@@ -133,6 +134,8 @@
   FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshTest,
                            ToggleTabletModeOnMinimizedWindow);
   FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshTest,
+                           ActiveStateOfButtonMatchesWidget);
+  FRIEND_TEST_ALL_PREFIXES(BrowserNonClientFrameViewAshTest,
                            RestoreMinimizedBrowserUpdatesCaption);
   FRIEND_TEST_ALL_PREFIXES(ImmersiveModeControllerAshHostedAppBrowserTest,
                            FrameLayoutToggleTabletMode);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 12ba5cb..df850862 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -453,6 +453,19 @@
             *test.size_button()->icon_definition_for_test()->name);
 }
 
+// Regression test for https://crbug.com/839955
+IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
+                       ActiveStateOfButtonMatchesWidget) {
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
+
+  ash::FrameCaptionButtonContainerView::TestApi test(
+      GetFrameViewAsh(browser_view)->caption_button_container_);
+  EXPECT_TRUE(test.size_button()->paint_as_active());
+
+  browser_view->GetWidget()->Deactivate();
+  EXPECT_FALSE(test.size_button()->paint_as_active());
+}
+
 // This is a regression test that session restore minimized browser should
 // update caption buttons (https://crbug.com/827444).
 IN_PROC_BROWSER_TEST_P(BrowserNonClientFrameViewAshTest,
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 18c97e9f..cf8e89f0 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -966,6 +966,29 @@
   toolbar_button_provider_ = provider;
 }
 
+const views::View::Views BrowserView::DesiredPaintOrderForViews(
+    const views::View::Views views) {
+  // Ink drops in the toolbar can spread beyond the toolbar bounds, so if the
+  // bookmark bar is attached, we want it to be below the toolbar so the toolbar
+  // ink drops draw atop it.  This doesn't cause a problem for interactions with
+  // the bookmark bar, since it does not host any ink drops that spread beyond
+  // its bounds.  If it did, we would need to change how ink drops are drawn.
+  auto it = std::find(views.cbegin(), views.cend(), bookmark_bar_view_.get());
+  if (it == views.cend())
+    return views;
+
+  views::View::Views result = {*it};
+  for (auto* view : views) {
+    if (view != *it)
+      result.push_back(view);
+  }
+  return result;
+}
+
+views::View::Views BrowserView::GetChildrenInZOrder() {
+  return DesiredPaintOrderForViews(views::View::GetChildrenInZOrder());
+}
+
 LocationBar* BrowserView::GetLocationBar() const {
   return GetLocationBarView();
 }
@@ -2287,7 +2310,10 @@
       new_parent = top_container_;
   }
   if (new_parent != bookmark_bar_view_->parent()) {
-    SetBookmarkBarParent(new_parent);
+    if (new_parent == nullptr)
+      bookmark_bar_view_->parent()->RemoveChildView(bookmark_bar_view_.get());
+    else
+      new_parent->AddChildView(bookmark_bar_view_.get());
     needs_layout = true;
   }
 
@@ -2299,38 +2325,6 @@
   return needs_layout;
 }
 
-void BrowserView::SetBookmarkBarParent(views::View* new_parent) {
-  // Because children are drawn in order, the child order also affects z-order:
-  // earlier children will appear "below" later ones.  This is important for ink
-  // drops, which are drawn with the z-order of the view that parents them.  Ink
-  // drops in the toolbar can spread beyond the toolbar bounds, so if the
-  // bookmark bar is attached, we want it to be below the toolbar so the toolbar
-  // ink drops draw atop it.  This doesn't cause a problem for interactions with
-  // the bookmark bar, since it does not host any ink drops that spread beyond
-  // its bounds.  If it did, we would need to change how ink drops are drawn.
-  // TODO(bruthig): Consider a more general mechanism for manipulating the
-  // z-order of the ink drops.
-
-  if (new_parent == this) {
-    // BookmarkBarView is detached.
-    const int top_container_index = GetIndexOf(top_container_);
-    DCHECK_GE(top_container_index, 0);
-    // |top_container_| contains the toolbar, so putting the bookmark bar ahead
-    // of it will ensure it's drawn before the toolbar.
-    AddChildViewAt(bookmark_bar_view_.get(), top_container_index);
-  } else if (new_parent == top_container_) {
-    // BookmarkBarView is attached.
-
-    // The toolbar is a child of |top_container_|, so making the bookmark bar
-    // the first child ensures it's drawn before the toolbar.
-    new_parent->AddChildViewAt(bookmark_bar_view_.get(), 0);
-  } else {
-    DCHECK(!new_parent);
-    // Bookmark bar is being detached from all views because it is hidden.
-    bookmark_bar_view_->parent()->RemoveChildView(bookmark_bar_view_.get());
-  }
-}
-
 bool BrowserView::MaybeShowInfoBar(WebContents* contents) {
   // TODO(beng): Remove this function once the interface between
   //             InfoBarContainer, DownloadShelfView and WebContents and this
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 323642d..fe5d9f6 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -266,6 +266,13 @@
     return toolbar_button_provider_;
   }
 
+  // Returns |views| reordered in the order in which they should be painted,
+  // suitable for returning in |GetChildrenInZOrder|. This is a public method
+  // so that |TopContainerView| can call into it, as it has no knowledge of
+  // what its subviews are.
+  const views::View::Views DesiredPaintOrderForViews(
+      const views::View::Views views);
+
   // Overridden from BrowserWindow:
   void Show() override;
   void ShowInactive() override;
@@ -451,6 +458,7 @@
 
   // Overridden from views::View:
   const char* GetClassName() const override;
+  View::Views GetChildrenInZOrder() override;
   void Layout() override;
   void OnGestureEvent(ui::GestureEvent* event) override;
   void ViewHierarchyChanged(
@@ -538,11 +546,6 @@
   // |contents| can be null.
   bool MaybeShowBookmarkBar(content::WebContents* contents);
 
-  // Moves the bookmark bar view to the specified parent, which may be null,
-  // |this|, or |top_container_|. Ensures that |top_container_| stays in front
-  // of |bookmark_bar_view_|.
-  void SetBookmarkBarParent(views::View* new_parent);
-
   // Prepare to show an Info Bar for the specified WebContents. Returns
   // true if there is an Info Bar to show and one is supported for this Browser
   // type, and there should be a subsequent re-layout to show it.
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc
index 7658f06..a3cc69a1 100644
--- a/chrome/browser/ui/views/frame/browser_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -96,15 +96,6 @@
   EXPECT_EQ(top_container, browser_view()->GetBookmarkBarView()->parent());
   EXPECT_EQ(browser_view(), browser_view()->infobar_container()->parent());
 
-  // Find bar host is at the front of the view hierarchy, followed by the
-  // infobar container and then top container.
-  EXPECT_EQ(browser_view()->child_count() - 1,
-            browser_view()->GetIndexOf(browser_view()->find_bar_host_view()));
-  EXPECT_EQ(browser_view()->child_count() - 2,
-            browser_view()->GetIndexOf(browser_view()->infobar_container()));
-  EXPECT_EQ(browser_view()->child_count() - 3,
-            browser_view()->GetIndexOf(top_container));
-
   // Verify basic layout.
   EXPECT_EQ(0, top_container->x());
   EXPECT_EQ(0, top_container->y());
@@ -145,15 +136,6 @@
   EXPECT_TRUE(bookmark_bar->IsDetached());
   EXPECT_EQ(browser_view(), bookmark_bar->parent());
 
-  // Find bar host is still at the front of the view hierarchy, followed by the
-  // infobar container and then top container.
-  EXPECT_EQ(browser_view()->child_count() - 1,
-            browser_view()->GetIndexOf(browser_view()->find_bar_host_view()));
-  EXPECT_EQ(browser_view()->child_count() - 2,
-            browser_view()->GetIndexOf(browser_view()->infobar_container()));
-  EXPECT_EQ(browser_view()->child_count() - 3,
-            browser_view()->GetIndexOf(top_container));
-
   // Bookmark bar layout on NTP.
   EXPECT_EQ(0, bookmark_bar->x());
   EXPECT_EQ(tabstrip->bounds().bottom() + toolbar->height(), bookmark_bar->y());
@@ -175,6 +157,31 @@
   BookmarkBarView::DisableAnimationsForTesting(false);
 }
 
+TEST_F(BrowserViewTest, BookmarkBarPaintsFirst) {
+  // The bookmark bar should be first in the z-order of its parent so that
+  // any ink drops from the toolbar can overlap it.
+
+  BookmarkBarView::DisableAnimationsForTesting(true);
+
+  Browser* browser = browser_view()->browser();
+
+  // Attached bookmark bar.
+  AddTab(browser, GURL("about:blank"));
+  chrome::ExecuteCommand(browser, IDC_SHOW_BOOKMARK_BAR);
+  EXPECT_EQ(browser_view()->top_container()->GetChildrenInZOrder()[0],
+            browser_view()->GetBookmarkBarView());
+
+  // If "Always Show Bookmark Bar" is off, the NTP displays the detached
+  // bookmark bar.
+  chrome::ExecuteCommand(browser, IDC_SHOW_BOOKMARK_BAR);
+  NavigateAndCommitActiveTabWithTitle(browser, GURL(chrome::kChromeUINewTabURL),
+                                      base::string16());
+  EXPECT_EQ(browser_view()->GetChildrenInZOrder()[0],
+            browser_view()->GetBookmarkBarView());
+
+  BookmarkBarView::DisableAnimationsForTesting(false);
+}
+
 // Test that repeated accelerators are processed or ignored depending on the
 // commands that they refer to. The behavior for different commands is dictated
 // by IsCommandRepeatable() in chrome/browser/ui/views/accelerator_table.h.
diff --git a/chrome/browser/ui/views/frame/top_container_view.cc b/chrome/browser/ui/views/frame/top_container_view.cc
index 188132c..d3d1627 100644
--- a/chrome/browser/ui/views/frame/top_container_view.cc
+++ b/chrome/browser/ui/views/frame/top_container_view.cc
@@ -45,3 +45,8 @@
 void TopContainerView::ChildPreferredSizeChanged(views::View* child) {
   PreferredSizeChanged();
 }
+
+views::View::Views TopContainerView::GetChildrenInZOrder() {
+  return browser_view_->DesiredPaintOrderForViews(
+      views::View::GetChildrenInZOrder());
+}
diff --git a/chrome/browser/ui/views/frame/top_container_view.h b/chrome/browser/ui/views/frame/top_container_view.h
index 5ffacf8..f21a3b00 100644
--- a/chrome/browser/ui/views/frame/top_container_view.h
+++ b/chrome/browser/ui/views/frame/top_container_view.h
@@ -23,6 +23,7 @@
   const char* GetClassName() const override;
   void PaintChildren(const views::PaintInfo& paint_info) override;
   void ChildPreferredSizeChanged(views::View* child) override;
+  views::View::Views GetChildrenInZOrder() override;
 
  private:
   // The parent of this view. Not owned.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
index 1108151..a38bc20 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -151,12 +151,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxMatchCellView:
 
-OmniboxMatchCellView::OmniboxMatchCellView(OmniboxResultView* result_view,
-                                           int text_height)
+OmniboxMatchCellView::OmniboxMatchCellView(OmniboxResultView* result_view)
     : is_old_style_answer_(false),
       is_rich_suggestion_(false),
-      is_search_type_(false),
-      text_height_(text_height) {
+      is_search_type_(false) {
   AddChildView(icon_view_ = new OmniboxImageView());
   AddChildView(image_view_ = new OmniboxImageView());
   AddChildView(content_view_ = new OmniboxTextView(result_view));
@@ -171,8 +169,9 @@
 OmniboxMatchCellView::~OmniboxMatchCellView() = default;
 
 gfx::Size OmniboxMatchCellView::CalculatePreferredSize() const {
-  int height = text_height_ +
-               GetVerticalInsets(text_height_, is_old_style_answer_).height();
+  const int text_height = content_view_->GetLineHeight();
+  int height = text_height +
+               GetVerticalInsets(text_height, is_old_style_answer_).height();
   if (is_rich_suggestion_ || is_old_style_answer_) {
     height += GetDescriptionHeight();
   }
@@ -242,14 +241,15 @@
 }
 
 void OmniboxMatchCellView::LayoutOldStyleAnswer() {
+  const int text_height = content_view_->GetLineHeight();
   int x = GetIconAlignmentOffset() + HorizontalPadding();
-  int y = GetVerticalInsets(text_height_, /*is_old_style_answer=*/true).top();
+  int y = GetVerticalInsets(text_height, /*is_old_style_answer=*/true).top();
   icon_view_->SetSize(icon_view_->CalculatePreferredSize());
   icon_view_->SetPosition(
-      gfx::Point(x, y + (text_height_ - icon_view_->height()) / 2));
+      gfx::Point(x, y + (text_height - icon_view_->height()) / 2));
   x += icon_view_->width() + HorizontalPadding();
-  content_view_->SetBounds(x, y, width() - x, text_height_);
-  y += text_height_;
+  content_view_->SetBounds(x, y, width() - x, text_height);
+  y += text_height;
   if (image_view_->visible()) {
     // The description may be multi-line. Using the view height results in
     // an image that's too large, so we use the line height here instead.
@@ -267,14 +267,15 @@
 }
 
 void OmniboxMatchCellView::LayoutRichSuggestion() {
+  const int text_height = content_view_->GetLineHeight();
   int x = GetIconAlignmentOffset() + HorizontalPadding();
-  int y = GetVerticalInsets(text_height_, /*is_old_style_answer=*/false).top();
+  int y = GetVerticalInsets(text_height, /*is_old_style_answer=*/false).top();
   image_view_->SetImageSize(gfx::Size(kRichImageSize, kRichImageSize));
-  image_view_->SetBounds(x, y + (text_height_ * 2 - kRichImageSize) / 2,
+  image_view_->SetBounds(x, y + (text_height * 2 - kRichImageSize) / 2,
                          kRichImageSize, kRichImageSize);
   x += kRichImageSize + HorizontalPadding();
-  content_view_->SetBounds(x, y, width() - x, text_height_);
-  y += text_height_;
+  content_view_->SetBounds(x, y, width() - x, text_height);
+  y += text_height;
   int description_width = width() - x;
   description_view_->SetBounds(
       x, y, description_width,
@@ -283,11 +284,12 @@
 }
 
 void OmniboxMatchCellView::LayoutSplit() {
+  const int text_height = content_view_->GetLineHeight();
   int x = GetIconAlignmentOffset() + HorizontalPadding();
   icon_view_->SetSize(icon_view_->CalculatePreferredSize());
-  int y = GetVerticalInsets(text_height_, /*is_old_style_answer=*/false).top();
+  int y = GetVerticalInsets(text_height, /*is_old_style_answer=*/false).top();
   icon_view_->SetPosition(
-      gfx::Point(x, y + (text_height_ - icon_view_->height()) / 2));
+      gfx::Point(x, y + (text_height - icon_view_->height()) / 2));
   x += icon_view_->width() + HorizontalPadding();
   int content_width = content_view_->CalculatePreferredSize().width();
   int description_width = description_view_->CalculatePreferredSize().width();
@@ -296,13 +298,13 @@
       content_width, separator_size.width(), description_width, width() - x,
       /*description_on_separate_line=*/false, !is_search_type_, &content_width,
       &description_width);
-  content_view_->SetBounds(x, y, content_width, text_height_);
+  content_view_->SetBounds(x, y, content_width, text_height);
   if (description_width != 0) {
     x += content_view_->width();
     separator_view_->SetSize(separator_size);
-    separator_view_->SetBounds(x, y, separator_view_->width(), text_height_);
+    separator_view_->SetBounds(x, y, separator_view_->width(), text_height);
     x += separator_view_->width();
-    description_view_->SetBounds(x, y, description_width, text_height_);
+    description_view_->SetBounds(x, y, description_width, text_height);
   } else {
     description_view_->SetSize(gfx::Size());
     separator_view_->SetSize(gfx::Size());
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h
index f8cbeef..b3aff004 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h
@@ -17,8 +17,7 @@
 
 class OmniboxMatchCellView : public views::View {
  public:
-  explicit OmniboxMatchCellView(OmniboxResultView* result_view,
-                                int text_height);
+  explicit OmniboxMatchCellView(OmniboxResultView* result_view);
   ~OmniboxMatchCellView() override;
 
   views::ImageView* icon() { return icon_view_; }
@@ -49,7 +48,6 @@
   bool is_old_style_answer_;
   bool is_rich_suggestion_;
   bool is_search_type_;
-  int text_height_;
 
   // Weak pointers for easy reference.
   views::ImageView* icon_view_;   // An icon representing the type or content.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 21d388a..4596c52 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -210,14 +210,12 @@
 // OmniboxPopupContentsView, public:
 
 OmniboxPopupContentsView::OmniboxPopupContentsView(
-    const gfx::FontList& font_list,
     OmniboxView* omnibox_view,
     OmniboxEditModel* edit_model,
     LocationBarView* location_bar_view)
     : model_(new OmniboxPopupModel(this, edit_model)),
       omnibox_view_(omnibox_view),
       location_bar_view_(location_bar_view),
-      font_list_(font_list),
       start_margin_(0),
       end_margin_(0) {
   // The contents is owned by the LocationBarView.
@@ -227,7 +225,7 @@
     InitializeWideShadows();
 
   for (size_t i = 0; i < AutocompleteResult::GetMaxMatches(); ++i) {
-    OmniboxResultView* result_view = new OmniboxResultView(this, i, font_list_);
+    OmniboxResultView* result_view = new OmniboxResultView(this, i);
     result_view->SetVisible(false);
     AddChildViewAt(result_view, static_cast<int>(i));
   }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
index 806132e3..85511e7 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
@@ -26,8 +26,7 @@
 // A view representing the contents of the autocomplete popup.
 class OmniboxPopupContentsView : public views::View, public OmniboxPopupView {
  public:
-  OmniboxPopupContentsView(const gfx::FontList& font_list,
-                           OmniboxView* omnibox_view,
+  OmniboxPopupContentsView(OmniboxView* omnibox_view,
                            OmniboxEditModel* edit_model,
                            LocationBarView* location_bar_view);
   ~OmniboxPopupContentsView() override;
@@ -123,9 +122,6 @@
 
   LocationBarView* location_bar_view_;
 
-  // The font list used for result rows, based on the omnibox font list.
-  gfx::FontList font_list_;
-
   int start_margin_;
   int end_margin_;
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 03fd742..2ce1ed0 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -44,7 +44,6 @@
 #include "ui/gfx/paint_vector_icon.h"
 
 namespace {
-
 // The vertical padding to provide each RenderText in addition to the height of
 // the font. Where possible, RenderText uses this additional space to vertically
 // center the cap height of the font instead of centering the entire font.
@@ -85,20 +84,15 @@
 // OmniboxResultView, public:
 
 OmniboxResultView::OmniboxResultView(OmniboxPopupContentsView* model,
-                                     int model_index,
-                                     const gfx::FontList& font_list)
+                                     int model_index)
     : model_(model),
       model_index_(model_index),
       is_hovered_(false),
-      font_height_(std::max(
-          font_list.GetHeight(),
-          font_list.DeriveWithWeight(gfx::Font::Weight::BOLD).GetHeight())),
       animation_(new gfx::SlideAnimation(this)) {
   CHECK_GE(model_index, 0);
 
-  AddChildView(suggestion_view_ =
-                   new OmniboxMatchCellView(this, GetTextHeight()));
-  AddChildView(keyword_view_ = new OmniboxMatchCellView(this, GetTextHeight()));
+  AddChildView(suggestion_view_ = new OmniboxMatchCellView(this));
+  AddChildView(keyword_view_ = new OmniboxMatchCellView(this));
 
   keyword_view_->icon()->EnableCanvasFlippingForRTLUI(true);
   keyword_view_->icon()->SetImage(gfx::CreateVectorIcon(
@@ -122,8 +116,11 @@
 
   // Set up 'switch to tab' button.
   if (match.has_tab_match && !match_.associated_keyword.get()) {
-    suggestion_tab_switch_button_ =
-        std::make_unique<OmniboxTabSwitchButton>(model_, this, GetTextHeight());
+    // TODO(dschuyler): the kVerticalPadding is added here, and again within
+    // OmniboxTabSwitchButton. Should that just be done once?
+    suggestion_tab_switch_button_ = std::make_unique<OmniboxTabSwitchButton>(
+        model_, this,
+        suggestion_view_->content()->GetLineHeight() + kVerticalPadding);
     suggestion_tab_switch_button_->set_owned_by_client();
     AddChildView(suggestion_tab_switch_button_.get());
   } else {
@@ -323,10 +320,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxResultView, private:
 
-int OmniboxResultView::GetTextHeight() const {
-  return font_height_ + kVerticalPadding;
-}
-
 gfx::Image OmniboxResultView::GetIcon() const {
   return model_->GetMatchIcon(match_, GetColor(OmniboxPart::RESULTS_ICON));
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index f808bbe..432cfa2b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -38,9 +38,7 @@
                           private gfx::AnimationDelegate,
                           public views::ButtonListener {
  public:
-  OmniboxResultView(OmniboxPopupContentsView* model,
-                    int model_index,
-                    const gfx::FontList& font_list);
+  OmniboxResultView(OmniboxPopupContentsView* model, int model_index);
   ~OmniboxResultView() override;
 
   // Helper to get the color for |part| using the current state and tint.
@@ -112,9 +110,6 @@
   // Whether this view is in the hovered state.
   bool is_hovered_;
 
-  // Cache the font height as a minor optimization.
-  int font_height_;
-
   // The data this class is built to display (the "Omnibox Result").
   AutocompleteMatch match_;
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
index 5b8d4a4..96dc8b0 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
@@ -29,7 +29,10 @@
 class TestOmniboxPopupContentsView : public OmniboxPopupContentsView {
  public:
   explicit TestOmniboxPopupContentsView(OmniboxEditModel* edit_model)
-      : OmniboxPopupContentsView(gfx::FontList(), nullptr, edit_model, nullptr),
+      : OmniboxPopupContentsView(
+            /*omnibox_view=*/nullptr,
+            edit_model,
+            /*location_bar_view=*/nullptr),
         selected_index_(0) {}
 
   void SetSelectedLine(size_t index) override { selected_index_ = index; }
@@ -55,8 +58,8 @@
         nullptr, nullptr, std::make_unique<TestOmniboxClient>());
     popup_view_ =
         std::make_unique<TestOmniboxPopupContentsView>(edit_model_.get());
-    result_view_ = new OmniboxResultView(popup_view_.get(),
-                                         kTestResultViewIndex, gfx::FontList());
+    result_view_ =
+        new OmniboxResultView(popup_view_.get(), kTestResultViewIndex);
 
     // Create a widget and assign bounds to support calls to HitTestPoint.
     widget_.reset(new views::Widget);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
index d243db0..46f6582 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
@@ -233,21 +233,20 @@
 
 void OmniboxTextView::SetText(const SuggestionAnswer::ImageLine& line) {
   wrap_text_lines_ = line.num_text_lines() > 1;
-  // This assumes that the first text type in the line can be used to specify
-  // the font for all the text fields in the line.  For now this works but
-  // eventually it may be necessary to get RenderText to support multiple font
-  // sizes or use multiple RenderTexts.
   render_text_.reset();
-  render_text_ = CreateText(line, GetFontForType(line.text_fields()[0].type()));
+  render_text_ = CreateText(line);
   UpdateLineHeight();
 }
 
 std::unique_ptr<gfx::RenderText> OmniboxTextView::CreateText(
-    const SuggestionAnswer::ImageLine& line,
-    const gfx::FontList& font_list) const {
+    const SuggestionAnswer::ImageLine& line) const {
   std::unique_ptr<gfx::RenderText> destination =
       CreateRenderText(base::string16());
-  destination->SetFontList(font_list);
+  // This assumes that the first text type in the line can be used to specify
+  // the font for all the text fields in the line.  For now this works but
+  // eventually it may be necessary to get RenderText to support multiple font
+  // sizes or use multiple RenderTexts.
+  destination->SetFontList(GetFontForType(line.text_fields()[0].type()));
 
   for (const SuggestionAnswer::TextField& text_field : line.text_fields())
     AppendText(destination.get(), text_field.text(), text_field.type());
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.h b/chrome/browser/ui/views/omnibox/omnibox_text_view.h
index ee16eb19..15d3e32 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_text_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.h
@@ -63,8 +63,7 @@
 
   // Creates a RenderText with text and styling from the image line.
   std::unique_ptr<gfx::RenderText> CreateText(
-      const SuggestionAnswer::ImageLine& line,
-      const gfx::FontList& font_list) const;
+      const SuggestionAnswer::ImageLine& line) const;
 
   // Adds |text| to |destination|.  |text_type| is an index into the
   // kTextStyles constant defined in the .cc file and is used to style the text,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index f50c24d..7461c8a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -159,8 +159,8 @@
 
   if (location_bar_view_) {
     // Initialize the popup view using the same font.
-    popup_view_.reset(new OmniboxPopupContentsView(GetFontList(), this, model(),
-                                                   location_bar_view_));
+    popup_view_.reset(
+        new OmniboxPopupContentsView(this, model(), location_bar_view_));
   }
 
   // Override the default FocusableBorder from Textfield, since the
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index a01419a0..e106328f 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1090,47 +1090,46 @@
       PaintTabBackgroundStroke(canvas, fill_path, stroke_path, active,
                                stroke_color);
     }
-    return;
-  }
+  } else {
+    BackgroundCache& cache =
+        active ? background_active_cache_ : background_inactive_cache_;
+    if (!cache.CacheKeyMatches(canvas->image_scale(), size(), active_color,
+                               inactive_color, stroke_color)) {
+      gfx::Path fill_path =
+          GetInteriorPath(canvas->image_scale(), size(), endcap_width);
+      gfx::Path stroke_path = GetBorderPath(canvas->image_scale(), false, false,
+                                            endcap_width, size());
+      cc::PaintRecorder recorder;
 
-  BackgroundCache& cache =
-      active ? background_active_cache_ : background_inactive_cache_;
-  if (!cache.CacheKeyMatches(canvas->image_scale(), size(), active_color,
-                             inactive_color, stroke_color)) {
-    gfx::Path fill_path =
-        GetInteriorPath(canvas->image_scale(), size(), endcap_width);
-    gfx::Path stroke_path = GetBorderPath(canvas->image_scale(), false, false,
-                                          endcap_width, size());
-    cc::PaintRecorder recorder;
+      {
+        gfx::Canvas cache_canvas(
+            recorder.beginRecording(size().width(), size().height()),
+            canvas->image_scale());
+        PaintTabBackgroundFill(&cache_canvas, fill_path, active,
+                               paint_hover_effect, active_color, inactive_color,
+                               fill_id, y_offset);
+        cache.fill_record = recorder.finishRecordingAsPicture();
+      }
+      if (TabStrip::ShouldDrawStrokes()) {
+        gfx::Canvas cache_canvas(
+            recorder.beginRecording(size().width(), size().height()),
+            canvas->image_scale());
+        PaintTabBackgroundStroke(&cache_canvas, fill_path, stroke_path, active,
+                                 stroke_color);
+        cache.stroke_record = recorder.finishRecordingAsPicture();
+      }
 
-    {
-      gfx::Canvas cache_canvas(
-          recorder.beginRecording(size().width(), size().height()),
-          canvas->image_scale());
-      PaintTabBackgroundFill(&cache_canvas, fill_path, active,
-                             paint_hover_effect, active_color, inactive_color,
-                             fill_id, y_offset);
-      cache.fill_record = recorder.finishRecordingAsPicture();
+      cache.SetCacheKey(canvas->image_scale(), size(), active_color,
+                        inactive_color, stroke_color);
     }
+
+    canvas->sk_canvas()->drawPicture(cache.fill_record);
     if (TabStrip::ShouldDrawStrokes()) {
-      gfx::Canvas cache_canvas(
-          recorder.beginRecording(size().width(), size().height()),
-          canvas->image_scale());
-      PaintTabBackgroundStroke(&cache_canvas, fill_path, stroke_path, active,
-                               stroke_color);
-      cache.stroke_record = recorder.finishRecordingAsPicture();
+      gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
+      if (clip)
+        canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
+      canvas->sk_canvas()->drawPicture(cache.stroke_record);
     }
-
-    cache.SetCacheKey(canvas->image_scale(), size(), active_color,
-                      inactive_color, stroke_color);
-  }
-
-  canvas->sk_canvas()->drawPicture(cache.fill_record);
-  if (TabStrip::ShouldDrawStrokes()) {
-    gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
-    if (clip)
-      canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
-    canvas->sk_canvas()->drawPicture(cache.stroke_record);
   }
 
   if (!active)
@@ -1195,25 +1194,33 @@
 }
 
 void Tab::PaintSeparator(gfx::Canvas* canvas, SkColor inactive_color) {
-  if (MD::GetMode() != MD::MATERIAL_REFRESH || IsMouseHovered())
+  if (MD::GetMode() != MD::MATERIAL_REFRESH)
     return;
 
-  // If the tab to the left is either active or the mouse is hovered over it,
-  // the separator on this tab should not be painted.
+  // If the tab to the left is active, the separator on this tab should not be
+  // painted.
   Tab* previous_tab =
       controller_->GetAdjacentTab(this, TabController::BACKWARD);
-  if (previous_tab &&
-      (previous_tab->IsActive() || previous_tab->IsMouseHovered()))
+  if (previous_tab && previous_tab->IsActive())
     return;
 
   const int tab_height = GetContentsBounds().height();
   gfx::RectF separator_bounds;
   separator_bounds.set_size(gfx::SizeF(1, 16));
   separator_bounds.set_origin(gfx::PointF(
-      (tab_height - separator_bounds.height()) / 2, GetTabEndcapWidth() / 2));
+      GetTabEndcapWidth() / 2, (tab_height - separator_bounds.height()) / 2));
+  // The following will paint the separator using an opacity that should
+  // cross-fade with the maximum hover animation value of this tab or the
+  // tab to the left. This will have the effect of fading out the separator
+  // while this tab's or the tab to the left's hover animation is progressing.
+  const double max_hover_value = std::max(
+      hover_controller_.GetAnimationValue(),
+      previous_tab ? previous_tab->hover_controller()->GetAnimationValue() : 0);
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-  flags.setColor(color_utils::BlendTowardOppositeLuma(inactive_color, 0x5a));
+  flags.setColor(
+      SkColorSetA(color_utils::BlendTowardOppositeLuma(inactive_color, 0x5a),
+                  gfx::Tween::IntValueBetween(max_hover_value, 255, 0)));
   canvas->DrawRect(separator_bounds, flags);
 }
 
@@ -1295,7 +1302,7 @@
       int title_width =
           (!showing_icon_ + !showing_alert_indicator_) * favicon_width;
       if ((!hide_inactive_close_button ||
-           (show_close_button_on_hover && IsMouseHovered())) &&
+           (show_close_button_on_hover && hover_controller_.ShouldDraw())) &&
           (title_width + close_button_width + extra_padding <=
            available_width)) {
         showing_close_button_ = true;
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.cc b/chrome/browser/ui/views/tabs/tab_close_button.cc
index c87643b3..2dfe8d1 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_close_button.cc
@@ -18,6 +18,8 @@
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/material_design/material_design_controller.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -104,6 +106,12 @@
   return "TabCloseButton";
 }
 
+void TabCloseButton::PaintButtonContents(gfx::Canvas* canvas) {
+  canvas->SaveLayerAlpha(GetOpacity());
+  views::ImageButton::PaintButtonContents(canvas);
+  canvas->Restore();
+}
+
 views::View* TabCloseButton::TargetForRect(views::View* root,
                                            const gfx::Rect& rect) {
   CHECK_EQ(root, this);
@@ -137,6 +145,14 @@
   return true;
 }
 
+SkAlpha TabCloseButton::GetOpacity() {
+  if (MD::GetMode() != MD::MATERIAL_REFRESH && !IsMouseHovered())
+    return SK_AlphaOPAQUE;
+  const double animation_value =
+      static_cast<Tab*>(parent())->hover_controller()->GetAnimationValue();
+  return gfx::Tween::IntValueBetween(animation_value, 0, 255);
+}
+
 void TabCloseButton::GenerateImages(bool is_touch,
                                     SkColor normal_icon_color,
                                     SkColor hover_pressed_icon_color,
diff --git a/chrome/browser/ui/views/tabs/tab_close_button.h b/chrome/browser/ui/views/tabs/tab_close_button.h
index 12cd81cb..932d189 100644
--- a/chrome/browser/ui/views/tabs/tab_close_button.h
+++ b/chrome/browser/ui/views/tabs/tab_close_button.h
@@ -48,11 +48,18 @@
   void OnGestureEvent(ui::GestureEvent* event) override;
   const char* GetClassName() const override;
 
+ protected:
+  void PaintButtonContents(gfx::Canvas* canvas) override;
+
  private:
   // views::MaskedTargeterDelegate:
   views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
   bool GetHitTestMask(gfx::Path* mask) const override;
 
+  // In material refresh mode, calculates opacity based on the current state of
+  // the hover animation on the parent tab.
+  SkAlpha GetOpacity();
+
   void GenerateImages(bool is_touch,
                       SkColor normal_icon_color,
                       SkColor hover_pressed_icon_color,
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index 783491f..31a2a0e 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h"
 
+#include "base/command_line.h"
 #include "base/i18n/timezone.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
@@ -223,6 +224,12 @@
   // ToS then prefs::kArcEnabled is automatically reset in ArcSessionManager.
   arc::SetArcPlayStoreEnabledForProfile(profile, true);
 
+  // Hide the Skip button if the ToS screen can not be skipped during OOBE.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableArcOobeOptinNoSkip)) {
+    CallJS("hideSkipButton");
+  }
+
   action_taken_ = false;
 
   ShowScreen(kScreenId);
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index 5c9f0f0..412e677e 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -109,6 +109,7 @@
   keyboard_delegate_ = std::make_unique<TestKeyboardDelegate>();
 
   UiInitialState ui_initial_state;
+  ui_initial_state.create_tabs_view = true;
   ui_ = std::make_unique<Ui>(this, nullptr, keyboard_delegate_.get(),
                              text_input_delegate_.get(), nullptr,
                              ui_initial_state);
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h
index 0c6cdfc..7aef648 100644
--- a/chrome/browser/vr/ui.h
+++ b/chrome/browser/vr/ui.h
@@ -51,7 +51,6 @@
   bool supports_selection = true;
   bool needs_keyboard_update = false;
   bool is_standalone_vr_device = false;
-  // TODO(crbug.com/838937): Enable tabs.
   bool create_tabs_view = false;
 };
 
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index fde31eb0..9c2c9cbd 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -59,10 +59,12 @@
     if (is_chromeos) {
       sources += [
         "$root_gen_dir/ash/components/resources/ash_components_resources_${percent}_percent.pak",
+        "$root_gen_dir/ash/resources/ash_resources_${percent}_percent.pak",
         "$root_gen_dir/ui/chromeos/resources/ui_chromeos_resources_${percent}_percent.pak",
       ]
       deps += [
         "//ash/components/resources",
+        "//ash/resources",
         "//ui/chromeos/resources",
       ]
     }
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index da90176..231520b 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -567,13 +567,11 @@
       // Otherwise, it'll be treated as a sub-key-system of normal
       // kExternalClearKeyKeySystem. See MultipleCdmTypes test in
       // ECKEncryptedMediaTest.
-      // TODO(crbug.com/835009): Update when ECK supports more encryption
-      // schemes.
       cdms->push_back(content::CdmInfo(
           media::kClearKeyCdmDisplayName, media::kClearKeyCdmDifferentGuid,
           base::Version("0.1.0.0"), clear_key_cdm_path,
           media::kClearKeyCdmFileSystemId, {}, supports_persistent_license,
-          {media::EncryptionMode::kCenc},
+          {media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs},
           kExternalClearKeyDifferentGuidTestKeySystem, false));
 
       // Supported codecs are hard-coded in ExternalClearKeyProperties.
@@ -581,7 +579,8 @@
           media::kClearKeyCdmDisplayName, media::kClearKeyCdmGuid,
           base::Version("0.1.0.0"), clear_key_cdm_path,
           media::kClearKeyCdmFileSystemId, {}, supports_persistent_license,
-          {media::EncryptionMode::kCenc}, kExternalClearKeyKeySystem, true));
+          {media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs},
+          kExternalClearKeyKeySystem, true));
     }
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2e60b5e..b4e894ad 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2908,6 +2908,7 @@
       "../browser/page_load_metrics/observers/session_restore_page_load_metrics_observer_unittest.cc",
       "../browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc",
       "../browser/resource_coordinator/discard_metrics_lifecycle_unit_observer_unittest.cc",
+      "../browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc",
       "../browser/resource_coordinator/lifecycle_unit_base_unittest.cc",
       "../browser/resource_coordinator/lifecycle_unit_unittest.cc",
       "../browser/resource_coordinator/local_site_characteristics_data_impl_unittest.cc",
@@ -2916,6 +2917,7 @@
       "../browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc",
       "../browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h",
       "../browser/resource_coordinator/local_site_characteristics_data_writer_unittest.cc",
+      "../browser/resource_coordinator/local_site_characteristics_non_recording_data_store_unittest.cc",
       "../browser/resource_coordinator/tab_activity_watcher_unittest.cc",
       "../browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc",
       "../browser/resource_coordinator/tab_lifecycle_unit_unittest.cc",
@@ -3250,6 +3252,7 @@
     deps += [
       "//ash:test_support_with_content",
       "//ash/public/cpp/resources:ash_public_unscaled_resources",
+      "//ash/resources",
       "//ash/strings",
     ]
   }
@@ -4882,6 +4885,7 @@
         "//ash:interactive_ui_test_support",
         "//ash/app_list/presenter:test_support",
         "//ash/public/interfaces:test_interfaces",
+        "//ash/resources",
         "//chrome/browser/media/router:test_support",
         "//chromeos",
         "//mojo/edk",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 7bb94ac..23a5547 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -26,7 +26,6 @@
     "javatests/src/org/chromium/chrome/test/util/BookmarkTestUtil.java",
     "javatests/src/org/chromium/chrome/test/util/browser/compositor/layouts/DisableChromeAnimations.java",
     "javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java",
-    "javatests/src/org/chromium/chrome/test/util/browser/ChromeHome.java",
     "javatests/src/org/chromium/chrome/test/util/browser/ChromeModernDesign.java",
     "javatests/src/org/chromium/chrome/test/util/browser/Features.java",
     "javatests/src/org/chromium/chrome/test/util/browser/LocationSettingsTestUtil.java",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/ChromeHome.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/ChromeHome.java
deleted file mode 100644
index 98c3d8a5..0000000
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/ChromeHome.java
+++ /dev/null
@@ -1,101 +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.
-
-package org.chromium.chrome.test.util.browser;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-
-import android.os.StrictMode;
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import org.chromium.base.test.util.AnnotationRule;
-import org.chromium.base.test.util.Restriction;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
-import org.chromium.chrome.browser.util.FeatureUtilities;
-import org.chromium.ui.test.util.UiRestriction;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Utility annotation and rule to enable or disable ChromeHome. Handles setting and resetting the
- * feature flag and the preference.
- *
- * @see ChromeHome.Processor
- * @see FeatureUtilities#isChromeHomeEnabled()
- */
-public interface ChromeHome {
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target({ElementType.METHOD, ElementType.TYPE})
-    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-    @Features.EnableFeatures(ChromeFeatureList.CHROME_HOME)
-    @interface Enable {}
-
-    @Retention(RetentionPolicy.RUNTIME)
-    @Target({ElementType.METHOD, ElementType.TYPE})
-    @Features.DisableFeatures(ChromeFeatureList.CHROME_HOME)
-    @interface Disable {}
-
-    /**
-     * Rule to handle setting and resetting the cached feature state for ChromeHome. Can be used by
-     * explicitly calling methods ({@link #setPrefs(boolean)} and {@link #clearTestState()}) or by
-     * using the {@link ChromeHome.Enable} and {@link ChromeHome.Disable} annotations on tests.
-     */
-    class Processor extends AnnotationRule {
-        private Boolean mOldState;
-
-        public Processor() {
-            super(ChromeHome.Enable.class, ChromeHome.Disable.class);
-        }
-
-        @Override
-        public Statement apply(Statement base, Description description) {
-            Statement wrappedStatement = super.apply(base, description);
-            return getAnnotations().isEmpty() ? base : wrappedStatement;
-        }
-
-        @Override
-        protected void before() throws Throwable {
-            boolean featureEnabled = getClosestAnnotation() instanceof ChromeHome.Enable;
-            setPrefs(featureEnabled);
-        }
-
-        @Override
-        protected void after() {
-            clearTestState();
-        }
-
-        public void setPrefs(boolean enabled) {
-            // Chrome relies on a shared preference to determine if the ChromeHome feature is
-            // enabled during start up, so we need to manually set the preference to enable
-            // ChromeHome before starting Chrome.
-            ChromePreferenceManager prefsManager = ChromePreferenceManager.getInstance();
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-            try {
-                mOldState = prefsManager.isChromeHomeEnabled();
-            } finally {
-                StrictMode.setThreadPolicy(oldPolicy);
-            }
-
-            FeatureUtilities.resetChromeHomeEnabledForTests();
-
-            // The native library should not be enabled yet, so we set the preference here and
-            // cache it by checking for the feature. Ideally we instead would call
-            // FeatureUtilities.cacheChromeHomeEnabled()
-            prefsManager.setChromeHomeEnabled(enabled);
-            assertEquals(enabled, FeatureUtilities.isChromeHomeEnabled());
-        }
-
-        public void clearTestState() {
-            assertNotNull(mOldState);
-            ChromePreferenceManager.getInstance().setChromeHomeEnabled(mOldState);
-        }
-    }
-}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/Features.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/Features.java
index a67843a..d4a81a3c 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/Features.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/Features.java
@@ -34,7 +34,7 @@
  *    &#64;Rule
  *    public Features.Processor processor = new Features.JUnitProcessor();
  *
- *    &#64;Features.EnableFeatures(ChromeFeatureList.CHROME_HOME)
+ *    &#64;Features.EnableFeatures(ChromeFeatureList.CHROME_MODERN_DESIGN)
  *    public void testFoo() { ... }
  * }
  * </pre>
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
index 9860507..73a9c9f8 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
@@ -207,6 +207,15 @@
 }
 
 Status ChromeDesktopImpl::QuitImpl() {
+  Status status = devtools_websocket_client_->ConnectIfNecessary();
+  if (status.IsOk()) {
+    status = devtools_websocket_client_->SendCommandAndIgnoreResponse(
+        "Browser.close", base::DictionaryValue());
+    if (status.IsOk() && process_.WaitForExitWithTimeout(
+                             base::TimeDelta::FromSeconds(10), nullptr))
+      return status;
+  }
+
   // If the Chrome session uses a custom user data directory, try sending a
   // SIGTERM signal before SIGKILL, so that Chrome has a chance to write
   // everything back out to the user data directory and exit cleanly. If we're
diff --git a/chromecast/base/init_command_line_shlib.h b/chromecast/base/init_command_line_shlib.h
index 0ef1354c..dcf295d 100644
--- a/chromecast/base/init_command_line_shlib.h
+++ b/chromecast/base/init_command_line_shlib.h
@@ -23,8 +23,8 @@
 // THREAD SAFTEY: Accessing the CommandLine instance for this process is
 // technically not threadsafe when using the component build. However, the
 // instance is initialized on the main thread before any other threads are
-// started (see content/app/content_main_runner.cc), so accessing this instance
-// on those threads for read-operations is safe in practice.
+// started (see content/app/content_main_runner_impl.cc), so accessing this
+// instance on those threads for read-operations is safe in practice.
 void InitCommandLineShlib(const std::vector<std::string>& argv);
 
 }  // namespace chromecast
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index b4f5914..a8cf538 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -303,6 +303,9 @@
 // Enables starting the ARC instance upon session start.
 const char kEnableArc[] = "enable-arc";
 
+// Enables "hide Skip button" for ARC setup in the OOBE flow.
+const char kEnableArcOobeOptinNoSkip[] = "enable-arc-oobe-optin-no-skip";
+
 // Enables using a random url for captive portal detection.
 const char kEnableCaptivePortalRandomUrl[] = "enable-captive-portal-random-url";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index c09dff7..a750afa 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -89,6 +89,7 @@
 CHROMEOS_EXPORT extern const char kDisableWakeOnWifi[];
 CHROMEOS_EXPORT extern const char kDisableZipArchiverUnpacker[];
 CHROMEOS_EXPORT extern const char kEnableArc[];
+CHROMEOS_EXPORT extern const char kEnableArcOobeOptinNoSkip[];
 CHROMEOS_EXPORT extern const char kEnableCaptivePortalRandomUrl[];
 CHROMEOS_EXPORT extern const char kEnableCastReceiver[];
 CHROMEOS_EXPORT extern const char kEnableChromeVoxArcSupport[];
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc
index 6ae80c8..0f9a487 100644
--- a/chromeos/dbus/smb_provider_client.cc
+++ b/chromeos/dbus/smb_provider_client.cc
@@ -236,7 +236,7 @@
     options.set_mount_id(mount_id);
     options.set_source_path(source_path.value());
     options.set_target_path(target_path.value());
-    CallDefaultMethod(smbprovider::kCopyEntryMethod, options, &callback);
+    CallCopyEntryMethod(options, std::move(callback));
   }
 
   void GetDeleteList(int32_t mount_id,
@@ -328,6 +328,21 @@
                        std::move(*callback)));
   }
 
+  // Calls the CopyEntry D-Bus method with no timeout, passing the |protobuf| as
+  // an argument. Uses the default callback handler to process |callback|.
+  void CallCopyEntryMethod(const google::protobuf::MessageLite& protobuf,
+                           StatusCallback callback) {
+    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
+                                 smbprovider::kCopyEntryMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendProtoAsArrayOfBytes(protobuf);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
+        base::BindOnce(&SmbProviderClientImpl::HandleDefaultCallback,
+                       GetWeakPtr(), method_call.GetMember(),
+                       std::move(callback)));
+  }
+
   // Handles D-Bus callback for mount.
   void HandleMountCallback(MountCallback callback, dbus::Response* response) {
     if (!response) {
diff --git a/chromeos/system/statistics_provider.cc b/chromeos/system/statistics_provider.cc
index 69c96bb..3abad2d 100644
--- a/chromeos/system/statistics_provider.cc
+++ b/chromeos/system/statistics_provider.cc
@@ -106,8 +106,8 @@
 // devices. It's known *not* to be present on caroline.
 // TODO(tnagel): Remove "Product_S/N" after all devices that have it are AUE.
 const char* const kMachineInfoSerialNumberKeys[] = {
-    "Product_S/N",     // Samsung legacy
-    kSerialNumberKey,  // VPD v2+ devices
+    "Product_S/N",    // Samsung legacy
+    "serial_number",  // VPD v2+ devices (Samsung: caroline and later)
 };
 
 // Gets ListValue from given |dictionary| by given |key| and (unless |result| is
@@ -198,7 +198,7 @@
 const char kOffersGroupCodeKey[] = "gbind_attribute";
 const char kRlzBrandCodeKey[] = "rlz_brand_code";
 const char kRegionKey[] = "region";
-const char kSerialNumberKey[] = "serial_number";
+const char kSerialNumberKeyForTest[] = "serial_number";
 const char kInitialLocaleKey[] = "initial_locale";
 const char kInitialTimezoneKey[] = "initial_timezone";
 const char kKeyboardLayoutKey[] = "keyboard_layout";
diff --git a/chromeos/system/statistics_provider.h b/chromeos/system/statistics_provider.h
index d466392..3a21c12 100644
--- a/chromeos/system/statistics_provider.h
+++ b/chromeos/system/statistics_provider.h
@@ -84,9 +84,10 @@
 CHROMEOS_EXPORT extern const char kInitialTimezoneKey[];
 CHROMEOS_EXPORT extern const char kKeyboardLayoutKey[];
 
-// Serial number key (only VPD v2+ devices). Use GetEnterpriseMachineID() to
-// cover legacy devices.
-CHROMEOS_EXPORT extern const char kSerialNumberKey[];
+// Serial number key (VPD v2+ devices, Samsung: caroline and later) for use in
+// tests. Outside of tests GetEnterpriseMachineID() is the backward-compatible
+// way to obtain the serial number.
+CHROMEOS_EXPORT extern const char kSerialNumberKeyForTest[];
 
 // This interface provides access to Chrome OS statistics.
 class CHROMEOS_EXPORT StatisticsProvider {
@@ -116,12 +117,11 @@
   virtual bool GetMachineFlag(const std::string& name, bool* result) = 0;
 
   // Returns the machine serial number after examining a set of well-known
-  // keys. In case no serial is found (possibly due to the device having already
-  // been enrolled or claimed by a local user), an empty string is returned.
-  // Caveat: For lumpy, the last letter is ommitted from the serial number for
-  // historical reasons.
-  // TODO(tnagel): Drop "Enterprise" from the method name and remove lumpy
-  // special casing after lumpy EOL.
+  // keys. In case no serial is found an empty string is returned.
+  // Caveat: On older Samsung devices, the last letter is omitted from the
+  // serial number for historical reasons. This is fine.
+  // TODO(tnagel): Drop "Enterprise" from the method name and remove Samsung
+  // special casing after kevin EOL.
   std::string GetEnterpriseMachineID();
 
   // Cancels any pending file operations.
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index 242857d..40c8b8e 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -55,6 +55,8 @@
 const base::Feature kAutofillRationalizeFieldTypePredictions{
     "AutofillRationalizeFieldTypePredictions",
     base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kAutofillSuggestInvalidProfileData{
+    "AutofillSuggestInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kAutofillSuppressDisusedAddresses{
     "AutofillSuppressDisusedAddresses", base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kAutofillSuppressDisusedCreditCards{
@@ -68,6 +70,8 @@
 const base::Feature kAutofillUpstreamUpdatePromptExplanation{
     "AutofillUpstreamUpdatePromptExplanation",
     base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillVoteUsingInvalidProfileData{
+    "AutofillVoteUsingInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit";
 const char kAutofillCreditCardPopupBackgroundColorKey[] = "background_color";
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index 887fbb8..e33d3afd1 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -39,12 +39,14 @@
 extern const base::Feature kAutofillExpandedPopupViews;
 extern const base::Feature kAutofillPreferServerNamePredictions;
 extern const base::Feature kAutofillRationalizeFieldTypePredictions;
+extern const base::Feature kAutofillSuggestInvalidProfileData;
 extern const base::Feature kAutofillSuppressDisusedAddresses;
 extern const base::Feature kAutofillSuppressDisusedCreditCards;
 extern const base::Feature kAutofillUpstreamAllowAllEmailDomains;
 extern const base::Feature kAutofillUpstreamSendDetectedValues;
 extern const base::Feature kAutofillUpstreamSendPanFirstSix;
 extern const base::Feature kAutofillUpstreamUpdatePromptExplanation;
+extern const base::Feature kAutofillVoteUsingInvalidProfileData;
 extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
 extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[];
 extern const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[];
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 6f9df9f..bef60c5 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -604,7 +604,10 @@
 
   friend class AutofillManagerTest;
   friend class FormStructureBrowserTest;
+  friend class GetMatchingTypesTest;
   friend class SaveCardBubbleViewsBrowserTestBase;
+  FRIEND_TEST_ALL_PREFIXES(ProfileMatchingTypesTest,
+                           DeterminePossibleFieldTypesForUpload);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
                            DeterminePossibleFieldTypesForUpload);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 8954769..13ad202 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
@@ -4445,28 +4446,163 @@
   EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
 }
 
+struct ProfileMatchingTypesTestCase {
+  const char* input_value;     // The value to input in the field.
+  ServerFieldType field_type;  // The expected field type to be determined.
+};
+
+class ProfileMatchingTypesTest
+    : public AutofillManagerTest,
+      public ::testing::WithParamInterface<
+          std::tuple<ProfileMatchingTypesTestCase,
+                     int,        // AutofillProfile::ValidityState
+                     bool>> {};  // Enable AutofillVoteUsingInvalidProfileValues
+
+const ProfileMatchingTypesTestCase kProfileMatchingTypesTestCases[] = {
+    // Profile fields matches.
+    {"Elvis", NAME_FIRST},
+    {"Aaron", NAME_MIDDLE},
+    {"A", NAME_MIDDLE_INITIAL},
+    {"Presley", NAME_LAST},
+    {"Elvis Aaron Presley", NAME_FULL},
+    {"theking@gmail.com", EMAIL_ADDRESS},
+    {"RCA", COMPANY_NAME},
+    {"3734 Elvis Presley Blvd.", ADDRESS_HOME_LINE1},
+    {"Apt. 10", ADDRESS_HOME_LINE2},
+    {"Memphis", ADDRESS_HOME_CITY},
+    {"Tennessee", ADDRESS_HOME_STATE},
+    {"38116", ADDRESS_HOME_ZIP},
+    {"USA", ADDRESS_HOME_COUNTRY},
+    {"United States", ADDRESS_HOME_COUNTRY},
+    {"12345678901", PHONE_HOME_WHOLE_NUMBER},
+    {"+1 (234) 567-8901", PHONE_HOME_WHOLE_NUMBER},
+    {"(234)567-8901", PHONE_HOME_CITY_AND_NUMBER},
+    {"2345678901", PHONE_HOME_CITY_AND_NUMBER},
+    {"1", PHONE_HOME_COUNTRY_CODE},
+    {"234", PHONE_HOME_CITY_CODE},
+    {"5678901", PHONE_HOME_NUMBER},
+    {"567", PHONE_HOME_NUMBER},
+    {"8901", PHONE_HOME_NUMBER},
+
+    // Test a European profile.
+    {"Paris", ADDRESS_HOME_CITY},
+    {"Île de France", ADDRESS_HOME_STATE},    // Exact match
+    {"Ile de France", ADDRESS_HOME_STATE},    // Missing accent.
+    {"-Ile-de-France-", ADDRESS_HOME_STATE},  // Extra punctuation.
+    {"île dÉ FrÃÑÇË", ADDRESS_HOME_STATE},    // Other accents & case mismatch.
+    {"75008", ADDRESS_HOME_ZIP},
+    {"FR", ADDRESS_HOME_COUNTRY},
+    {"France", ADDRESS_HOME_COUNTRY},
+    {"33249197070", PHONE_HOME_WHOLE_NUMBER},
+    {"+33 2 49 19 70 70", PHONE_HOME_WHOLE_NUMBER},
+    {"2 49 19 70 70", PHONE_HOME_CITY_AND_NUMBER},
+    {"249197070", PHONE_HOME_CITY_AND_NUMBER},
+    {"33", PHONE_HOME_COUNTRY_CODE},
+    {"2", PHONE_HOME_CITY_CODE},
+
+    // Credit card fields matches.
+    {"John Doe", CREDIT_CARD_NAME_FULL},
+    {"John", CREDIT_CARD_NAME_FIRST},
+    {"Doe", CREDIT_CARD_NAME_LAST},
+    {"4234-5678-9012-3456", CREDIT_CARD_NUMBER},
+    {"04", CREDIT_CARD_EXP_MONTH},
+    {"April", CREDIT_CARD_EXP_MONTH},
+    {"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR},
+    {"99", CREDIT_CARD_EXP_2_DIGIT_YEAR},
+    {"04/2999", CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+
+    // Make sure whitespace and invalid characters are handled properly.
+    {"", EMPTY_TYPE},
+    {" ", EMPTY_TYPE},
+    {"***", UNKNOWN_TYPE},
+    {" Elvis", NAME_FIRST},
+    {"Elvis ", NAME_FIRST},
+
+    // Make sure fields that differ by case match.
+    {"elvis ", NAME_FIRST},
+    {"UnItEd StAtEs", ADDRESS_HOME_COUNTRY},
+
+    // Make sure fields that differ by punctuation match.
+    {"3734 Elvis Presley Blvd", ADDRESS_HOME_LINE1},
+    {"3734, Elvis    Presley Blvd.", ADDRESS_HOME_LINE1},
+
+    // Make sure that a state's full name and abbreviation match.
+    {"TN", ADDRESS_HOME_STATE},     // Saved as "Tennessee" in profile.
+    {"Texas", ADDRESS_HOME_STATE},  // Saved as "TX" in profile.
+
+    // Special phone number case. A profile with no country code should only
+    // match PHONE_HOME_CITY_AND_NUMBER.
+    {"5142821292", PHONE_HOME_CITY_AND_NUMBER},
+
+    // Make sure unsupported variants do not match.
+    {"Elvis Aaron", UNKNOWN_TYPE},
+    {"Mr. Presley", UNKNOWN_TYPE},
+    {"3734 Elvis Presley", UNKNOWN_TYPE},
+    {"38116-1023", UNKNOWN_TYPE},
+    {"5", UNKNOWN_TYPE},
+    {"56", UNKNOWN_TYPE},
+    {"901", UNKNOWN_TYPE},
+};
+
 // Tests that DeterminePossibleFieldTypesForUpload makes accurate matches.
-TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload) {
+TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
+  // Unpack the test paramters
+  const auto& test_case = std::get<0>(GetParam());
+  const auto& validity_state =
+      static_cast<AutofillProfile::ValidityState>(std::get<1>(GetParam()));
+  const auto& vote_using_invalid_profile_data = std::get<2>(GetParam());
+
+  SCOPED_TRACE(base::StringPrintf(
+      "Test: input_value='%s', field_type=%s, validity_state=%d, "
+      "ignore_invalid_profile_data=%d",
+      test_case.input_value,
+      AutofillType(test_case.field_type).ToString().c_str(), validity_state,
+      vote_using_invalid_profile_data));
+
+  ASSERT_LE(AutofillProfile::UNVALIDATED, validity_state);
+  ASSERT_LE(validity_state, AutofillProfile::UNSUPPORTED);
+
+  // Enable/Disable ignoring invalid profile data for the scope of this test.
+  base::test::ScopedFeatureList sfl;
+  if (vote_using_invalid_profile_data) {
+    sfl.InitAndEnableFeature(kAutofillVoteUsingInvalidProfileData);
+  } else {
+    sfl.InitAndDisableFeature(kAutofillVoteUsingInvalidProfileData);
+  }
+
   // Set up the test profiles.
   std::vector<AutofillProfile> profiles;
-  AutofillProfile profile;
-  test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
+  profiles.resize(3);
+  test::SetProfileInfo(&profiles[0], "Elvis", "Aaron", "Presley",
                        "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
                        "Apt. 10", "Memphis", "Tennessee", "38116", "US",
                        "+1 (234) 567-8901");
-  profile.set_guid("00000000-0000-0000-0000-000000000001");
-  profiles.push_back(profile);
-  test::SetProfileInfo(&profile, "Charles", "", "Holley", "buddy@gmail.com",
+  profiles[0].set_guid("00000000-0000-0000-0000-000000000001");
+
+  test::SetProfileInfo(&profiles[1], "Charles", "", "Holley", "buddy@gmail.com",
                        "Decca", "123 Apple St.", "unit 6", "Lubbock", "TX",
                        "79401", "US", "5142821292");
-  profile.set_guid("00000000-0000-0000-0000-000000000002");
-  profiles.push_back(profile);
-  test::SetProfileInfo(&profile, "Charles", "", "Baudelaire",
+  profiles[1].set_guid("00000000-0000-0000-0000-000000000002");
+
+  test::SetProfileInfo(&profiles[2], "Charles", "", "Baudelaire",
                        "lesfleursdumal@gmail.com", "", "108 Rue Saint-Lazare",
                        "Apt. 10", "Paris", "Île de France", "75008", "FR",
                        "+33 2 49 19 70 70");
-  profile.set_guid("00000000-0000-0000-0000-000000000001");
-  profiles.push_back(profile);
+  profiles[2].set_guid("00000000-0000-0000-0000-000000000001");
+
+  // Set the validity state for the matching field type.
+  if (test_case.field_type != EMPTY_TYPE &&
+      test_case.field_type != UNKNOWN_TYPE) {
+    auto field_type = test_case.field_type;
+    auto field_type_group = AutofillType(field_type).group();
+    if (field_type_group != CREDIT_CARD) {
+      if (field_type_group == PHONE_HOME || field_type_group == PHONE_BILLING)
+        field_type = PHONE_HOME_WHOLE_NUMBER;
+      for (auto& profile : profiles) {
+        profile.SetValidityState(test_case.field_type, validity_state);
+      }
+    }
+  }
 
   // Set up the test credit cards.
   std::vector<CreditCard> credit_cards;
@@ -4476,122 +4612,56 @@
   credit_card.set_guid("00000000-0000-0000-0000-000000000003");
   credit_cards.push_back(credit_card);
 
-  typedef struct {
-    std::string input_value;     // The value to input in the field.
-    ServerFieldType field_type;  // The expected field type to be determined.
-  } TestCase;
+  FormData form;
+  form.name = ASCIIToUTF16("MyForm");
+  form.origin = GURL("http://myform.com/form.html");
+  form.action = GURL("http://myform.com/submit.html");
 
-  TestCase test_cases[] = {
-      // Profile fields matches.
-      {"Elvis", NAME_FIRST},
-      {"Aaron", NAME_MIDDLE},
-      {"A", NAME_MIDDLE_INITIAL},
-      {"Presley", NAME_LAST},
-      {"Elvis Aaron Presley", NAME_FULL},
-      {"theking@gmail.com", EMAIL_ADDRESS},
-      {"RCA", COMPANY_NAME},
-      {"3734 Elvis Presley Blvd.", ADDRESS_HOME_LINE1},
-      {"Apt. 10", ADDRESS_HOME_LINE2},
-      {"Memphis", ADDRESS_HOME_CITY},
-      {"Tennessee", ADDRESS_HOME_STATE},
-      {"38116", ADDRESS_HOME_ZIP},
-      {"USA", ADDRESS_HOME_COUNTRY},
-      {"United States", ADDRESS_HOME_COUNTRY},
-      {"12345678901", PHONE_HOME_WHOLE_NUMBER},
-      {"+1 (234) 567-8901", PHONE_HOME_WHOLE_NUMBER},
-      {"(234)567-8901", PHONE_HOME_CITY_AND_NUMBER},
-      {"2345678901", PHONE_HOME_CITY_AND_NUMBER},
-      {"1", PHONE_HOME_COUNTRY_CODE},
-      {"234", PHONE_HOME_CITY_CODE},
-      {"5678901", PHONE_HOME_NUMBER},
-      {"567", PHONE_HOME_NUMBER},
-      {"8901", PHONE_HOME_NUMBER},
+  FormFieldData field;
+  test::CreateTestFormField("", "1", "", "text", &field);
+  field.value = UTF8ToUTF16(test_case.input_value);
+  form.fields.push_back(field);
 
-      // Test a European profile.
-      {"Paris", ADDRESS_HOME_CITY},
-      {"Île de France", ADDRESS_HOME_STATE},    // Exact match
-      {"Ile de France", ADDRESS_HOME_STATE},    // Missing accent.
-      {"-Ile-de-France-", ADDRESS_HOME_STATE},  // Extra punctuation.
-      {"île dÉ FrÃÑÇË", ADDRESS_HOME_STATE},  // Other accents & case mismatch.
-      {"75008", ADDRESS_HOME_ZIP},
-      {"FR", ADDRESS_HOME_COUNTRY},
-      {"France", ADDRESS_HOME_COUNTRY},
-      {"33249197070", PHONE_HOME_WHOLE_NUMBER},
-      {"+33 2 49 19 70 70", PHONE_HOME_WHOLE_NUMBER},
-      {"2 49 19 70 70", PHONE_HOME_CITY_AND_NUMBER},
-      {"249197070", PHONE_HOME_CITY_AND_NUMBER},
-      {"33", PHONE_HOME_COUNTRY_CODE},
-      {"2", PHONE_HOME_CITY_CODE},
+  FormStructure form_structure(form);
 
-      // Credit card fields matches.
-      {"John Doe", CREDIT_CARD_NAME_FULL},
-      {"John", CREDIT_CARD_NAME_FIRST},
-      {"Doe", CREDIT_CARD_NAME_LAST},
-      {"4234-5678-9012-3456", CREDIT_CARD_NUMBER},
-      {"04", CREDIT_CARD_EXP_MONTH},
-      {"April", CREDIT_CARD_EXP_MONTH},
-      {"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR},
-      {"99", CREDIT_CARD_EXP_2_DIGIT_YEAR},
-      {"04/2999", CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+  base::HistogramTester histogram_tester;
+  AutofillManager::DeterminePossibleFieldTypesForUpload(
+      profiles, credit_cards, "en-us", &form_structure);
 
-      // Make sure whitespace and invalid characters are handled properly.
-      {"", EMPTY_TYPE},
-      {" ", EMPTY_TYPE},
-      {"***", UNKNOWN_TYPE},
-      {" Elvis", NAME_FIRST},
-      {"Elvis ", NAME_FIRST},
+  ASSERT_EQ(1U, form_structure.field_count());
+  ServerFieldTypeSet possible_types = form_structure.field(0)->possible_types();
+  EXPECT_EQ(1U, possible_types.size());
 
-      // Make sure fields that differ by case match.
-      {"elvis ", NAME_FIRST},
-      {"UnItEd StAtEs", ADDRESS_HOME_COUNTRY},
-
-      // Make sure fields that differ by punctuation match.
-      {"3734 Elvis Presley Blvd", ADDRESS_HOME_LINE1},
-      {"3734, Elvis    Presley Blvd.", ADDRESS_HOME_LINE1},
-
-      // Make sure that a state's full name and abbreviation match.
-      {"TN", ADDRESS_HOME_STATE},     // Saved as "Tennessee" in profile.
-      {"Texas", ADDRESS_HOME_STATE},  // Saved as "TX" in profile.
-
-      // Special phone number case. A profile with no country code should only
-      // match PHONE_HOME_CITY_AND_NUMBER.
-      {"5142821292", PHONE_HOME_CITY_AND_NUMBER},
-
-      // Make sure unsupported variants do not match.
-      {"Elvis Aaron", UNKNOWN_TYPE},
-      {"Mr. Presley", UNKNOWN_TYPE},
-      {"3734 Elvis Presley", UNKNOWN_TYPE},
-      {"38116-1023", UNKNOWN_TYPE},
-      {"5", UNKNOWN_TYPE},
-      {"56", UNKNOWN_TYPE},
-      {"901", UNKNOWN_TYPE}};
-
-  for (TestCase test_case : test_cases) {
-    FormData form;
-    form.name = ASCIIToUTF16("MyForm");
-    form.origin = GURL("http://myform.com/form.html");
-    form.action = GURL("http://myform.com/submit.html");
-
-    FormFieldData field;
-    test::CreateTestFormField("", "1", "", "text", &field);
-    field.value = UTF8ToUTF16(test_case.input_value);
-    form.fields.push_back(field);
-
-    FormStructure form_structure(form);
-
-    AutofillManager::DeterminePossibleFieldTypesForUpload(
-        profiles, credit_cards, "en-us", &form_structure);
-
-    ASSERT_EQ(1U, form_structure.field_count());
-    ServerFieldTypeSet possible_types =
-        form_structure.field(0)->possible_types();
-    EXPECT_EQ(1U, possible_types.size());
-
-    EXPECT_NE(possible_types.end(), possible_types.find(test_case.field_type))
-        << "Failed to determine type for: \"" << test_case.input_value << "\"";
+  if (test_case.field_type != EMPTY_TYPE &&
+      AutofillProfile::IsValidationSupportedForType(test_case.field_type) &&
+      validity_state == AutofillProfile::INVALID) {
+    // There are two addresses in the US, every other type/value pair is unique.
+    int expected_count =
+        (test_case.field_type == ADDRESS_HOME_COUNTRY &&
+         base::StartsWith(test_case.input_value, "U",
+                          base::CompareCase::INSENSITIVE_ASCII))
+            ? 2
+            : 1;
+    histogram_tester.ExpectBucketCount(
+        "Autofill.InvalidProfileData.UsedForMetrics",
+        vote_using_invalid_profile_data, expected_count);
+    EXPECT_EQ(*possible_types.begin(), vote_using_invalid_profile_data
+                                           ? test_case.field_type
+                                           : UNKNOWN_TYPE);
+  } else {
+    EXPECT_EQ(*possible_types.begin(), test_case.field_type);
   }
 }
 
+INSTANTIATE_TEST_CASE_P(
+    AutofillManagerTest,
+    ProfileMatchingTypesTest,
+    testing::Combine(
+        testing::ValuesIn(kProfileMatchingTypesTestCases),
+        testing::Range(static_cast<int>(AutofillProfile::UNVALIDATED),
+                       static_cast<int>(AutofillProfile::UNSUPPORTED) + 1),
+        testing::Bool()));
+
 // Tests that DeterminePossibleFieldTypesForUpload is called when a form is
 // submitted.
 TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload_IsTriggered) {
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index cff037a..44b5d69a 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -25,6 +25,7 @@
 #include "components/autofill/core/browser/address.h"
 #include "components/autofill/core/browser/address_i18n.h"
 #include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/autofill_profile_comparator.h"
@@ -192,10 +193,10 @@
 }
 
 // Constants for the validity bitfield.
-static const size_t kValidityBitsPerType = 2;
+const size_t kValidityBitsPerType = 2;
 // The order is important to ensure a consistent bitfield value. New values
 // should be added at the end NOT at the start or middle.
-static const ServerFieldType kSupportedTypesForValidation[] = {
+const ServerFieldType kSupportedTypesForValidation[] = {
     ADDRESS_HOME_COUNTRY,
     ADDRESS_HOME_STATE,
     ADDRESS_HOME_ZIP,
@@ -204,13 +205,22 @@
     EMAIL_ADDRESS,
     PHONE_HOME_WHOLE_NUMBER};
 
-static const size_t kNumSupportedTypesForValidation =
+const size_t kNumSupportedTypesForValidation =
     sizeof(kSupportedTypesForValidation) /
     sizeof(kSupportedTypesForValidation[0]);
 
 static_assert(kNumSupportedTypesForValidation * kValidityBitsPerType <= 64,
               "Not enough bits to encode profile validity information!");
 
+// Some types are specializations of other types. Normalize these back to the
+// main stored type for used to mark field validity .
+ServerFieldType NormalizeTypeForValidityCheck(ServerFieldType type) {
+  auto field_type_group = AutofillType(type).group();
+  if (field_type_group == PHONE_HOME || field_type_group == PHONE_BILLING)
+    return PHONE_HOME_WHOLE_NUMBER;
+  return type;
+}
+
 }  // namespace
 
 AutofillProfile::AutofillProfile(const std::string& guid,
@@ -278,9 +288,22 @@
     const base::string16& text,
     const std::string& app_locale,
     ServerFieldTypeSet* matching_types) const {
+  ServerFieldTypeSet matching_types_in_this_profile;
   FormGroupList info = FormGroups();
   for (const auto* form_group : info) {
-    form_group->GetMatchingTypes(text, app_locale, matching_types);
+    form_group->GetMatchingTypes(text, app_locale,
+                                 &matching_types_in_this_profile);
+  }
+  for (auto type : matching_types_in_this_profile) {
+    if (GetValidityState(type) == INVALID) {
+      bool vote_using_invalid_data =
+          base::FeatureList::IsEnabled(kAutofillVoteUsingInvalidProfileData);
+      UMA_HISTOGRAM_BOOLEAN("Autofill.InvalidProfileData.UsedForMetrics",
+                            vote_using_invalid_data);
+      if (!vote_using_invalid_data)
+        continue;
+    }
+    matching_types->insert(type);
   }
 }
 
@@ -707,6 +730,7 @@
 
 AutofillProfile::ValidityState AutofillProfile::GetValidityState(
     ServerFieldType type) const {
+  type = NormalizeTypeForValidityCheck(type);
   // Return UNSUPPORTED for types that autofill does not validate.
   if (!IsValidationSupportedForType(type))
     return UNSUPPORTED;
@@ -724,7 +748,8 @@
   validity_states_[type] = validity;
 }
 
-bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) const {
+// static
+bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) {
   for (auto supported_type : kSupportedTypesForValidation) {
     if (type == supported_type)
       return true;
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index f5a06442..c097d14 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -203,7 +203,7 @@
   void SetValidityState(ServerFieldType type, ValidityState validity);
 
   // Returns whether autofill does the validation of the specified |type|.
-  bool IsValidationSupportedForType(ServerFieldType type) const;
+  static bool IsValidationSupportedForType(ServerFieldType type);
 
   // Returns the bitfield value representing the validity state of this profile.
   int GetValidityBitfieldValue() const;
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index 22934f9..2689031 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -1127,7 +1127,7 @@
             profile.GetValidityState(ADDRESS_HOME_LINE1));
   EXPECT_EQ(AutofillProfile::UNSUPPORTED,
             profile.GetValidityState(ADDRESS_HOME_LINE2));
-  EXPECT_EQ(AutofillProfile::UNSUPPORTED,
+  EXPECT_EQ(AutofillProfile::UNVALIDATED,
             profile.GetValidityState(PHONE_HOME_CITY_AND_NUMBER));
 }
 
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index becc128..66d8074 100644
--- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -85,7 +85,7 @@
 bool AutofillSaveCardInfoBarDelegateMobile::IsGooglePayBrandingEnabled() const {
   return upload_ &&
          base::FeatureList::IsEnabled(
-             features::kAutofillUpstreamUseGooglePayOnAndroidBranding);
+             features::kAutofillUpstreamUseGooglePayBrandingOnMobile);
 }
 
 base::string16 AutofillSaveCardInfoBarDelegateMobile::GetTitleText() const {
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index 803170b..413948a 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -731,13 +731,13 @@
   EXPECT_EQ(base::string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE));
 }
 
-struct MatchingTypesCase {
-  MatchingTypesCase(const char* value,
-                    const char* card_exp_month,
-                    const char* card_exp_year,
-                    CreditCard::RecordType record_type,
-                    ServerFieldTypeSet expected_matched_types,
-                    const char* locale = "US")
+struct CreditCardMatchingTypesCase {
+  CreditCardMatchingTypesCase(const char* value,
+                              const char* card_exp_month,
+                              const char* card_exp_year,
+                              CreditCard::RecordType record_type,
+                              ServerFieldTypeSet expected_matched_types,
+                              const char* locale = "US")
       : value(value),
         card_exp_month(card_exp_month),
         card_exp_year(card_exp_year),
@@ -746,7 +746,7 @@
         locale(locale) {}
 
   // The value entered by the user.
-  const std::string value;
+  const char* value;
   // Some values for an already saved card. Card number will be fixed to
   // 4012888888881881.
   const char* card_exp_month;
@@ -755,13 +755,13 @@
   // The types that are expected to match.
   const ServerFieldTypeSet expected_matched_types;
 
-  const std::string locale;
+  const char* locale = "US";
 };
 
-class GetMatchingTypesTest : public testing::TestWithParam<MatchingTypesCase> {
-};
+class CreditCardMatchingTypesTest
+    : public testing::TestWithParam<CreditCardMatchingTypesCase> {};
 
-TEST_P(GetMatchingTypesTest, Cases) {
+TEST_P(CreditCardMatchingTypesTest, Cases) {
   auto test_case = GetParam();
   CreditCard card(base::GenerateGUID(), "https://www.example.com/");
   card.set_record_type(test_case.record_type);
@@ -777,129 +777,60 @@
   EXPECT_EQ(test_case.expected_matched_types, matching_types);
 }
 
-INSTANTIATE_TEST_CASE_P(
-    CreditCardTest,
-    GetMatchingTypesTest,
-    testing::Values(
-        // If comparing against a masked card, last four digits are checked.
-        MatchingTypesCase{"1881",
-                          "01",
-                          "2020",
-                          MASKED_SERVER_CARD,
-                          {CREDIT_CARD_NUMBER}},
-        MatchingTypesCase{"4012888888881881",
-                          "01",
-                          "2020",
-                          MASKED_SERVER_CARD,
-                          {CREDIT_CARD_NUMBER}},
-        MatchingTypesCase{"4111111111111111", "01", "2020",
-                          CreditCard::MASKED_SERVER_CARD, ServerFieldTypeSet()},
-        // Same value will not match a local card or full server card since we
-        // have the full number for those. However the full number will.
-        MatchingTypesCase{"1881", "01", "2020", LOCAL_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"1881", "01", "2020", FULL_SERVER_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"4012888888881881",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_NUMBER}},
-        MatchingTypesCase{"4012888888881881",
-                          "01",
-                          "2020",
-                          FULL_SERVER_CARD,
-                          {CREDIT_CARD_NUMBER}},
+const CreditCardMatchingTypesCase kCreditCardMatchingTypesTestCases[] = {
+    // If comparing against a masked card, last four digits are checked.
+    {"1881", "01", "2020", MASKED_SERVER_CARD, {CREDIT_CARD_NUMBER}},
+    {"4012888888881881",
+     "01",
+     "2020",
+     MASKED_SERVER_CARD,
+     {CREDIT_CARD_NUMBER}},
+    {"4111111111111111", "01", "2020", CreditCard::MASKED_SERVER_CARD,
+     ServerFieldTypeSet()},
+    // Same value will not match a local card or full server card since we
+    // have the full number for those. However the full number will.
+    {"1881", "01", "2020", LOCAL_CARD, ServerFieldTypeSet()},
+    {"1881", "01", "2020", FULL_SERVER_CARD, ServerFieldTypeSet()},
+    {"4012888888881881", "01", "2020", LOCAL_CARD, {CREDIT_CARD_NUMBER}},
+    {"4012888888881881", "01", "2020", FULL_SERVER_CARD, {CREDIT_CARD_NUMBER}},
 
-        // Wrong last four digits.
-        MatchingTypesCase{"1111", "01", "2020", MASKED_SERVER_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"1111", "01", "2020", LOCAL_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"1111", "01", "2020", FULL_SERVER_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"4111111111111111", "01", "2020", MASKED_SERVER_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"4111111111111111", "01", "2020", LOCAL_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"4111111111111111", "01", "2020", FULL_SERVER_CARD,
-                          ServerFieldTypeSet()},
+    // Wrong last four digits.
+    {"1111", "01", "2020", MASKED_SERVER_CARD, ServerFieldTypeSet()},
+    {"1111", "01", "2020", LOCAL_CARD, ServerFieldTypeSet()},
+    {"1111", "01", "2020", FULL_SERVER_CARD, ServerFieldTypeSet()},
+    {"4111111111111111", "01", "2020", MASKED_SERVER_CARD,
+     ServerFieldTypeSet()},
+    {"4111111111111111", "01", "2020", LOCAL_CARD, ServerFieldTypeSet()},
+    {"4111111111111111", "01", "2020", FULL_SERVER_CARD, ServerFieldTypeSet()},
 
-        // Matching the expiration month.
-        MatchingTypesCase{"01",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH}},
-        MatchingTypesCase{"1",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH}},
-        MatchingTypesCase{"jan",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH},
-                          "US"},
-        // Locale-specific interpretations.
-        MatchingTypesCase{"janv",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH},
-                          "FR"},
-        MatchingTypesCase{"janv.",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH},
-                          "FR"},
-        MatchingTypesCase{"janvier",
-                          "01",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH},
-                          "FR"},
-        MatchingTypesCase{"février",
-                          "02",
-                          "2020",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_MONTH},
-                          "FR"},
-        MatchingTypesCase{"mars", "01", "2020", LOCAL_CARD,
-                          ServerFieldTypeSet(), "FR"},
+    // Matching the expiration month.
+    {"01", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}},
+    {"1", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}},
+    {"jan", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "US"},
+    // Locale-specific interpretations.
+    {"janv", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+    {"janv.", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+    {"janvier", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+    {"février", "02", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+    {"mars", "01", "2020", LOCAL_CARD, ServerFieldTypeSet(), "FR"},
 
-        // Matching the expiration year.
-        MatchingTypesCase{"2019",
-                          "01",
-                          "2019",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_4_DIGIT_YEAR}},
-        MatchingTypesCase{"19",
-                          "01",
-                          "2019",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_2_DIGIT_YEAR}},
-        MatchingTypesCase{"01/2019",
-                          "01",
-                          "2019",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
-        MatchingTypesCase{"01-2019",
-                          "01",
-                          "2019",
-                          LOCAL_CARD,
-                          {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
-        MatchingTypesCase{"01/2020", "01", "2019", LOCAL_CARD,
-                          ServerFieldTypeSet()},
-        MatchingTypesCase{"20", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
-        MatchingTypesCase{"2021", "01", "2019", LOCAL_CARD,
-                          ServerFieldTypeSet()}));
+    // Matching the expiration year.
+    {"2019", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_4_DIGIT_YEAR}},
+    {"19", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_2_DIGIT_YEAR}},
+    {"01/2019", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+    {"01-2019", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+    {"01/2020", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+    {"20", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+    {"2021", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+};
+
+INSTANTIATE_TEST_CASE_P(CreditCardTest,
+                        CreditCardMatchingTypesTest,
+                        testing::ValuesIn(kCreditCardMatchingTypesTestCases));
 
 struct GetCardNetworkTestCase {
-  std::string card_number;
-  std::string issuer_network;
+  const char* card_number;
+  const char* issuer_network;
   bool is_valid;
 };
 
@@ -975,7 +906,7 @@
         GetCardNetworkTestCase{"6362970000457013", kEloCard, true},
 
         // Empty string
-        GetCardNetworkTestCase{std::string(), kGenericCard, false},
+        GetCardNetworkTestCase{"", kGenericCard, false},
 
         // Non-numeric
         GetCardNetworkTestCase{"garbage", kGenericCard, false},
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 43fdcc0..6fed3ff6 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -16,6 +16,7 @@
 #include "base/feature_list.h"
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/timezone.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -975,6 +976,32 @@
       num_profiles_supressed);
 }
 
+// static
+void PersonalDataManager::MaybeRemoveInvalidSuggestions(
+    const AutofillType& type,
+    std::vector<AutofillProfile*>* profiles) {
+  const bool suggest_invalid =
+      base::FeatureList::IsEnabled(kAutofillSuggestInvalidProfileData);
+
+  for (size_t i = 0; i < profiles->size(); ++i) {
+    bool is_invalid = (*profiles)[i]->GetValidityState(
+                          type.GetStorableType()) == AutofillProfile::INVALID;
+    if (is_invalid) {
+      UMA_HISTOGRAM_BOOLEAN("Autofill.InvalidProfileData.UsedForSuggestion",
+                            suggest_invalid);
+      if (!suggest_invalid)
+        (*profiles)[i] = nullptr;
+    }
+  }
+
+  if (!suggest_invalid) {
+    profiles->erase(
+        std::stable_partition(profiles->begin(), profiles->end(),
+                              [](AutofillProfile* p) { return p != nullptr; }),
+        profiles->end());
+  }
+}
+
 std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
     const AutofillType& type,
     const base::string16& field_contents,
@@ -990,13 +1017,15 @@
   // Get the profiles to suggest, which are already sorted.
   std::vector<AutofillProfile*> profiles = GetProfilesToSuggest();
 
-  // If enabled, suppress disused address profiles when triggered from an empty
-  // field.
-  if (field_contents_canon.empty() &&
-      base::FeatureList::IsEnabled(kAutofillSuppressDisusedAddresses)) {
-    const base::Time min_last_used =
-        AutofillClock::Now() - kDisusedProfileTimeDelta;
-    RemoveProfilesNotUsedSinceTimestamp(min_last_used, &profiles);
+  // When suggesting with no prefix to match, consider suppressing disused
+  // address suggestions as well as those based on invalid profile data.
+  if (field_contents_canon.empty()) {
+    if (base::FeatureList::IsEnabled(kAutofillSuppressDisusedAddresses)) {
+      const base::Time min_last_used =
+          AutofillClock::Now() - kDisusedProfileTimeDelta;
+      RemoveProfilesNotUsedSinceTimestamp(min_last_used, &profiles);
+    }
+    MaybeRemoveInvalidSuggestions(type, &profiles);
   }
 
   std::vector<Suggestion> suggestions;
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 6eb722b0..5fc2d9f 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -215,6 +215,12 @@
       base::Time min_last_used,
       std::vector<AutofillProfile*>* profiles);
 
+  // Remove profiles that whose |type| field is flagged as invalid, if Chrome
+  // is configured to not make suggestions based on invalid data.
+  static void MaybeRemoveInvalidSuggestions(
+      const AutofillType& type,
+      std::vector<AutofillProfile*>* profiles);
+
   // Loads profiles that can suggest data for |type|. |field_contents| is the
   // part the user has already typed. |field_is_autofilled| is true if the field
   // has already been autofilled. |other_field_types| represents the rest of
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 584fa7d..a34e66d3 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -1925,6 +1925,54 @@
   }
 }
 
+// Tests that suggestions based on invalid data are handled correctly.
+TEST_F(PersonalDataManagerTest, GetProfileSuggestions_InvalidData) {
+  // Set up 2 different profiles.
+  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "9876543210");
+  profile1.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID);
+  profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
+  personal_data_->AddProfile(profile1);
+
+  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "456 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "1234567890");
+  personal_data_->AddProfile(profile2);
+
+  ResetPersonalDataManager(USER_MODE_NORMAL);
+  {
+    base::HistogramTester histogram_tester;
+    base::test::ScopedFeatureList scoped_features;
+    scoped_features.InitAndDisableFeature(kAutofillSuggestInvalidProfileData);
+    std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
+        AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false,
+        std::vector<ServerFieldType>());
+    ASSERT_EQ(1U, suggestions.size());
+    EXPECT_EQ(base::ASCIIToUTF16("1234567890"), suggestions[0].value);
+    histogram_tester.ExpectUniqueSample(
+        "Autofill.InvalidProfileData.UsedForSuggestion", false, 1);
+  }
+
+  {
+    base::HistogramTester histogram_tester;
+    base::test::ScopedFeatureList scoped_features;
+    scoped_features.InitAndEnableFeature(kAutofillSuggestInvalidProfileData);
+    std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
+        AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false,
+        std::vector<ServerFieldType>());
+    ASSERT_EQ(2U, suggestions.size());
+    EXPECT_EQ(base::ASCIIToUTF16("1234567890"), suggestions[0].value);
+    EXPECT_EQ(base::ASCIIToUTF16("9876543210"), suggestions[1].value);
+    histogram_tester.ExpectUniqueSample(
+        "Autofill.InvalidProfileData.UsedForSuggestion", true, 1);
+  }
+}
+
 TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesMaskedServerCard) {
   // Add a masked server card.
   std::vector<CreditCard> server_cards;
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index df69471..476678b1 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -56,8 +56,8 @@
     "AutofillSkipComparingInferredLabels", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Controls whether the credit card upload bubble shows the Google Pay logo and
-// a shorter "Save card?" header message on Android.
-const base::Feature kAutofillUpstreamUseGooglePayOnAndroidBranding{
+// a shorter "Save card?" header message on mobile.
+const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile{
     "AutofillUpstreamUseGooglePayOnAndroidBranding",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 3d32bcf..e354955 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -20,7 +20,7 @@
 extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout;
 extern const base::Feature kAutofillShowTypePredictions;
 extern const base::Feature kAutofillSkipComparingInferredLabels;
-extern const base::Feature kAutofillUpstreamUseGooglePayOnAndroidBranding;
+extern const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile;
 
 }  // namespace features
 }  // namespace autofill
diff --git a/components/certificate_transparency/ct_policy_manager_unittest.cc b/components/certificate_transparency/ct_policy_manager_unittest.cc
index 9d3b3b1..0cd328e 100644
--- a/components/certificate_transparency/ct_policy_manager_unittest.cc
+++ b/components/certificate_transparency/ct_policy_manager_unittest.cc
@@ -130,9 +130,10 @@
   // Wildcards are ignored (both * and https://*).
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
             delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
-  // File URL hosts are ignored.
-  EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("withahost", cert_.get(), hashes_));
+  // TODO(rsleevi): https://crbug.com/841407 - Ensure that file URLs have their
+  // hosts ignored for policy.
+  // EXPECT_EQ(CTRequirementLevel::DEFAULT,
+  //          delegate->IsCTRequiredForHost("withahost", cert_.get(), hashes_));
 
   // While the partially parsed hosts should take effect.
   EXPECT_EQ(
diff --git a/components/components_locale_settings.grd b/components/components_locale_settings.grd
index 1db75317..a9ffdfb3 100644
--- a/components/components_locale_settings.grd
+++ b/components/components_locale_settings.grd
@@ -250,7 +250,7 @@
     <messages fallback_to_english="true">
 
       <!-- The default value for HTTP Accept-Language header. -->
-      <message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true" formatter_data="android_java">
+      <message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true">
         en-US,en
       </message>
 
diff --git a/components/omnibox/browser/autocomplete_input.cc b/components/omnibox/browser/autocomplete_input.cc
index 3130623..42e80de 100644
--- a/components/omnibox/browser/autocomplete_input.cc
+++ b/components/omnibox/browser/autocomplete_input.cc
@@ -175,21 +175,6 @@
 }
 
 // static
-void AutocompleteInput::ParseFilePath(const base::string16& text,
-                                      size_t offset,
-                                      url::Parsed* parts) {
-  parts->path.begin = offset;
-  size_t hash_offset = text.find('#', offset);
-  if (hash_offset != text.npos) {
-    parts->path.len = hash_offset - offset;
-    parts->ref.begin = hash_offset + 1;
-    parts->ref.len = text.size() - parts->ref.begin;
-  } else {
-    parts->path.len = text.size() - offset;
-  }
-}
-
-// static
 metrics::OmniboxInputType AutocompleteInput::Parse(
     const base::string16& text,
     const std::string& desired_tld,
@@ -228,8 +213,6 @@
     // A user might or might not type a scheme when entering a file URL.  In
     // either case, |parsed_scheme_utf8| will tell us that this is a file URL,
     // but |parts->scheme| might be empty, e.g. if the user typed "C:\foo".
-    ParseFilePath(text, parts->scheme.is_nonempty() ? parts->scheme.end() : 0,
-                  parts);
     return metrics::OmniboxInputType::URL;
   }
 
diff --git a/components/omnibox/browser/autocomplete_input.h b/components/omnibox/browser/autocomplete_input.h
index c456b61..f1220c3 100644
--- a/components/omnibox/browser/autocomplete_input.h
+++ b/components/omnibox/browser/autocomplete_input.h
@@ -61,11 +61,6 @@
   // Converts |type| to a string representation.  Used in logging.
   static std::string TypeToString(metrics::OmniboxInputType type);
 
-  // Parses the |path| and |ref| fields of |parts| from a file path input.
-  static void ParseFilePath(const base::string16& text,
-                            size_t offset,
-                            url::Parsed* parts);
-
   // Parses |text| (including an optional |desired_tld|) and returns the type of
   // input this will be interpreted as.  |scheme_classifier| is used to check
   // the scheme in |text| is known and registered in the current environment.
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index ebdd632b..bf9098b0 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -85,7 +85,13 @@
 
 // Feature used to display the title of the current URL match.
 const base::Feature kDisplayTitleForCurrentUrl{
-    "OmniboxDisplayTitleForCurrentUrl", base::FEATURE_DISABLED_BY_DEFAULT};
+  "OmniboxDisplayTitleForCurrentUrl",
+#if defined(OS_ANDROID)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 // Feature used for the max autocomplete matches UI experiment.
 const base::Feature kUIExperimentMaxAutocompleteMatches{
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc
index bddd608..3c3e697 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.cc
+++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -57,6 +57,8 @@
 const char kValueRequestAppInstallReport[] = "app_install_report";
 const char kValueRequestTokenEnrollment[] = "register_browser";
 const char kValueRequestChromeDesktopReport[] = "chrome_desktop_report";
+const char kValueRequestInitialEnrollmentStateRetrieval[] =
+    "device_initial_enrollment_state";
 
 const char kChromeDevicePolicyType[] = "google/chromeos/device";
 #if defined(OS_CHROMEOS)
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.h b/components/policy/core/common/cloud/cloud_policy_constants.h
index f2a82709..2d1cc55 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.h
+++ b/components/policy/core/common/cloud/cloud_policy_constants.h
@@ -49,6 +49,7 @@
 POLICY_EXPORT extern const char kValueRequestAppInstallReport[];
 POLICY_EXPORT extern const char kValueRequestTokenEnrollment[];
 POLICY_EXPORT extern const char kValueRequestChromeDesktopReport[];
+POLICY_EXPORT extern const char kValueRequestInitialEnrollmentStateRetrieval[];
 
 // Policy type strings for the policy_type field in PolicyFetchRequest.
 POLICY_EXPORT extern const char kChromeDevicePolicyType[];
diff --git a/components/policy/core/common/cloud/device_management_service.cc b/components/policy/core/common/cloud/device_management_service.cc
index b81384b1..93eb38a 100644
--- a/components/policy/core/common/cloud/device_management_service.cc
+++ b/components/policy/core/common/cloud/device_management_service.cc
@@ -166,6 +166,8 @@
       return dm_protocol::kValueRequestTokenEnrollment;
     case DeviceManagementRequestJob::TYPE_CHROME_DESKTOP_REPORT:
       return dm_protocol::kValueRequestChromeDesktopReport;
+    case DeviceManagementRequestJob::TYPE_INITIAL_ENROLLMENT_STATE_RETRIEVAL:
+      return dm_protocol::kValueRequestInitialEnrollmentStateRetrieval;
   }
   NOTREACHED() << "Invalid job type " << type;
   return "";
diff --git a/components/policy/core/common/cloud/device_management_service.h b/components/policy/core/common/cloud/device_management_service.h
index ec6f24b7..28816b39 100644
--- a/components/policy/core/common/cloud/device_management_service.h
+++ b/components/policy/core/common/cloud/device_management_service.h
@@ -66,6 +66,7 @@
     TYPE_UPLOAD_APP_INSTALL_REPORT = 17,
     TYPE_TOKEN_ENROLLMENT = 18,
     TYPE_CHROME_DESKTOP_REPORT = 19,
+    TYPE_INITIAL_ENROLLMENT_STATE_RETRIEVAL = 20,
   };
 
   typedef base::Callback<
diff --git a/components/sync/protocol/extension_specifics.proto b/components/sync/protocol/extension_specifics.proto
index 394b0b04..e560995 100644
--- a/components/sync/protocol/extension_specifics.proto
+++ b/components/sync/protocol/extension_specifics.proto
@@ -42,11 +42,8 @@
   // Whether this extension was installed by the custodian of a supervised user.
   optional bool installed_by_custodian = 8;
 
-  // Whether this extension has explicit user consent access to all urls.
-  // This is a tri-state boolean, so, unlike most fields here, it really *is*
-  // optional and may be absent. We need this for the time being because we need
-  // to know if a user has not set an explicit preference.
-  optional bool all_urls_enabled = 9;
+  // DEPRECATED. See https://crbug.com/839681.
+  optional bool all_urls_enabled = 9 [deprecated = true];
 
   // Bitmask of the set of reasons why the extension is disabled (see
   // extensions::disable_reason::DisableReason). Only relevant when enabled ==
diff --git a/components/url_formatter/url_fixer.cc b/components/url_formatter/url_fixer.cc
index 36511cf5..26be3c86 100644
--- a/components/url_formatter/url_fixer.cc
+++ b/components/url_formatter/url_fixer.cc
@@ -404,20 +404,20 @@
   if (trimmed.empty())
     return std::string();  // Nothing to segment.
 
+  std::string scheme;
 #if defined(OS_WIN)
   int trimmed_length = static_cast<int>(trimmed.length());
   if (url::DoesBeginWindowsDriveSpec(trimmed.data(), 0, trimmed_length) ||
       url::DoesBeginUNCPath(trimmed.data(), 0, trimmed_length, true))
-    return url::kFileScheme;
+    scheme = url::kFileScheme;
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
   if (base::FilePath::IsSeparator(trimmed.data()[0]) ||
       trimmed.data()[0] == '~')
-    return url::kFileScheme;
+    scheme = url::kFileScheme;
 #endif
 
   // Otherwise, we need to look at things carefully.
-  std::string scheme;
-  if (!GetValidScheme(*text, &parts->scheme, &scheme)) {
+  if (scheme.empty() && !GetValidScheme(*text, &parts->scheme, &scheme)) {
     // Try again if there is a ';' in the text. If changing it to a ':' results
     // in a standard scheme, "about", "chrome" or "file" scheme being found,
     // continue processing with the modified text.
@@ -444,24 +444,26 @@
 
   // Proceed with about and chrome schemes, but not file or nonstandard schemes.
   if ((scheme != url::kAboutScheme) && (scheme != kChromeUIScheme) &&
-      ((scheme == url::kFileScheme) ||
-       !url::IsStandard(
-           scheme.c_str(),
-           url::Component(0, static_cast<int>(scheme.length()))))) {
+      !url::IsStandard(scheme.c_str(),
+                       url::Component(0, static_cast<int>(scheme.length())))) {
+    return scheme;
+  }
+
+  int text_length = static_cast<int>(text->length());
+  if (scheme == url::kFileScheme) {
+    url::ParseFileURL(text->data(), text_length, parts);
     return scheme;
   }
 
   if (scheme == url::kFileSystemScheme) {
     // Have the GURL parser do the heavy lifting for us.
-    url::ParseFileSystemURL(text->data(), static_cast<int>(text->length()),
-                            parts);
+    url::ParseFileSystemURL(text->data(), text_length, parts);
     return scheme;
   }
 
   if (parts->scheme.is_valid()) {
     // Have the GURL parser do the heavy lifting for us.
-    url::ParseStandardURL(text->data(), static_cast<int>(text->length()),
-                          parts);
+    url::ParseStandardURL(text->data(), text_length, parts);
     return scheme;
   }
 
diff --git a/components/url_formatter/url_fixer_unittest.cc b/components/url_formatter/url_fixer_unittest.cc
index e946f23..5415d19 100644
--- a/components/url_formatter/url_fixer_unittest.cc
+++ b/components/url_formatter/url_fixer_unittest.cc
@@ -192,6 +192,52 @@
     url::Component(), // query
     url::Component(), // ref
   },
+  {
+      "file://host/path/file#ref", "file", url::Component(0, 4),  // scheme
+      url::Component(),                                           // username
+      url::Component(),                                           // password
+      url::Component(7, 4),                                       // host
+      url::Component(),                                           // port
+      url::Component(11, 10),                                     // path
+      url::Component(),                                           // query
+      url::Component(22, 3),                                      // ref
+  },
+  {
+      "file:///notahost/path/file#ref", "file",
+      url::Component(0, 4),   // scheme
+      url::Component(),       // username
+      url::Component(),       // password
+      url::Component(),       // host
+      url::Component(),       // port
+      url::Component(7, 19),  // path
+      url::Component(),       // query
+      url::Component(27, 3),  // ref
+  },
+#if defined(OS_WIN)
+  {
+      "c:/notahost/path/file#ref", "file",
+      url::Component(),       // scheme
+      url::Component(),       // username
+      url::Component(),       // password
+      url::Component(),       // host
+      url::Component(),       // port
+      url::Component(0, 21),  // path
+      url::Component(),       // query
+      url::Component(22, 3),  // ref
+  },
+#elif defined(OS_POSIX)
+  {
+      "~/notahost/path/file#ref", "file",
+      url::Component(),       // scheme
+      url::Component(),       // username
+      url::Component(),       // password
+      url::Component(),       // host
+      url::Component(),       // port
+      url::Component(0, 20),  // path
+      url::Component(),       // query
+      url::Component(21, 3),  // ref
+  },
+#endif
 };
 
 typedef testing::Test URLFixerTest;
diff --git a/components/viz/common/frame_sinks/copy_output_request.cc b/components/viz/common/frame_sinks/copy_output_request.cc
index 43fa33b..56164fa 100644
--- a/components/viz/common/frame_sinks/copy_output_request.cc
+++ b/components/viz/common/frame_sinks/copy_output_request.cc
@@ -64,14 +64,6 @@
          result_task_runner_->RunsTasksInCurrentSequence();
 }
 
-void CopyOutputRequest::SetMailbox(const gpu::Mailbox& mailbox,
-                                   const gpu::SyncToken& sync_token) {
-  DCHECK_EQ(result_format_, ResultFormat::RGBA_TEXTURE);
-  DCHECK(!mailbox.IsZero());
-  mailbox_ = mailbox;
-  sync_token_ = sync_token;
-}
-
 // static
 std::unique_ptr<CopyOutputRequest> CopyOutputRequest::CreateStubForTesting() {
   return std::make_unique<CopyOutputRequest>(
diff --git a/components/viz/common/frame_sinks/copy_output_request.h b/components/viz/common/frame_sinks/copy_output_request.h
index 4c57ab26..d38cfde 100644
--- a/components/viz/common/frame_sinks/copy_output_request.h
+++ b/components/viz/common/frame_sinks/copy_output_request.h
@@ -107,17 +107,6 @@
   bool has_result_selection() const { return result_selection_.has_value(); }
   const gfx::Rect& result_selection() const { return *result_selection_; }
 
-  // Legacy support for providing textures up-front, to copy results into.
-  // TODO(miu): Remove these methods after tab capture is moved to VIZ.
-  // http://crbug.com/754872
-  // The texture bound to the mailbox is expected to have a GL_TEXTURE_2D
-  // target.
-  void SetMailbox(const gpu::Mailbox& mailbox,
-                  const gpu::SyncToken& sync_token);
-  bool has_mailbox() const { return mailbox_.has_value(); }
-  const gpu::Mailbox& mailbox() const { return *mailbox_; }
-  const gpu::SyncToken& sync_token() const { return *sync_token_; }
-
   // Sends the result from executing this request. Called by the internal
   // implementation, usually a DirectRenderer.
   void SendResult(std::unique_ptr<CopyOutputResult> result);
@@ -144,8 +133,6 @@
   base::Optional<base::UnguessableToken> source_;
   base::Optional<gfx::Rect> area_;
   base::Optional<gfx::Rect> result_selection_;
-  base::Optional<gpu::Mailbox> mailbox_;
-  base::Optional<gpu::SyncToken> sync_token_;
 
   DISALLOW_COPY_AND_ASSIGN(CopyOutputRequest);
 };
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 42b6787..202e608 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -39,6 +39,13 @@
 
 namespace viz {
 
+struct Display::PendingPresentedCallbacks {
+  PendingPresentedCallbacks(uint64_t swap_id, PresentedCallbacks callbacks)
+      : swap_id(swap_id), callbacks(std::move(callbacks)) {}
+  uint64_t swap_id = 0;
+  PresentedCallbacks callbacks;
+};
+
 Display::Display(
     SharedBitmapManager* bitmap_manager,
     const RendererSettings& settings,
@@ -61,14 +68,11 @@
 }
 
 Display::~Display() {
-  for (auto& callbacks : previous_presented_callbacks_) {
-    for (auto& callback : callbacks)
+  for (auto& pending_callbacks : pending_presented_callbacks_) {
+    for (auto& callback : pending_callbacks.callbacks)
       std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0);
   }
 
-  for (auto& callback : active_presented_callbacks_)
-    std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0);
-
   for (auto& callback : presented_callbacks_)
     std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0);
 
@@ -444,16 +448,12 @@
 }
 
 void Display::DidReceiveSwapBuffersAck(uint64_t swap_id) {
-  // TODO(penghuang): Remove it when we can get accurate presentation time from
-  // GPU for every SwapBuffers. https://crbug.com/776877
-  if (!active_presented_callbacks_.empty() ||
-      !previous_presented_callbacks_.empty()) {
-    DLOG(WARNING) << "VSync for last SwapBuffers is not received!";
-    previous_presented_callbacks_.push_back(
-        std::move(active_presented_callbacks_));
+  DCHECK(pending_presented_callbacks_.empty() ||
+         pending_presented_callbacks_.back().swap_id < swap_id);
+  if (!presented_callbacks_.empty()) {
+    pending_presented_callbacks_.emplace_back(swap_id,
+                                              std::move(presented_callbacks_));
   }
-  active_presented_callbacks_ = std::move(presented_callbacks_);
-
   if (scheduler_)
     scheduler_->DidReceiveSwapBuffersAck();
   if (renderer_)
@@ -475,23 +475,17 @@
 void Display::DidReceivePresentationFeedback(
     uint64_t swap_id,
     const gfx::PresentationFeedback& feedback) {
-  // TODO(penghuang): Remove it when we can get accurate presentation time from
-  // GPU for every SwapBuffers. https://crbug.com/776877
-  base::TimeTicks previous_timebase =
-      feedback.timestamp -
-      feedback.interval * previous_presented_callbacks_.size();
-  for (auto& callbacks : previous_presented_callbacks_) {
-    for (auto& callback : callbacks)
-      std::move(callback).Run(previous_timebase, feedback.interval, 0);
-    previous_timebase += feedback.interval;
+  if (pending_presented_callbacks_.empty())
+    return;
+  DCHECK_LE(swap_id, pending_presented_callbacks_.front().swap_id);
+  auto& pending_callbacks = pending_presented_callbacks_.front();
+  if (swap_id == pending_callbacks.swap_id) {
+    for (auto& callback : pending_callbacks.callbacks) {
+      std::move(callback).Run(feedback.timestamp, feedback.interval,
+                              feedback.flags);
+    }
+    pending_presented_callbacks_.pop_front();
   }
-  previous_presented_callbacks_.clear();
-
-  for (auto& callback : active_presented_callbacks_) {
-    std::move(callback).Run(feedback.timestamp, feedback.interval,
-                            feedback.flags);
-  }
-  active_presented_callbacks_.clear();
 }
 
 void Display::DidFinishLatencyInfo(
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index 4b7d805..4b4f705 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/single_thread_task_runner.h"
@@ -170,10 +171,8 @@
 
   using PresentedCallbacks = std::vector<Surface::PresentedCallback>;
   PresentedCallbacks presented_callbacks_;
-  PresentedCallbacks active_presented_callbacks_;
-  // TODO(penghuang): Remove it when we can get accurate presentation time from
-  // GPU for every SwapBuffers. https://crbug.com/776877
-  std::vector<PresentedCallbacks> previous_presented_callbacks_;
+  struct PendingPresentedCallbacks;
+  base::circular_deque<PendingPresentedCallbacks> pending_presented_callbacks_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Display);
diff --git a/components/viz/service/display/gl_renderer_copier.cc b/components/viz/service/display/gl_renderer_copier.cc
index ee56fad4..fb4b00ef 100644
--- a/components/viz/service/display/gl_renderer_copier.cc
+++ b/components/viz/service/display/gl_renderer_copier.cc
@@ -215,10 +215,10 @@
     // return it as the result texture. The request must not include scaling nor
     // a texture mailbox to use for delivering results. The texture format must
     // also be GL_RGBA, as described by CopyOutputResult::Format::RGBA_TEXTURE.
-    const int purpose = (!request.is_scaled() && flipped_source &&
-                         !request.has_mailbox() && internal_format == GL_RGBA)
-                            ? CacheEntry::kResultTexture
-                            : CacheEntry::kFramebufferCopyTexture;
+    const int purpose =
+        (!request.is_scaled() && flipped_source && internal_format == GL_RGBA)
+            ? CacheEntry::kResultTexture
+            : CacheEntry::kFramebufferCopyTexture;
     TakeCachedObjectsOrCreate(SourceOf(request), purpose, 1, &source_texture);
     gl->BindTexture(GL_TEXTURE_2D, source_texture);
     gl->CopyTexImage2D(GL_TEXTURE_2D, 0, internal_format, sampling_rect.x(),
@@ -230,21 +230,9 @@
     sampling_rect.set_origin(gfx::Point());
   }
 
-  // Determine the result texture: If the copy request provided a valid one, use
-  // it instead of one owned by GLRendererCopier.
   GLuint result_texture = 0;
-  if (request.has_mailbox()) {
-    if (!request.mailbox().IsZero()) {
-      if (request.sync_token().HasData())
-        gl->WaitSyncTokenCHROMIUM(request.sync_token().GetConstData());
-      result_texture =
-          gl->CreateAndConsumeTextureCHROMIUM(request.mailbox().name);
-    }
-  }
-  if (result_texture == 0) {
-    TakeCachedObjectsOrCreate(SourceOf(request), CacheEntry::kResultTexture, 1,
-                              &result_texture);
-  }
+  TakeCachedObjectsOrCreate(SourceOf(request), CacheEntry::kResultTexture, 1,
+                            &result_texture);
   gl->BindTexture(GL_TEXTURE_2D, result_texture);
   gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, result_rect.width(),
                  result_rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
@@ -492,34 +480,18 @@
   // within its own GL context will be using the texture at a point in time
   // after the texture has been rendered (via GLRendererCopier's GL context).
   gpu::Mailbox mailbox;
-  if (request->has_mailbox()) {
-    mailbox = request->mailbox();
-  } else {
-    gl->GenMailboxCHROMIUM(mailbox.name);
-    gl->ProduceTextureDirectCHROMIUM(result_texture, mailbox.name);
-  }
+  gl->GenMailboxCHROMIUM(mailbox.name);
+  gl->ProduceTextureDirectCHROMIUM(result_texture, mailbox.name);
   gpu::SyncToken sync_token;
   gl->GenSyncTokenCHROMIUM(sync_token.GetData());
 
-  // Create a |release_callback| appropriate to the situation: If the
-  // |result_texture| was provided in the mailbox of the copy request,
-  // create a no-op release callback because the requestor owns the texture.
-  // Otherwise, create a callback that deletes what was created in this GL
-  // context.
-  std::unique_ptr<SingleReleaseCallback> release_callback;
-  if (request->has_mailbox()) {
-    gl->DeleteTextures(1, &result_texture);
-    // TODO(crbug/754872): This non-null release callback wart is going away
-    // soon, as copy requestors won't need pool/manage textures anymore.
-    release_callback = SingleReleaseCallback::Create(base::DoNothing());
-  } else {
-    // Note: There's no need to try to pool/re-use the result texture from here,
-    // since only clients that are trying to re-invent video capture would see
-    // any significant performance benefit. Instead, such clients should use the
-    // video capture services provided by VIZ.
-    release_callback =
-        texture_deleter_->GetReleaseCallback(context_provider_, result_texture);
-  }
+  // Create a callback that deletes what was created in this GL context.
+  // Note: There's no need to try to pool/re-use the result texture from here,
+  // since only clients that are trying to re-invent video capture would see any
+  // significant performance benefit. Instead, such clients should use the video
+  // capture services provided by VIZ.
+  auto release_callback =
+      texture_deleter_->GetReleaseCallback(context_provider_, result_texture);
 
   request->SendResult(std::make_unique<CopyOutputTextureResult>(
       result_rect, mailbox, sync_token, color_space,
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc
index 42c74f06..f6b0624 100644
--- a/components/viz/test/test_context_provider.cc
+++ b/components/viz/test/test_context_provider.cc
@@ -9,6 +9,7 @@
 
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -204,8 +205,7 @@
   context_gl_->set_test_context(context3d_.get());
   context3d_->set_test_support(support_.get());
   raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>(
-      context_gl_.get(), support_.get(), nullptr,
-      context3d_->test_capabilities());
+      context_gl_.get(), nullptr, context3d_->test_capabilities());
   // Just pass nullptr to the ContextCacheController for its task runner.
   // Idle handling is tested directly in ContextCacheController's
   // unittests, and isn't needed here.
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index 8d8f282..70d55be 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -71,7 +71,7 @@
     content_app_deps += [ "//content/ppapi_plugin:ppapi_plugin_sources" ]
   }
 
-  # Compile content_main_runner.cc in a separate target to exempt from GN
+  # Compile content_main_runner_impl.cc in a separate target to exempt from GN
   # header checking without exempting any other source file. This file includes
   # headers of all process types and varies significantly per platform in
   # between browser and child. Otherwise it would require many "nogncheck"
@@ -84,7 +84,7 @@
     check_includes = false
 
     sources = [
-      "content_main_runner.cc",
+      "content_main_runner_impl.cc",
     ]
 
     configs += extra_configs
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner_impl.cc
similarity index 96%
rename from content/app/content_main_runner.cc
rename to content/app/content_main_runner_impl.cc
index 2296874..4863bbf 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -191,8 +191,8 @@
   // browser process.
   field_trial_list->reset(new base::FieldTrialList(nullptr));
 
-  // Ensure any field trials in browser are reflected into the child
-  // process.
+// Ensure any field trials in browser are reflected into the child
+// process.
 #if defined(OS_WIN)
   base::FieldTrialList::CreateTrialsFromCommandLine(
       command_line, switches::kFieldTrialHandle, -1);
@@ -587,12 +587,12 @@
 #else
   base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
   if (command_line.HasSwitch(switches::kSingleProcess)) {
-    LOG(FATAL) <<
-        "--single-process is not supported in chrome multiple dll browser.";
+    LOG(FATAL)
+        << "--single-process is not supported in chrome multiple dll browser.";
   }
   if (command_line.HasSwitch(switches::kInProcessGPU)) {
-    LOG(FATAL) <<
-        "--in-process-gpu is not supported in chrome multiple dll browser.";
+    LOG(FATAL)
+        << "--in-process-gpu is not supported in chrome multiple dll browser.";
   }
 #endif  // !CHROME_MULTIPLE_DLL_BROWSER && !CHROME_MULTIPLE_DLL_CHILD
 }
@@ -600,22 +600,21 @@
 // Run the FooMain() for a given process type.
 // If |process_type| is empty, runs BrowserMain().
 // Returns the exit code for this process.
-int RunNamedProcessTypeMain(
-    const std::string& process_type,
-    const MainFunctionParams& main_function_params,
-    ContentMainDelegate* delegate) {
+int RunNamedProcessTypeMain(const std::string& process_type,
+                            const MainFunctionParams& main_function_params,
+                            ContentMainDelegate* delegate) {
   static const MainFunction kMainFunctions[] = {
 #if !defined(CHROME_MULTIPLE_DLL_CHILD)
-    { "",                            BrowserMain },
+    {"", BrowserMain},
 #endif
 #if !defined(CHROME_MULTIPLE_DLL_BROWSER)
 #if BUILDFLAG(ENABLE_PLUGINS)
-    { switches::kPpapiPluginProcess, PpapiPluginMain },
-    { switches::kPpapiBrokerProcess, PpapiBrokerMain },
+    {switches::kPpapiPluginProcess, PpapiPluginMain},
+    {switches::kPpapiBrokerProcess, PpapiBrokerMain},
 #endif  // ENABLE_PLUGINS
-    { switches::kUtilityProcess,     UtilityMain },
-    { switches::kRendererProcess,    RendererMain },
-    { switches::kGpuProcess,         GpuMain },
+    {switches::kUtilityProcess, UtilityMain},
+    {switches::kRendererProcess, RendererMain},
+    {switches::kGpuProcess, GpuMain},
 #endif  // !CHROME_MULTIPLE_DLL_BROWSER
   };
 
@@ -624,8 +623,8 @@
   for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
     if (process_type == kMainFunctions[i].name) {
       if (delegate) {
-        int exit_code = delegate->RunProcess(process_type,
-            main_function_params);
+        int exit_code =
+            delegate->RunProcess(process_type, main_function_params);
 #if defined(OS_ANDROID)
         // In Android's browser process, the negative exit code doesn't mean the
         // default behavior should be used as the UI message loop is managed by
@@ -719,10 +718,10 @@
     is_initialized_ = true;
     delegate_ = params.delegate;
 
-    // The exit manager is in charge of calling the dtors of singleton objects.
-    // On Android, AtExitManager is set up when library is loaded.
-    // A consequence of this is that you can't use the ctor/dtor-based
-    // TRACE_EVENT methods on Linux or iOS builds till after we set this up.
+// The exit manager is in charge of calling the dtors of singleton objects.
+// On Android, AtExitManager is set up when library is loaded.
+// A consequence of this is that you can't use the ctor/dtor-based
+// TRACE_EVENT methods on Linux or iOS builds till after we set this up.
 #if !defined(OS_ANDROID)
     if (!ui_task_) {
       // When running browser tests, don't create a second AtExitManager as that
@@ -752,8 +751,8 @@
 
 #if defined(OS_WIN)
     if (command_line.HasSwitch(switches::kDeviceScaleFactor)) {
-      std::string scale_factor_string = command_line.GetSwitchValueASCII(
-          switches::kDeviceScaleFactor);
+      std::string scale_factor_string =
+          command_line.GetSwitchValueASCII(switches::kDeviceScaleFactor);
       double scale_factor = 0;
       if (base::StringToDouble(scale_factor_string, &scale_factor))
         display::win::SetDefaultDeviceScaleFactor(scale_factor);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 7299492..ccb4f8e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -325,8 +325,6 @@
     "android/launcher_thread.h",
     "android/scoped_surface_request_manager.cc",
     "android/scoped_surface_request_manager.h",
-    "android/string_message_codec.cc",
-    "android/string_message_codec.h",
     "android/text_suggestion_host_android.cc",
     "android/text_suggestion_host_android.h",
     "android/text_suggestion_host_mojo_impl_android.cc",
@@ -501,7 +499,7 @@
     "browser_main.h",
     "browser_main_loop.cc",
     "browser_main_loop.h",
-    "browser_main_runner.cc",
+    "browser_main_runner_impl.cc",
     "browser_plugin/browser_plugin_embedder.cc",
     "browser_plugin/browser_plugin_embedder.h",
     "browser_plugin/browser_plugin_guest.cc",
diff --git a/content/browser/android/app_web_message_port.cc b/content/browser/android/app_web_message_port.cc
index 97e66fd5..ec7b9ba 100644
--- a/content/browser/android/app_web_message_port.cc
+++ b/content/browser/android/app_web_message_port.cc
@@ -9,8 +9,8 @@
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/browser/android/string_message_codec.h"
 #include "jni/AppWebMessagePort_jni.h"
+#include "third_party/blink/public/common/message_port/string_message_codec.h"
 
 using blink::MessagePortChannel;
 
@@ -44,7 +44,7 @@
                                            &encoded_message);
 
   base::string16 message;
-  if (!DecodeStringMessage(encoded_message, &message))
+  if (!blink::DecodeStringMessage(encoded_message, &message))
     return nullptr;
 
   base::android::ScopedJavaLocalRef<jstring> jmessage =
@@ -57,8 +57,8 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jstring>& jmessage) {
-  std::vector<uint8_t> encoded_message =
-      EncodeStringMessage(base::android::ConvertJavaStringToUTF16(jmessage));
+  std::vector<uint8_t> encoded_message = blink::EncodeStringMessage(
+      base::android::ConvertJavaStringToUTF16(jmessage));
   return base::android::ToJavaByteArray(env, encoded_message);
 }
 
diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner_impl.cc
similarity index 96%
rename from content/browser/browser_main_runner.cc
rename to content/browser/browser_main_runner_impl.cc
index 9c94248..8e5ef3c 100644
--- a/content/browser/browser_main_runner.cc
+++ b/content/browser/browser_main_runner_impl.cc
@@ -127,9 +127,9 @@
       main_loop_->MainMessageLoopStart();
       main_loop_->PostMainMessageLoopStart();
 
-// WARNING: If we get a WM_ENDSESSION, objects created on the stack here
-// are NOT deleted. If you need something to run during WM_ENDSESSION add it
-// to browser_shutdown::Shutdown or BrowserProcess::EndSession.
+      // WARNING: If we get a WM_ENDSESSION, objects created on the stack here
+      // are NOT deleted. If you need something to run during WM_ENDSESSION add
+      // it to browser_shutdown::Shutdown or BrowserProcess::EndSession.
 
       ui::InitializeInputMethod();
       UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep1Time",
@@ -215,16 +215,16 @@
       main_loop_->ShutdownThreadsAndCleanUp();
 
       ui::ShutdownInputMethod();
-  #if defined(OS_WIN)
+#if defined(OS_WIN)
       ole_initializer_.reset(NULL);
-  #endif
-  #if defined(OS_ANDROID)
+#endif
+#if defined(OS_ANDROID)
       // Forcefully terminates the RunLoop inside MessagePumpForUI, ensuring
       // proper shutdown for content_browsertests. Shutdown() is not used by
       // the actual browser.
       if (base::RunLoop::IsRunningOnCurrentThread())
         base::RunLoop::QuitCurrentDeprecated();
-  #endif
+#endif
       main_loop_.reset(nullptr);
 
       notification_service_.reset(nullptr);
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index dfc17cc..8677c1cc 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -96,6 +96,10 @@
   return rwhv;
 }
 
+RenderWidgetHostViewBase* RenderWidgetHostViewGuest::GetParentView() {
+  return GetOwnerRenderWidgetHostView();
+}
+
 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
     RenderWidgetHost* widget_host,
     BrowserPluginGuest* guest,
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h
index 39125bf..529bf0bf 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -62,6 +62,9 @@
   // Called when this RenderWidgetHostViewGuest is attached.
   void OnAttached();
 
+  // RenderWidgetHostViewChildFrame implementation.
+  RenderWidgetHostViewBase* GetParentView() override;
+
   // RenderWidgetHostView implementation.
   bool OnMessageReceived(const IPC::Message& msg) override;
   void InitAsChild(gfx::NativeView parent_view) override;
diff --git a/content/browser/media/audio_input_stream_broker_unittest.cc b/content/browser/media/audio_input_stream_broker_unittest.cc
index 1d078d3..956f5f04 100644
--- a/content/browser/media/audio_input_stream_broker_unittest.cc
+++ b/content/browser/media/audio_input_stream_broker_unittest.cc
@@ -12,6 +12,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "media/mojo/interfaces/audio_input_stream.mojom.h"
 #include "mojo/public/cpp/system/platform_handle.h"
+#include "services/audio/public/cpp/fake_stream_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -69,19 +70,11 @@
   media::mojom::AudioInputStreamClientRequest client_request_;
 };
 
-class MockStreamFactory : public audio::mojom::StreamFactory {
+class MockStreamFactory : public audio::FakeStreamFactory {
  public:
-  MockStreamFactory() : binding_(this) {}
+  MockStreamFactory() {}
   ~MockStreamFactory() final {}
 
-  audio::mojom::StreamFactoryPtr MakePtr() {
-    audio::mojom::StreamFactoryPtr ret;
-    binding_.Bind(mojo::MakeRequest(&ret));
-    return ret;
-  }
-
-  void CloseBinding() { binding_.Close(); }
-
   // State of an expected stream creation. |device_id| and |params| are set
   // ahead of time and verified during request. The other fields are filled in
   // when the request is received.
@@ -134,23 +127,6 @@
     stream_request_data_->created_callback = std::move(created_callback);
   }
 
-  void CreateOutputStream(
-      media::mojom::AudioOutputStreamRequest stream_request,
-      media::mojom::AudioOutputStreamObserverAssociatedPtrInfo observer_info,
-      media::mojom::AudioLogPtr log,
-      const std::string& output_device_id,
-      const media::AudioParameters& params,
-      const base::UnguessableToken& group_id,
-      CreateOutputStreamCallback created_callback) final {
-    ADD_FAILURE() << "Unexpected output stream creation in input test.";
-  }
-
-  void BindMuter(audio::mojom::LocalMuterAssociatedRequest request,
-                 const base::UnguessableToken& group_id) final {
-    ADD_FAILURE() << "Unexpected muting in input stream test";
-  }
-
-  mojo::Binding<audio::mojom::StreamFactory> binding_;
   StreamRequestData* stream_request_data_;
 };
 
diff --git a/content/browser/media/audio_output_stream_broker_unittest.cc b/content/browser/media/audio_output_stream_broker_unittest.cc
index 98fb2d4..2a634904 100644
--- a/content/browser/media/audio_output_stream_broker_unittest.cc
+++ b/content/browser/media/audio_output_stream_broker_unittest.cc
@@ -20,7 +20,7 @@
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/platform_handle.h"
-#include "services/audio/public/mojom/stream_factory.mojom.h"
+#include "services/audio/public/cpp/fake_stream_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -76,19 +76,11 @@
   mojo::Binding<media::mojom::AudioOutputStreamProviderClient> binding_;
 };
 
-class MockStreamFactory : public audio::mojom::StreamFactory {
+class MockStreamFactory : public audio::FakeStreamFactory {
  public:
-  MockStreamFactory() : binding_(this) {}
+  MockStreamFactory() {}
   ~MockStreamFactory() final {}
 
-  audio::mojom::StreamFactoryPtr MakePtr() {
-    audio::mojom::StreamFactoryPtr ret;
-    binding_.Bind(mojo::MakeRequest(&ret));
-    return ret;
-  }
-
-  void CloseBinding() { binding_.Close(); }
-
   // State of an expected stream creation. |output_device_id|, |params|,
   // and |groups_id| are set ahead of time and verified during request.
   // The other fields are filled in when the request is received.
@@ -115,19 +107,6 @@
   }
 
  private:
-  void CreateInputStream(media::mojom::AudioInputStreamRequest stream_request,
-                         media::mojom::AudioInputStreamClientPtr client,
-                         media::mojom::AudioInputStreamObserverPtr observer,
-                         media::mojom::AudioLogPtr log,
-                         const std::string& device_id,
-                         const media::AudioParameters& params,
-                         uint32_t shared_memory_count,
-                         bool enable_agc,
-                         mojo::ScopedSharedBufferHandle key_press_count_buffer,
-                         CreateInputStreamCallback created_callback) final {
-    ADD_FAILURE() << "Unexpected input stream creation in output test.";
-  }
-
   void CreateOutputStream(
       media::mojom::AudioOutputStreamRequest stream_request,
       media::mojom::AudioOutputStreamObserverAssociatedPtrInfo observer_info,
@@ -148,12 +127,6 @@
     stream_request_data_->created_callback = std::move(created_callback);
   }
 
-  void BindMuter(audio::mojom::LocalMuterAssociatedRequest request,
-                 const base::UnguessableToken& group_id) final {
-    ADD_FAILURE() << "Unexpected muting in output stream test";
-  }
-
-  mojo::Binding<audio::mojom::StreamFactory> binding_;
   StreamRequestData* stream_request_data_;
 };
 
diff --git a/content/browser/message_port_provider.cc b/content/browser/message_port_provider.cc
index 86ebc20d..e5d8f66 100644
--- a/content/browser/message_port_provider.cc
+++ b/content/browser/message_port_provider.cc
@@ -9,6 +9,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/common/message_port/string_message_codec.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/jni_string.h"
@@ -28,11 +29,10 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   FrameMsg_PostMessage_Params params;
-  params.is_data_raw_string = true;
   params.message = new base::RefCountedData<blink::TransferableMessage>();
+  params.message->data.owned_encoded_message = blink::EncodeStringMessage(data);
   params.message->data.encoded_message =
-      base::make_span(reinterpret_cast<const uint8_t*>(data.data()),
-                      data.size() * sizeof(base::char16));
+      params.message->data.owned_encoded_message;
   params.message->data.ports = std::move(channels);
   params.source_routing_id = MSG_ROUTING_NONE;
   params.source_origin = source_origin;
diff --git a/content/browser/renderer_host/media/media_devices_manager.cc b/content/browser/renderer_host/media/media_devices_manager.cc
index 0ec4dc82..0a57242 100644
--- a/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/content/browser/renderer_host/media/media_devices_manager.cc
@@ -12,6 +12,7 @@
 
 #include "base/command_line.h"
 #include "base/location.h"
+#include "base/sequence_checker.h"
 #include "base/strings/stringprintf.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_checker.h"
@@ -20,11 +21,18 @@
 #include "content/browser/media/media_devices_permission_checker.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
+#include "content/browser/service_manager/service_manager_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_features.h"
 #include "media/audio/audio_device_description.h"
 #include "media/audio/audio_system.h"
 #include "media/base/media_switches.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/audio/public/mojom/constants.mojom.h"
+#include "services/audio/public/mojom/device_notifications.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/identity.h"
+#include "services/service_manager/public/mojom/connector.mojom-shared.h"
 
 #if defined(OS_MACOSX)
 #include "base/bind_helpers.h"
@@ -267,6 +275,64 @@
 MediaDevicesManager::SubscriptionRequest::operator=(SubscriptionRequest&&) =
     default;
 
+class MediaDevicesManager::AudioServiceDeviceListener
+    : public audio::mojom::DeviceListener {
+ public:
+  explicit AudioServiceDeviceListener(service_manager::Connector* connector)
+      : binding_(this), weak_factory_(this) {
+    TryConnectToService(connector);
+  }
+  ~AudioServiceDeviceListener() override = default;
+
+  void DevicesChanged() override {
+    auto* system_monitor = base::SystemMonitor::Get();
+    if (system_monitor)
+      system_monitor->ProcessDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO);
+  }
+
+ private:
+  void TryConnectToService(service_manager::Connector* connector) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    // Check if the service manager is managing the audio service.
+    connector->QueryService(
+        service_manager::Identity(audio::mojom::kServiceName),
+        base::BindOnce(&AudioServiceDeviceListener::DoConnectToService,
+                       weak_factory_.GetWeakPtr(), connector));
+  }
+
+  void DoConnectToService(service_manager::Connector* connector,
+                          service_manager::mojom::ConnectResult connect_result,
+                          const std::string& ignore) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    DCHECK(!mojo_audio_device_notifier_);
+    DCHECK(!binding_);
+    // Do not connect if the service manager is not managing the audio service.
+    if (connect_result != service_manager::mojom::ConnectResult::SUCCEEDED) {
+      LOG(WARNING) << "Audio service not available: " << connect_result;
+      return;
+    }
+
+    connector->BindInterface(audio::mojom::kServiceName,
+                             mojo::MakeRequest(&mojo_audio_device_notifier_));
+    mojo_audio_device_notifier_.set_connection_error_handler(base::BindOnce(
+        &MediaDevicesManager::AudioServiceDeviceListener::TryConnectToService,
+        weak_factory_.GetWeakPtr(), connector));
+    audio::mojom::DeviceListenerPtr audio_device_listener_ptr;
+    binding_.Bind(mojo::MakeRequest(&audio_device_listener_ptr));
+    mojo_audio_device_notifier_->RegisterListener(
+        std::move(audio_device_listener_ptr));
+  }
+
+  mojo::Binding<audio::mojom::DeviceListener> binding_;
+  audio::mojom::DeviceNotifierPtr mojo_audio_device_notifier_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<AudioServiceDeviceListener> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioServiceDeviceListener);
+};
+
 MediaDevicesManager::MediaDevicesManager(
     media::AudioSystem* audio_system,
     const scoped_refptr<VideoCaptureManager>& video_capture_manager,
@@ -336,6 +402,7 @@
     const BoolDeviceTypes& subscribe_types,
     blink::mojom::MediaDevicesListenerPtr listener) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  StartMonitoring();
   uint32_t subscription_id = ++last_subscription_id_;
   blink::mojom::MediaDevicesListenerPtr media_devices_listener =
       std::move(listener);
@@ -385,6 +452,22 @@
     return;
 #endif
 
+#if defined(OS_WIN)
+  if (base::FeatureList::IsEnabled(features::kAudioServiceOutOfProcess)) {
+    DCHECK(!audio_service_device_listener_);
+    if (!connector_) {
+      auto* connector = ServiceManagerContext::GetConnectorForIOThread();
+      // |connector| can be null on unit tests.
+      if (!connector)
+        return;
+
+      connector_ = connector->Clone();
+    }
+
+    audio_service_device_listener_ =
+        std::make_unique<AudioServiceDeviceListener>(connector_.get());
+  }
+#endif
   monitoring_started_ = true;
   base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
 
@@ -419,6 +502,7 @@
   if (!monitoring_started_)
     return;
   base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
+  audio_service_device_listener_.reset();
   monitoring_started_ = false;
   for (size_t i = 0; i < NUM_MEDIA_DEVICE_TYPES; ++i)
     SetCachePolicy(static_cast<MediaDeviceType>(i), CachePolicy::NO_CACHE);
diff --git a/content/browser/renderer_host/media/media_devices_manager.h b/content/browser/renderer_host/media/media_devices_manager.h
index 59fae7ff..a6696e0 100644
--- a/content/browser/renderer_host/media/media_devices_manager.h
+++ b/content/browser/renderer_host/media/media_devices_manager.h
@@ -30,6 +30,10 @@
 class AudioSystem;
 }
 
+namespace service_manager {
+class Connector;
+}
+
 namespace content {
 
 class MediaDevicesPermissionChecker;
@@ -264,6 +268,11 @@
   // Callback used to obtain the current device ID salt and security origin.
   MediaDeviceSaltAndOriginCallback salt_and_origin_callback_;
 
+  std::unique_ptr<service_manager::Connector> connector_;
+
+  class AudioServiceDeviceListener;
+  std::unique_ptr<AudioServiceDeviceListener> audio_service_device_listener_;
+
   base::WeakPtrFactory<MediaDevicesManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaDevicesManager);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 54864936..44fe389 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1939,9 +1939,9 @@
   scoped_refptr<ChromeBlobStorageContext> blob_storage_context =
       ChromeBlobStorageContext::GetFor(browser_context);
 
-  AddUIThreadInterface(
-      registry.get(),
-      base::Bind(&ClipboardHostImpl::Create, std::move(blob_storage_context)));
+  AddUIThreadInterface(registry.get(),
+                       base::BindRepeating(&ClipboardHostImpl::Create,
+                                           std::move(blob_storage_context)));
 
   media::VideoDecodePerfHistory* video_perf_history =
       GetBrowserContext()->GetVideoDecodePerfHistory();
@@ -2014,8 +2014,6 @@
   AddUIThreadInterface(registry.get(), base::Bind(&FieldTrialRecorder::Create));
 
   associated_interfaces_.reset(new AssociatedInterfaceRegistryImpl());
-  GetContentClient()->browser()->ExposeInterfacesToRenderer(
-      registry.get(), associated_interfaces_.get(), this);
   blink::AssociatedInterfaceRegistry* associated_registry =
       associated_interfaces_.get();
   associated_registry->AddInterface(base::Bind(
@@ -2038,6 +2036,14 @@
   registry->AddInterface(base::BindRepeating(&KeySystemSupportImpl::Create));
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
+  // ---- Please do not register interfaces below this line ------
+  //
+  // This call should be done after registering all interfaces above, so that
+  // embedder can override any interfaces. The fact that registry calls
+  // the last registration for the name allows us to easily override interfaces.
+  GetContentClient()->browser()->ExposeInterfacesToRenderer(
+      registry.get(), associated_interfaces_.get(), this);
+
   ServiceManagerConnection* service_manager_connection =
       BrowserContext::GetServiceManagerConnectionFor(browser_context_);
   if (connection_filter_id_ !=
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index c94df659..bed6be9 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -221,7 +221,7 @@
   // Returns the view into which this view is directly embedded. This can
   // return nullptr when this view's associated child frame is not connected
   // to the frame tree.
-  RenderWidgetHostViewBase* GetParentView();
+  virtual RenderWidgetHostViewBase* GetParentView();
 
   void RegisterFrameSinkId();
   void UnregisterFrameSinkId();
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 1b5b3ad3..c5720b29 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -431,11 +431,6 @@
 IPC_STRUCT_END()
 
 IPC_STRUCT_BEGIN(FrameMsg_PostMessage_Params)
-  // Whether the data format is supplied as serialized script value, or as
-  // a simple string. If it is a raw string, must be converted from string to a
-  // WebSerializedScriptValue in the renderer process.
-  IPC_STRUCT_MEMBER(bool, is_data_raw_string)
-
   // When sent to the browser, this is the routing ID of the source frame in
   // the source process.  The browser replaces it with the routing ID of the
   // equivalent frame proxy in the destination process.
diff --git a/content/public/android/java/src/org/chromium/content/browser/RenderCoordinatesImpl.java b/content/public/android/java/src/org/chromium/content/browser/RenderCoordinatesImpl.java
index 4dd4761b..9cacde5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/RenderCoordinatesImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/RenderCoordinatesImpl.java
@@ -79,6 +79,11 @@
         return (int) Math.ceil(getLastFrameViewportHeightPix());
     }
 
+    @Override
+    public int getMaxVerticalScrollPixInt() {
+        return (int) Math.floor(getMaxVerticalScrollPix());
+    }
+
     void updateContentSizeCss(float contentWidthCss, float contentHeightCss) {
         mContentWidthCss = contentWidthCss;
         mContentHeightCss = contentHeightCss;
@@ -224,9 +229,4 @@
     private int getMaxHorizontalScrollPixInt() {
         return (int) Math.floor(getMaxHorizontalScrollPix());
     }
-
-    // Maximum possible vertical scroll in physical pixels (approx, integer).
-    private int getMaxVerticalScrollPixInt() {
-        return (int) Math.floor(getMaxVerticalScrollPix());
-    }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/RenderCoordinates.java b/content/public/android/java/src/org/chromium/content_public/browser/RenderCoordinates.java
index 87ee3fc..1244d05 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/RenderCoordinates.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/RenderCoordinates.java
@@ -46,4 +46,9 @@
      * @return Render-reported height of the viewport in physical pixels (approx, integer).
      */
     int getLastFrameViewportHeightPixInt();
+
+    /**
+     * @return Maximum possible vertical scroll in physical pixels (approx, integer).
+     */
+    int getMaxVerticalScrollPixInt();
 }
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index e3c4a13..9642ff3 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -74,7 +74,12 @@
       },
       "requires": {
         "*": [ "app" ],
-        "audio": [ "info", "debug_recording", "stream_factory"],
+        "audio": [
+          "info",
+          "debug_recording",
+          "device_notifier",
+          "stream_factory"
+        ],
         "cdm": [ "media:cdm" ],
         "content_gpu": [ "browser" ],
         "content_plugin": [ "browser" ],
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index dffff04f..b5cad2b 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -134,7 +134,9 @@
   using BlobContextGetter =
       base::RepeatingCallback<base::WeakPtr<storage::BlobStorageContext>()>;
 
-  // |callback| returns a nullptr scoped_ptr on failure.
+  // This method should be called on UI thread and calls back on UI thread
+  // as well. Note that retrieving a blob ptr out of BlobHandle can only be
+  // done on IO. |callback| returns a nullptr on failure.
   static void CreateMemoryBackedBlob(BrowserContext* browser_context,
                                      const char* data,
                                      size_t length,
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index c8e1db9..5ff6ab1 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -70,10 +70,6 @@
   return nullptr;
 }
 
-blink::WebClipboard* ContentRendererClient::OverrideWebClipboard() {
-  return nullptr;
-}
-
 blink::WebThemeEngine* ContentRendererClient::OverrideThemeEngine() {
   return nullptr;
 }
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index e62a17b..59aba6d 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -41,7 +41,6 @@
 namespace blink {
 class WebAudioDevice;
 class WebAudioLatencyHint;
-class WebClipboard;
 class WebFrame;
 class WebLocalFrame;
 class WebMIDIAccessor;
@@ -172,10 +171,6 @@
   virtual std::unique_ptr<blink::WebAudioDevice> OverrideCreateAudioDevice(
       const blink::WebAudioLatencyHint& latency_hint);
 
-  // Allows the embedder to override the blink::WebClipboard used. If it
-  // returns NULL the content layer will handle clipboard interactions.
-  virtual blink::WebClipboard* OverrideWebClipboard();
-
   // Allows the embedder to override the WebThemeEngine used. If it returns NULL
   // the content layer will provide an engine.
   virtual blink::WebThemeEngine* OverrideThemeEngine();
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 86db62d..53e2aa1 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -751,6 +751,25 @@
       mouse_event);
 }
 
+void SimulateRoutedMouseEvent(WebContents* web_contents,
+                              blink::WebInputEvent::Type type,
+                              const gfx::Point& point) {
+  content::WebContentsImpl* web_contents_impl =
+      static_cast<content::WebContentsImpl*>(web_contents);
+  content::RenderWidgetHostViewBase* rwhvb =
+      static_cast<content::RenderWidgetHostViewBase*>(
+          web_contents->GetRenderWidgetHostView());
+  blink::WebMouseEvent mouse_event(type, 0, ui::EventTimeForNow());
+  mouse_event.SetPositionInWidget(point.x(), point.y());
+  // Mac needs positionInScreen for events to plugins.
+  gfx::Rect offset = web_contents->GetContainerBounds();
+  mouse_event.SetPositionInScreen(point.x() + offset.x(),
+                                  point.y() + offset.y());
+
+  web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
+                                                            ui::LatencyInfo());
+}
+
 void SimulateMouseWheelEvent(WebContents* web_contents,
                              const gfx::Point& point,
                              const gfx::Vector2d& delta,
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index e2954ad2..1cca5c1 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -160,6 +160,12 @@
                         blink::WebInputEvent::Type type,
                         const gfx::Point& point);
 
+// Same as SimulateMouseEvent() except it forces the mouse event to go through
+// RenderWidgetHostInputEventRouter.
+void SimulateRoutedMouseEvent(WebContents* web_contents,
+                              blink::WebInputEvent::Type type,
+                              const gfx::Point& point);
+
 // Simulate a mouse wheel event.
 void SimulateMouseWheelEvent(WebContents* web_contents,
                              const gfx::Point& point,
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index 387ebc9b..3c0fcb21 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -57,8 +57,7 @@
     : response_(response),
       completed_event_(completed_event),
       download_to_blob_registry_(std::move(download_to_blob_registry)),
-      task_runner_(std::move(task_runner)),
-      fetch_request_mode_(request->fetch_request_mode) {
+      task_runner_(std::move(task_runner)) {
   url_loader_factory_ =
       network::SharedURLLoaderFactory::Create(std::move(url_loader_factory));
   if (abort_event) {
@@ -88,25 +87,19 @@
     const net::RedirectInfo& redirect_info,
     const network::ResourceResponseInfo& info) {
   DCHECK(!Completed());
-  // Synchronous loads in blink aren't associated with a ResourceClient, and
-  // CORS checks are performed by ResourceClient subclasses, so there's
-  // currently no way to perform CORS checks for redirects.
-  // Err on the side of extreme caution and block any cross origin redirect
-  // that might have CORS implications.
-  if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS &&
-      redirect_info.new_url.GetOrigin() != response_->url.GetOrigin()) {
+  if (redirect_info.new_url.GetOrigin() != response_->url.GetOrigin()) {
     LOG(ERROR) << "Cross origin redirect denied";
     response_->error_code = net::ERR_ABORTED;
-  } else {
-    response_->info = info;
-    response_->redirect_info = redirect_info;
+
+    CompleteRequest(false /* remove_pending_request */);
+
+    // Returning false here will cause the request to be cancelled and this
+    // object deleted.
+    return false;
   }
 
-  // Returning false here will cause the request to be cancelled and this
-  // object deleted. WebURLLoaderImpl may create a new SyncLoadContext to
-  // manually follow the redirect.
-  CompleteRequest(false /* remove_pending_request */);
-  return false;
+  response_->url = redirect_info.new_url;
+  return true;
 }
 
 void SyncLoadContext::OnReceivedResponse(
diff --git a/content/renderer/loader/sync_load_context.h b/content/renderer/loader/sync_load_context.h
index 96c8b901..26c0772 100644
--- a/content/renderer/loader/sync_load_context.h
+++ b/content/renderer/loader/sync_load_context.h
@@ -114,8 +114,6 @@
   base::WaitableEventWatcher abort_watcher_;
   base::OneShotTimer timeout_timer_;
 
-  const network::mojom::FetchRequestMode fetch_request_mode_;
-
   DISALLOW_COPY_AND_ASSIGN(SyncLoadContext);
 };
 
diff --git a/content/renderer/loader/sync_load_response.h b/content/renderer/loader/sync_load_response.h
index 9c845bc2..bd46a9b 100644
--- a/content/renderer/loader/sync_load_response.h
+++ b/content/renderer/loader/sync_load_response.h
@@ -26,8 +26,6 @@
 
   SyncLoadResponse& operator=(SyncLoadResponse&& other);
 
-  base::Optional<net::RedirectInfo> redirect_info;
-
   network::ResourceResponseInfo info;
 
   // The response error code.
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index c61303a..622625df 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -1290,8 +1290,7 @@
 }
 
 void WebURLLoaderImpl::LoadSynchronously(
-    WebURLLoaderClient* client,
-    const WebURLRequest& passed_request,
+    const WebURLRequest& request,
     WebURLResponse& response,
     base::Optional<WebURLError>& error,
     WebData& data,
@@ -1301,40 +1300,7 @@
     blink::WebBlobInfo& downloaded_blob) {
   TRACE_EVENT0("loading", "WebURLLoaderImpl::loadSynchronously");
   SyncLoadResponse sync_load_response;
-  int redirect_limit = net::URLRequest::kMaxRedirects;
-  WebURLRequest request(passed_request);
-
-  // SyncLoadResponse won't automatically follow redirects, so manually
-  // check and follow valid redirects here.
-  while (true) {
-    context_->Start(request, &sync_load_response);
-
-    if (!sync_load_response.redirect_info)
-      break;
-
-    if (!redirect_limit--) {
-      error = WebURLError(net::ERR_TOO_MANY_REDIRECTS, sync_load_response.url);
-      return;
-    }
-
-    const net::RedirectInfo& redirect_info = *sync_load_response.redirect_info;
-    WebURLResponse redirect_response;
-    PopulateURLResponse(sync_load_response.url, sync_load_response.info,
-                        &redirect_response, request.ReportRawHeaders());
-    bool report_raw_headers = false;
-    if (!client->WillFollowRedirect(
-            redirect_info.new_url, redirect_info.new_site_for_cookies,
-            WebString::FromUTF8(redirect_info.new_referrer),
-            Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
-                redirect_info.new_referrer_policy),
-            WebString::FromUTF8(redirect_info.new_method), redirect_response,
-            report_raw_headers)) {
-      return;
-    }
-
-    request.SetURL(redirect_info.new_url);
-    sync_load_response = SyncLoadResponse();
-  }
+  context_->Start(request, &sync_load_response);
 
   const GURL& final_url = sync_load_response.url;
 
diff --git a/content/renderer/loader/web_url_loader_impl.h b/content/renderer/loader/web_url_loader_impl.h
index 552d5b4..36ac4350 100644
--- a/content/renderer/loader/web_url_loader_impl.h
+++ b/content/renderer/loader/web_url_loader_impl.h
@@ -69,8 +69,7 @@
                                   blink::WebURLResponse* response,
                                   bool report_security_info);
   // WebURLLoader methods:
-  void LoadSynchronously(blink::WebURLLoaderClient* client,
-                         const blink::WebURLRequest& request,
+  void LoadSynchronously(const blink::WebURLRequest& request,
                          blink::WebURLResponse& response,
                          base::Optional<blink::WebURLError>& error,
                          blink::WebData& data,
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index 0dfe9aa..c842cb5 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -798,8 +798,8 @@
   base::Optional<int64_t> downloaded_file_length;
   blink::WebBlobInfo downloaded_blob;
   client()->loader()->LoadSynchronously(
-      nullptr, request, response, error, data, encoded_data_length,
-      encoded_body_length, downloaded_file_length, downloaded_blob);
+      request, response, error, data, encoded_data_length, encoded_body_length,
+      downloaded_file_length, downloaded_blob);
 
   EXPECT_EQ(kEncodedBodyLength, encoded_body_length);
   EXPECT_EQ(kEncodedDataLength, encoded_data_length);
diff --git a/content/renderer/media_capture_from_element/canvas_capture_handler.cc b/content/renderer/media_capture_from_element/canvas_capture_handler.cc
index 9c71a01..c2d9031 100644
--- a/content/renderer/media_capture_from_element/canvas_capture_handler.cc
+++ b/content/renderer/media_capture_from_element/canvas_capture_handler.cc
@@ -62,12 +62,15 @@
                     const VideoCaptureDeliverFrameCB& frame_callback,
                     const RunningCallback& running_callback) override {
     DCHECK(main_render_thread_checker_.CalledOnValidThread());
-    canvas_handler_->StartVideoCapture(params, frame_callback,
-                                       running_callback);
+    if (canvas_handler_.get()) {
+      canvas_handler_->StartVideoCapture(params, frame_callback,
+                                         running_callback);
+    }
   }
   void RequestRefreshFrame() override {
     DCHECK(main_render_thread_checker_.CalledOnValidThread());
-    canvas_handler_->RequestRefreshFrame();
+    if (canvas_handler_.get())
+      canvas_handler_->RequestRefreshFrame();
   }
   void StopCapture() override {
     DCHECK(main_render_thread_checker_.CalledOnValidThread());
@@ -80,8 +83,10 @@
   const float frame_rate_;
   // Bound to Main Render thread.
   base::ThreadChecker main_render_thread_checker_;
-  // CanvasCaptureHandler is owned by CanvasDrawListener in blink and might be
-  // destroyed before StopCapture() call.
+  // CanvasCaptureHandler is owned by CanvasDrawListener in blink. It is
+  // guaranteed to be destroyed on Main Render thread and it would happen
+  // independently of this class. Therefore, WeakPtr should always be checked
+  // before use.
   base::WeakPtr<CanvasCaptureHandler> canvas_handler_;
 };
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 3f687911..48d934d 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2297,33 +2297,9 @@
         WebString::FromUTF16(params.target_origin));
   }
 
-  WebDOMMessageEvent msg_event;
-  if (params.is_data_raw_string) {
-    v8::Isolate* isolate = blink::MainThreadIsolate();
-    v8::HandleScope handle_scope(isolate);
-    v8::Local<v8::Context> context = frame_->MainWorldScriptContext();
-    v8::Context::Scope context_scope(context);
-    V8ValueConverterImpl converter;
-    converter.SetDateAllowed(true);
-    converter.SetRegExpAllowed(true);
-    base::string16 data;
-    data.resize(params.message->data.encoded_message.size() /
-                sizeof(base::char16));
-    std::memcpy(&data[0], params.message->data.encoded_message.data(),
-                data.length() * sizeof(base::char16));
-    base::Value value(data);
-    v8::Local<v8::Value> result_value = converter.ToV8Value(&value, context);
-    WebSerializedScriptValue serialized_script_value =
-        WebSerializedScriptValue::Serialize(isolate, result_value);
-    msg_event = WebDOMMessageEvent(serialized_script_value,
-                                   WebString::FromUTF16(params.source_origin),
-                                   source_frame, frame_->GetDocument(),
-                                   std::move(params.message->data.ports));
-  } else {
-    msg_event = WebDOMMessageEvent(std::move(params.message->data),
-                                   WebString::FromUTF16(params.source_origin),
-                                   source_frame, frame_->GetDocument());
-  }
+  WebDOMMessageEvent msg_event(std::move(params.message->data),
+                               WebString::FromUTF16(params.source_origin),
+                               source_frame, frame_->GetDocument());
 
   frame_->DispatchMessageEventWithOriginCheck(
       target_origin, msg_event, params.message->data.has_user_gesture);
@@ -4568,10 +4544,6 @@
 }
 
 void RenderFrameImpl::ShowDeferredContextMenu(const ContextMenuParams& params) {
-  // TODO (amaralp): Remove this once selection menu race conditions are fixed.
-  if (selection_text_.empty() && !params.selection_text.empty())
-    return;
-
   Send(new FrameHostMsg_ContextMenu(routing_id_, params));
 }
 
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 5dbe0ff..6ed73a7 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -734,7 +734,6 @@
   DCHECK(!web_frame_ || web_frame_ == target_frame);
 
   FrameMsg_PostMessage_Params params;
-  params.is_data_raw_string = false;
   params.message =
       new base::RefCountedData<blink::TransferableMessage>(event.AsMessage());
   params.message->data.has_user_gesture = has_user_gesture;
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index bc8a289..d7262fe 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -96,7 +96,6 @@
 #include "third_party/blink/public/platform/web_gesture_device.h"
 #include "third_party/blink/public/platform/web_gesture_event.h"
 #include "third_party/blink/public/platform/web_input_event.h"
-#include <android/keycodes.h>
 #endif
 
 #if defined(OS_WIN)
@@ -1552,55 +1551,6 @@
       ExecuteJavaScriptAndReturnIntValue(check_did_select, &did_select));
   EXPECT_EQ(1, did_select);
 }
-
-TEST_F(RenderViewImplTest, AndroidContextMenuSelectionCleared) {
-  // Load an HTML page consisting of an input field.
-  LoadHTML("<html>"
-           "<head>"
-           "</head>"
-           "<body>"
-           "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
-           "</body>"
-           "</html>");
-
-  WebGestureEvent gesture_event(WebInputEvent::kGestureTap,
-                                WebInputEvent::kNoModifiers,
-                                ui::EventTimeForNow());
-  gesture_event.SetPositionInWidget(gfx::PointF(20, 20));
-
-  SendWebGestureEvent(gesture_event);
-
-  frame()->GetWebFrame()->ExecuteCommand("SelectAll");
-
-  blink::WebKeyboardEvent event(blink::WebKeyboardEvent::kRawKeyDown,
-                                blink::WebInputEvent::kNoModifiers,
-                                ui::EventTimeForNow());
-  event.windows_key_code = ui::VKEY_BACK;
-  event.native_key_code = AKEYCODE_DEL;
-  SendWebKeyboardEvent(event);
-
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner =
-      new content::MessageLoopRunner;
-  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
-      FROM_HERE, message_loop_runner->QuitClosure());
-
-  EXPECT_FALSE(render_thread_->sink().GetUniqueMessageMatching(
-      FrameHostMsg_ContextMenu::ID));
-
-  message_loop_runner->Run();
-
-  EXPECT_FALSE(render_thread_->sink().GetUniqueMessageMatching(
-      FrameHostMsg_ContextMenu::ID));
-
-  // Check whether text selection is cleared.
-  blink::WebInputMethodController* controller =
-      frame()->GetWebFrame()->GetInputMethodController();
-  blink::WebTextInputInfo info = controller->TextInputInfo();
-  EXPECT_EQ(0, info.selection_start);
-  EXPECT_EQ(0, info.selection_end);
-}
-
-
 #endif
 
 TEST_F(RenderViewImplTest, TestBackForward) {
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 1007db7..e6ada07 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -400,11 +400,7 @@
 }
 
 blink::WebClipboard* RendererBlinkPlatformImpl::Clipboard() {
-  blink::WebClipboard* clipboard =
-      GetContentClient()->renderer()->OverrideWebClipboard();
-  if (clipboard)
-    return clipboard;
-
+  // TODO(dgozman): remove the ability to override this from embedder.
   return BlinkPlatformImpl::Clipboard();
 }
 
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index 363653d..924625a 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -490,6 +490,7 @@
   prefs_ = WebPreferences();
   should_override_prefs_ = false;
   LayoutTestContentBrowserClient::Get()->SetPopupBlockingEnabled(false);
+  LayoutTestContentBrowserClient::Get()->ResetMockClipboardHost();
   navigation_history_dump_ = "";
   pixel_dump_.reset();
   actual_pixel_hash_ = "";
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.cc b/content/shell/browser/layout_test/layout_test_content_browser_client.cc
index 9b1341b..f601736 100644
--- a/content/shell/browser/layout_test/layout_test_content_browser_client.cc
+++ b/content/shell/browser/layout_test/layout_test_content_browser_client.cc
@@ -26,6 +26,7 @@
 #include "content/shell/common/layout_test/layout_test_switches.h"
 #include "content/shell/common/shell_messages.h"
 #include "content/shell/renderer/layout_test/blink_test_helpers.h"
+#include "content/test/mock_clipboard_host.h"
 #include "device/bluetooth/test/fake_bluetooth.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -97,6 +98,11 @@
   block_popups_ = block_popups;
 }
 
+void LayoutTestContentBrowserClient::ResetMockClipboardHost() {
+  if (mock_clipboard_host_)
+    mock_clipboard_host_->Reset();
+}
+
 std::unique_ptr<FakeBluetoothChooser>
 LayoutTestContentBrowserClient::GetNextFakeBluetoothChooser() {
   return std::move(next_fake_bluetooth_chooser_);
@@ -134,9 +140,9 @@
   registry->AddInterface(base::BindRepeating(&bluetooth::FakeBluetooth::Create),
                          ui_task_runner);
   // This class outlives |render_process_host|, which owns |registry|. Since
-  // CreateFakeBluetoothChooser will not be called after |registry| is deleted
+  // any binders will not be called after |registry| is deleted
   // and |registry| is outlived by this class, it is safe to use
-  // base::Unretained.
+  // base::Unretained in all binders.
   registry->AddInterface(
       base::BindRepeating(
           &LayoutTestContentBrowserClient::CreateFakeBluetoothChooser,
@@ -147,6 +153,19 @@
       base::Unretained(
           render_process_host->GetStoragePartition()->GetWebPackageContext())));
   registry->AddInterface(base::BindRepeating(&MojoLayoutTestHelper::Create));
+  registry->AddInterface(
+      base::BindRepeating(&LayoutTestContentBrowserClient::BindClipboardHost,
+                          base::Unretained(this)),
+      ui_task_runner);
+}
+
+void LayoutTestContentBrowserClient::BindClipboardHost(
+    blink::mojom::ClipboardHostRequest request) {
+  if (!mock_clipboard_host_) {
+    mock_clipboard_host_ =
+        std::make_unique<MockClipboardHost>(browser_context());
+  }
+  mock_clipboard_host_->Bind(std::move(request));
 }
 
 void LayoutTestContentBrowserClient::OverrideWebkitPrefs(
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.h b/content/shell/browser/layout_test/layout_test_content_browser_client.h
index 22245bf..d0ba191 100644
--- a/content/shell/browser/layout_test/layout_test_content_browser_client.h
+++ b/content/shell/browser/layout_test/layout_test_content_browser_client.h
@@ -7,12 +7,14 @@
 
 #include "content/shell/browser/shell_content_browser_client.h"
 #include "content/shell/common/layout_test/fake_bluetooth_chooser.mojom.h"
+#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
 
 namespace content {
 
 class FakeBluetoothChooser;
 class LayoutTestBrowserContext;
 class LayoutTestNotificationManager;
+class MockClipboardHost;
 
 class LayoutTestContentBrowserClient : public ShellContentBrowserClient {
  public:
@@ -24,6 +26,7 @@
 
   LayoutTestBrowserContext* GetLayoutTestBrowserContext();
   void SetPopupBlockingEnabled(bool block_popups_);
+  void ResetMockClipboardHost();
 
   // Retrieves the last created FakeBluetoothChooser instance.
   std::unique_ptr<FakeBluetoothChooser> GetNextFakeBluetoothChooser();
@@ -83,6 +86,7 @@
  private:
   // Creates and stores a FakeBluetoothChooser instance.
   void CreateFakeBluetoothChooser(mojom::FakeBluetoothChooserRequest request);
+  void BindClipboardHost(blink::mojom::ClipboardHostRequest request);
 
   std::unique_ptr<LayoutTestNotificationManager>
       layout_test_notification_manager_;
@@ -91,6 +95,7 @@
   // Stores the next instance of FakeBluetoothChooser that is to be returned
   // when GetNextFakeBluetoothChooser is called.
   std::unique_ptr<FakeBluetoothChooser> next_fake_bluetooth_chooser_;
+  std::unique_ptr<MockClipboardHost> mock_clipboard_host_;
 };
 
 }  // content
diff --git a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
index ac36346..a406244 100644
--- a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
+++ b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
@@ -31,7 +31,6 @@
 #include "content/shell/test_runner/web_test_interfaces.h"
 #include "content/shell/test_runner/web_test_runner.h"
 #include "content/shell/test_runner/web_view_test_proxy.h"
-#include "content/test/mock_webclipboard_impl.h"
 #include "media/base/audio_latency.h"
 #include "media/base/mime_util.h"
 #include "media/media_buildflags.h"
@@ -49,7 +48,6 @@
 #include "v8/include/v8.h"
 
 using blink::WebAudioDevice;
-using blink::WebClipboard;
 using blink::WebFrame;
 using blink::WebLocalFrame;
 using blink::WebMIDIAccessor;
@@ -205,12 +203,6 @@
   return interfaces->CreateAudioDevice(hw_sample_rate, buffer_size);
 }
 
-WebClipboard* LayoutTestContentRendererClient::OverrideWebClipboard() {
-  if (!clipboard_)
-    clipboard_.reset(new MockWebClipboardImpl);
-  return clipboard_.get();
-}
-
 WebThemeEngine* LayoutTestContentRendererClient::OverrideThemeEngine() {
   return LayoutTestRenderThreadObserver::GetInstance()
       ->test_interfaces()
diff --git a/content/shell/renderer/layout_test/layout_test_content_renderer_client.h b/content/shell/renderer/layout_test/layout_test_content_renderer_client.h
index 4f66252..c3dbbb2b 100644
--- a/content/shell/renderer/layout_test/layout_test_content_renderer_client.h
+++ b/content/shell/renderer/layout_test/layout_test_content_renderer_client.h
@@ -12,7 +12,6 @@
 namespace content {
 
 class LayoutTestRenderThreadObserver;
-class MockWebClipboardImpl;
 
 class LayoutTestContentRendererClient : public ShellContentRendererClient {
  public:
@@ -27,7 +26,6 @@
       blink::WebMIDIAccessorClient* client) override;
   std::unique_ptr<blink::WebAudioDevice> OverrideCreateAudioDevice(
       const blink::WebAudioLatencyHint& latency_hint) override;
-  blink::WebClipboard* OverrideWebClipboard() override;
   blink::WebThemeEngine* OverrideThemeEngine() override;
   std::unique_ptr<MediaStreamRendererFactory> CreateMediaStreamRendererFactory()
       override;
@@ -40,7 +38,6 @@
 
  private:
   std::unique_ptr<LayoutTestRenderThreadObserver> shell_observer_;
-  std::unique_ptr<MockWebClipboardImpl> clipboard_;
 };
 
 }  // namespace content
diff --git a/content/shell/test_runner/DEPS b/content/shell/test_runner/DEPS
index 93c11b5..87557c17 100644
--- a/content/shell/test_runner/DEPS
+++ b/content/shell/test_runner/DEPS
@@ -9,6 +9,7 @@
   "+net/base",
   "+services/device/public/cpp/generic_sensor",
   "+services/device/public/mojom",
+  "+services/service_manager/public/cpp",
   "+skia",
   "+third_party/khronos/GLES2/gl2.h",
   "+third_party/skia",
diff --git a/content/shell/test_runner/pixel_dump.cc b/content/shell/test_runner/pixel_dump.cc
index 9fe74f9..691b465 100644
--- a/content/shell/test_runner/pixel_dump.cc
+++ b/content/shell/test_runner/pixel_dump.cc
@@ -17,23 +17,51 @@
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/skia_paint_canvas.h"
 #include "content/shell/test_runner/layout_test_runtime_flags.h"
+#include "mojo/public/cpp/system/data_pipe_drainer.h"
+#include "services/service_manager/public/cpp/connector.h"
 // FIXME: Including platform_canvas.h here is a layering violation.
 #include "skia/ext/platform_canvas.h"
+#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_image.h"
-#include "third_party/blink/public/platform/web_mock_clipboard.h"
 #include "third_party/blink/public/platform/web_point.h"
 #include "third_party/blink/public/web/web_frame.h"
 #include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_page_popup.h"
 #include "third_party/blink/public/web/web_print_params.h"
+#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/point.h"
 
 namespace test_runner {
 
 namespace {
 
+class BitmapDataPipeDrainer : public mojo::DataPipeDrainer::Client {
+ public:
+  BitmapDataPipeDrainer(mojo::ScopedDataPipeConsumerHandle handle,
+                        base::OnceCallback<void(const SkBitmap&)> callback)
+      : callback_(std::move(callback)), drainer_(this, std::move(handle)) {}
+
+  void OnDataAvailable(const void* data, size_t num_bytes) override {
+    const unsigned char* ptr = static_cast<const unsigned char*>(data);
+    data_.insert(data_.end(), ptr, ptr + num_bytes);
+  }
+
+  void OnDataComplete() override {
+    SkBitmap bitmap;
+    if (!gfx::PNGCodec::Decode(data_.data(), data_.size(), &bitmap))
+      bitmap.reset();
+    std::move(callback_).Run(bitmap);
+    delete this;
+  }
+
+ private:
+  base::OnceCallback<void(const SkBitmap&)> callback_;
+  mojo::DataPipeDrainer drainer_;
+  std::vector<unsigned char> data_;
+};
+
 class CaptureCallback : public base::RefCountedThreadSafe<CaptureCallback> {
  public:
   explicit CaptureCallback(base::OnceCallback<void(const SkBitmap&)> callback);
@@ -182,24 +210,30 @@
     int x,
     int y,
     base::OnceCallback<void(const SkBitmap&)> callback) {
-  DCHECK(!callback.is_null());
-  uint64_t sequence_number =
-      blink::Platform::Current()->Clipboard()->SequenceNumber(
-          blink::mojom::ClipboardBuffer::kStandard);
+  blink::mojom::ClipboardHostPtr clipboard;
+  blink::Platform::Current()->GetConnector()->BindInterface(
+      blink::Platform::Current()->GetBrowserServiceName(), &clipboard);
+
+  uint64_t sequence_number_before;
+  clipboard->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE,
+                               &sequence_number_before);
   web_frame->CopyImageAt(blink::WebPoint(x, y));
-  if (sequence_number ==
-      blink::Platform::Current()->Clipboard()->SequenceNumber(
-          blink::mojom::ClipboardBuffer::kStandard)) {
-    SkBitmap emptyBitmap;
-    std::move(callback).Run(emptyBitmap);
+  uint64_t sequence_number_after;
+  clipboard->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE,
+                               &sequence_number_after);
+  if (sequence_number_before == sequence_number_after) {
+    std::move(callback).Run(SkBitmap());
     return;
   }
 
-  blink::WebImage image =
-      static_cast<blink::WebMockClipboard*>(
-          blink::Platform::Current()->Clipboard())
-          ->ReadRawImage(blink::mojom::ClipboardBuffer::kStandard);
-  std::move(callback).Run(image.GetSkBitmap());
+  blink::mojom::SerializedBlobPtr serialized_blob;
+  clipboard->ReadImage(ui::CLIPBOARD_TYPE_COPY_PASTE, &serialized_blob);
+  blink::mojom::BlobPtr blob(std::move(serialized_blob->blob));
+  mojo::DataPipe pipe;
+  blob->ReadAll(std::move(pipe.producer_handle), nullptr);
+  // Self-destructs after draining the pipe.
+  new BitmapDataPipeDrainer(std::move(pipe.consumer_handle),
+                            std::move(callback));
 }
 
 }  // namespace test_runner
diff --git a/content/shell/test_runner/test_runner_for_specific_view.cc b/content/shell/test_runner/test_runner_for_specific_view.cc
index cef9fa3..e2a3608 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.cc
+++ b/content/shell/test_runner/test_runner_for_specific_view.cc
@@ -283,13 +283,6 @@
     v8::Local<v8::Function> callback) {
   v8::UniquePersistent<v8::Function> persistent_callback(
       blink::MainThreadIsolate(), callback);
-
-  // TODO(lukasza): Support image capture in OOPIFs for
-  // https://crbug.com/477150.
-  CHECK(web_view()->MainFrame()->IsWebLocalFrame())
-      << "Layout tests harness doesn't support calling "
-      << "testRunner.copyImageAtAndCapturePixelsAsyncThen from an OOPIF.";
-
   CopyImageAtAndCapturePixels(
       web_view()->MainFrame()->ToWebLocalFrame(), x, y,
       base::BindOnce(&TestRunnerForSpecificView::CapturePixelsCallback,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 6f7a854..597cbe3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -213,6 +213,8 @@
     "leveldb_wrapper_test_util.h",
     "mock_background_sync_controller.cc",
     "mock_background_sync_controller.h",
+    "mock_clipboard_host.cc",
+    "mock_clipboard_host.h",
     "mock_keyboard.cc",
     "mock_keyboard.h",
     "mock_keyboard_driver_win.cc",
@@ -228,8 +230,6 @@
     "mock_ssl_host_state_delegate.h",
     "mock_webblob_registry_impl.cc",
     "mock_webblob_registry_impl.h",
-    "mock_webclipboard_impl.cc",
-    "mock_webclipboard_impl.h",
     "mock_widget_impl.cc",
     "mock_widget_impl.h",
     "mock_widget_input_handler.cc",
@@ -1955,7 +1955,6 @@
       "../browser/android/java/java_type_unittest.cc",
       "../browser/android/overscroll_controller_android_unittest.cc",
       "../browser/android/scoped_surface_request_manager_unittest.cc",
-      "../browser/android/string_message_codec_unittest.cc",
       "../browser/android/url_request_content_job_unittest.cc",
       "../browser/media/capture/screen_capture_device_android_unittest.cc",
       "../renderer/java/gin_java_bridge_value_converter_unittest.cc",
diff --git a/content/test/data/gpu/pixel_webgl_sad_canvas.html b/content/test/data/gpu/pixel_webgl_sad_canvas.html
index 5c714d4..5abcdfcd 100644
--- a/content/test/data/gpu/pixel_webgl_sad_canvas.html
+++ b/content/test/data/gpu/pixel_webgl_sad_canvas.html
@@ -39,6 +39,8 @@
 
   gl.clearColor(1.0, 0.0, 0.0, 1.0);
   gl.clear(gl.COLOR_BUFFER_BIT);
+
+  // Sending READY will make the GPU crash.
   sendResult("READY");
 }
 
diff --git a/content/test/data/gpu/pixel_worker_requestAnimationFrame.html b/content/test/data/gpu/pixel_worker_requestAnimationFrame.html
new file mode 100644
index 0000000..429174c
--- /dev/null
+++ b/content/test/data/gpu/pixel_worker_requestAnimationFrame.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<title>Worker requestAnimationFrame after GPU crash</title>
+<style type="text/css">
+.nomargin {
+  margin: 0px auto;
+}
+</style>
+<script id="worker" type="text/worker">
+// This test kills the GPU process, which takes some time to recover,
+// so give it a few seconds before proceeding.
+var numFramesBeforeEnd = 200;
+
+function frame() {
+  if (--numFramesBeforeEnd == 0) {
+    postMessage("DONE");
+  } else {
+    requestAnimationFrame(frame);
+  }
+}
+frame();
+postMessage("READY");
+</script>
+<script>
+var numFramesBeforeFail = 500;
+
+function sendResult(status, detail) {
+  console.log(detail);
+  if (window.domAutomationController) {
+    window.domAutomationController.send(status);
+  } else {
+    console.log(status);
+  }
+}
+
+function main() {
+  var blob = new Blob([document.getElementById('worker').textContent]);
+  var worker = new Worker(URL.createObjectURL(blob));
+  var done = false;
+
+  worker.addEventListener("message", (ev) => {
+    if (ev.data == "READY") {
+      // Sending READY will make the GPU crash.
+      sendResult("READY");
+      frame();
+    } else {
+      sendResult("SUCCESS", "Test complete");
+      done = true;
+    }
+  });
+
+  function frame() {
+    if (done) return;
+    if (--numFramesBeforeFail == 0) {
+      sendResult("FAILURE", "Worker.requestAnimationFrame didn't recover");
+    } else {
+      requestAnimationFrame(frame);
+    }
+  }
+}
+</script>
+</head>
+<body onload="main()">
+<canvas id="c" width="300" height="300" class="nomargin" style="position:absolute; top:0px; left:0px;"></canvas>
+</div>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index f4e82ad..a88499d3 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -101,3 +101,6 @@
     self.Flaky('Pixel_WebGLSadCanvas', ['mac'], bug=575305)
     self.Flaky('Pixel_WebGLSadCanvas', ['win', 'intel'], bug=575305)
     self.Fail('Pixel_WebGLSadCanvas', ['android', 'nvidia'], bug=575305)
+
+    # TODO(fserb): temporary suppression for new test.
+    self.Fail('Pixel_WorkerRAF_OOPD', bug=833902)
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index e83c6fa..8de3698 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -395,6 +395,9 @@
   unaccelerated_args = [
     '--disable-accelerated-2d-canvas',
     '--disable-gpu-compositing']
+  browser_args_oopd = [
+    '--enable-viz-display-compositor',
+    '--enable-experimental-web-platform-features']
 
   return [
     PixelTestPage(
@@ -412,6 +415,14 @@
       browser_args=browser_args),
 
     PixelTestPage(
+      'pixel_worker_requestAnimationFrame.html',
+      base_name + '_WorkerRAF_OOPD',
+      test_rect=[0, 0, 1, 1],
+      revision=1,
+      optional_action='CrashGpuProcess',
+      browser_args=browser_args_oopd),
+
+    PixelTestPage(
       'pixel_offscreenCanvas_transferToImageBitmap_main.html',
       base_name + '_OffscreenCanvasTransferToImageBitmap',
       test_rect=[0, 0, 300, 300],
@@ -599,8 +610,7 @@
 # arguments.
 def MacSpecificPages(base_name):
   iosurface_2d_canvas_args = [
-    '--enable-accelerated-2d-canvas',
-    '--disable-display-list-2d-canvas']
+    '--enable-accelerated-2d-canvas']
 
   non_chromium_image_args = ['--disable-webgl-image-chromium']
 
diff --git a/content/test/mock_clipboard_host.cc b/content/test/mock_clipboard_host.cc
new file mode 100644
index 0000000..23a088e
--- /dev/null
+++ b/content/test/mock_clipboard_host.cc
@@ -0,0 +1,225 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/test/mock_clipboard_host.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/blob_handle.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace content {
+
+namespace {
+
+void ReleaseSharedMemoryPixels(void* addr, void* context) {
+  MojoResult result = MojoUnmapBuffer(context);
+  DCHECK_EQ(MOJO_RESULT_OK, result);
+}
+
+blink::mojom::SerializedBlobPtr ConstructSerializedBlobOnIO(
+    size_t data_size,
+    std::unique_ptr<BlobHandle> blob_handle) {
+  blink::mojom::SerializedBlobPtr blob;
+  if (blob_handle) {
+    blob = blink::mojom::SerializedBlob::New(
+        blob_handle->GetUUID(), "image/png", static_cast<int64_t>(data_size),
+        blob_handle->PassBlob().PassInterface());
+  }
+  return blob;
+}
+
+void ReplyToReadImage(blink::mojom::ClipboardHost::ReadImageCallback callback,
+                      size_t data_size,
+                      std::vector<unsigned char> owner_buffer,
+                      std::unique_ptr<BlobHandle> blob_handle) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Unfortunately, we cannot call blob_handle->PassBlob() on UI,
+  // since that binds a blob ptr which only works on IO. If we do,
+  // future access to that blob will be handled by Mojo on the wrong
+  // thread.
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&ConstructSerializedBlobOnIO, data_size,
+                     std::move(blob_handle)),
+      std::move(callback));
+}
+
+}  // namespace
+
+MockClipboardHost::MockClipboardHost(BrowserContext* browser_context)
+    : browser_context_(browser_context) {}
+
+MockClipboardHost::~MockClipboardHost() {}
+
+void MockClipboardHost::Bind(blink::mojom::ClipboardHostRequest request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+
+void MockClipboardHost::Reset() {
+  plain_text_ = base::string16();
+  html_text_ = base::string16();
+  url_ = GURL();
+  image_.reset();
+  custom_data_.clear();
+  write_smart_paste_ = false;
+  needs_reset_ = false;
+}
+
+void MockClipboardHost::GetSequenceNumber(ui::ClipboardType clipboard_type,
+                                          GetSequenceNumberCallback callback) {
+  std::move(callback).Run(sequence_number_);
+}
+
+void MockClipboardHost::ReadAvailableTypes(
+    ui::ClipboardType clipboard_type,
+    ReadAvailableTypesCallback callback) {
+  std::vector<base::string16> types;
+  if (!plain_text_.empty())
+    types.push_back(base::UTF8ToUTF16("text/plain"));
+  if (!html_text_.empty())
+    types.push_back(base::UTF8ToUTF16("text/html"));
+  if (!image_.isNull())
+    types.push_back(base::UTF8ToUTF16("image/png"));
+  for (auto& it : custom_data_) {
+    CHECK(std::find(types.begin(), types.end(), it.first) == types.end());
+    types.push_back(it.first);
+  }
+  std::move(callback).Run(types, false);
+}
+
+void MockClipboardHost::IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                                          ui::ClipboardType clipboard_type,
+                                          IsFormatAvailableCallback callback) {
+  bool result = false;
+  switch (format) {
+    case blink::mojom::ClipboardFormat::kPlaintext:
+      result = !plain_text_.empty();
+      break;
+    case blink::mojom::ClipboardFormat::kHtml:
+      result = !html_text_.empty();
+      break;
+    case blink::mojom::ClipboardFormat::kSmartPaste:
+      result = write_smart_paste_;
+      break;
+    case blink::mojom::ClipboardFormat::kBookmark:
+      result = false;
+      break;
+  }
+  std::move(callback).Run(result);
+}
+
+void MockClipboardHost::ReadText(ui::ClipboardType clipboard_type,
+                                 ReadTextCallback callback) {
+  std::move(callback).Run(plain_text_);
+}
+
+void MockClipboardHost::ReadHtml(ui::ClipboardType clipboard_type,
+                                 ReadHtmlCallback callback) {
+  std::move(callback).Run(html_text_, url_, 0, html_text_.length());
+}
+
+void MockClipboardHost::ReadRtf(ui::ClipboardType clipboard_type,
+                                ReadRtfCallback callback) {
+  std::move(callback).Run(std::string());
+}
+
+void MockClipboardHost::ReadImage(ui::ClipboardType clipboard_type,
+                                  ReadImageCallback callback) {
+  if (image_.isNull() || !browser_context_) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+  std::vector<unsigned char> png_data;
+  if (!gfx::PNGCodec::FastEncodeBGRASkBitmap(image_, false, &png_data)) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+  if (png_data.size() >= std::numeric_limits<uint32_t>::max()) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+
+  char* char_data = reinterpret_cast<char*>(png_data.data());
+  size_t size = png_data.size();
+  // We pass png_data to retain encoded data until CreateMemoryBackedBlob
+  // takes a copy of it.
+  BrowserContext::CreateMemoryBackedBlob(
+      browser_context_, char_data, size, "",
+      base::BindOnce(&ReplyToReadImage, std::move(callback), size,
+                     std::move(png_data)));
+}
+
+void MockClipboardHost::ReadCustomData(ui::ClipboardType clipboard_type,
+                                       const base::string16& type,
+                                       ReadCustomDataCallback callback) {
+  auto it = custom_data_.find(type);
+  std::move(callback).Run(it != custom_data_.end() ? it->second
+                                                   : base::string16());
+}
+
+void MockClipboardHost::WriteText(ui::ClipboardType,
+                                  const base::string16& text) {
+  if (needs_reset_)
+    Reset();
+  plain_text_ = text;
+}
+
+void MockClipboardHost::WriteHtml(ui::ClipboardType,
+                                  const base::string16& markup,
+                                  const GURL& url) {
+  if (needs_reset_)
+    Reset();
+  html_text_ = markup;
+  url_ = url;
+}
+
+void MockClipboardHost::WriteSmartPasteMarker(ui::ClipboardType) {
+  if (needs_reset_)
+    Reset();
+  write_smart_paste_ = true;
+}
+
+void MockClipboardHost::WriteCustomData(
+    ui::ClipboardType,
+    const base::flat_map<base::string16, base::string16>& data) {
+  if (needs_reset_)
+    Reset();
+  for (auto& it : data)
+    custom_data_[it.first] = it.second;
+}
+
+void MockClipboardHost::WriteBookmark(ui::ClipboardType,
+                                      const std::string& url,
+                                      const base::string16& title) {}
+
+void MockClipboardHost::WriteImage(
+    ui::ClipboardType,
+    const gfx::Size& size,
+    mojo::ScopedSharedBufferHandle shared_buffer_handle) {
+  if (needs_reset_)
+    Reset();
+  if (!image_.setInfo(SkImageInfo::MakeN32Premul(size.width(), size.height())))
+    return;
+  auto mapped = shared_buffer_handle->Map(image_.computeByteSize());
+  if (!mapped)
+    return;
+  if (!image_.installPixels(image_.info(), mapped.get(), image_.rowBytes(),
+                            &ReleaseSharedMemoryPixels, mapped.get())) {
+    return;
+  }
+  mapped.release();
+}
+
+void MockClipboardHost::CommitWrite(ui::ClipboardType) {
+  ++sequence_number_;
+  needs_reset_ = true;
+}
+
+#if defined(OS_MACOSX)
+void MockClipboardHost::WriteStringToFindPboard(const base::string16& text) {}
+#endif
+
+}  // namespace content
diff --git a/content/test/mock_clipboard_host.h b/content/test/mock_clipboard_host.h
new file mode 100644
index 0000000..9d300df
--- /dev/null
+++ b/content/test/mock_clipboard_host.h
@@ -0,0 +1,85 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_TEST_MOCK_CLIPBOARD_HOST_H_
+#define CONTENT_TEST_MOCK_CLIPBOARD_HOST_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace content {
+
+class BrowserContext;
+
+class MockClipboardHost : public blink::mojom::ClipboardHost {
+ public:
+  // |browser_context| could be null, in which case reading images
+  // is not supported.
+  explicit MockClipboardHost(BrowserContext* browser_context);
+  ~MockClipboardHost() override;
+
+  void Bind(blink::mojom::ClipboardHostRequest request);
+  void Reset();
+
+ private:
+  // blink::mojom::ClipboardHost
+  void GetSequenceNumber(ui::ClipboardType clipboard_type,
+                         GetSequenceNumberCallback callback) override;
+  void IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                         ui::ClipboardType clipboard_type,
+                         IsFormatAvailableCallback callback) override;
+  void ReadAvailableTypes(ui::ClipboardType clipboard_type,
+                          ReadAvailableTypesCallback callback) override;
+  void ReadText(ui::ClipboardType clipboard_type,
+                ReadTextCallback callback) override;
+  void ReadHtml(ui::ClipboardType clipboard_type,
+                ReadHtmlCallback callback) override;
+  void ReadRtf(ui::ClipboardType clipboard_type,
+               ReadRtfCallback callback) override;
+  void ReadImage(ui::ClipboardType clipboard_type,
+                 ReadImageCallback callback) override;
+  void ReadCustomData(ui::ClipboardType clipboard_type,
+                      const base::string16& type,
+                      ReadCustomDataCallback callback) override;
+  void WriteText(ui::ClipboardType clipboard_type,
+                 const base::string16& text) override;
+  void WriteHtml(ui::ClipboardType clipboard_type,
+                 const base::string16& markup,
+                 const GURL& url) override;
+  void WriteSmartPasteMarker(ui::ClipboardType clipboard_type) override;
+  void WriteCustomData(
+      ui::ClipboardType clipboard_type,
+      const base::flat_map<base::string16, base::string16>& data) override;
+  void WriteBookmark(ui::ClipboardType clipboard_type,
+                     const std::string& url,
+                     const base::string16& title) override;
+  void WriteImage(ui::ClipboardType clipboard_type,
+                  const gfx::Size& size_in_pixels,
+                  mojo::ScopedSharedBufferHandle shared_buffer_handle) override;
+  void CommitWrite(ui::ClipboardType clipboard_type) override;
+#if defined(OS_MACOSX)
+  void WriteStringToFindPboard(const base::string16& text) override;
+#endif
+
+  BrowserContext* browser_context_;
+  mojo::BindingSet<blink::mojom::ClipboardHost> bindings_;
+  uint64_t sequence_number_ = 0;
+  base::string16 plain_text_;
+  base::string16 html_text_;
+  GURL url_;
+  SkBitmap image_;
+  std::map<base::string16, base::string16> custom_data_;
+  bool write_smart_paste_ = false;
+  bool needs_reset_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(MockClipboardHost);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_TEST_MOCK_CLIPBOARD_HOST_H_
diff --git a/content/test/mock_webclipboard_impl.cc b/content/test/mock_webclipboard_impl.cc
deleted file mode 100644
index d38b97d..0000000
--- a/content/test/mock_webclipboard_impl.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-// 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.
-
-#include "content/test/mock_webclipboard_impl.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-
-#include "base/guid.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "content/renderer/clipboard_utils.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_drag_data.h"
-#include "third_party/blink/public/platform/web_image.h"
-#include "third_party/blink/public/platform/web_thread_safe_data.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/geometry/size.h"
-
-using blink::WebDragData;
-using blink::WebString;
-using blink::WebURL;
-using blink::WebVector;
-
-namespace content {
-
-MockWebClipboardImpl::MockWebClipboardImpl()
-  : m_sequenceNumber(0),
-    m_writeSmartPaste(false) {}
-
-MockWebClipboardImpl::~MockWebClipboardImpl() {}
-
-uint64_t MockWebClipboardImpl::SequenceNumber(blink::mojom::ClipboardBuffer) {
-  return m_sequenceNumber;
-}
-
-bool MockWebClipboardImpl::IsFormatAvailable(
-    blink::mojom::ClipboardFormat format,
-    blink::mojom::ClipboardBuffer buffer) {
-  switch (format) {
-    case blink::mojom::ClipboardFormat::kPlaintext:
-      return !m_plainText.is_null();
-
-    case blink::mojom::ClipboardFormat::kHtml:
-      return !m_htmlText.is_null();
-
-    case blink::mojom::ClipboardFormat::kSmartPaste:
-      return m_writeSmartPaste;
-
-    case blink::mojom::ClipboardFormat::kBookmark:
-      return false;
-  }
-  return false;
-}
-
-WebVector<WebString> MockWebClipboardImpl::ReadAvailableTypes(
-    blink::mojom::ClipboardBuffer buffer,
-    bool* containsFilenames) {
-  *containsFilenames = false;
-  std::vector<WebString> results;
-  if (!m_plainText.string().empty()) {
-    results.push_back(WebString("text/plain"));
-  }
-  if (!m_htmlText.string().empty()) {
-    results.push_back(WebString("text/html"));
-  }
-  if (!m_image.IsNull()) {
-    results.push_back(WebString("image/png"));
-  }
-  for (std::map<base::string16, base::string16>::const_iterator it =
-           m_customData.begin();
-       it != m_customData.end(); ++it) {
-    CHECK(std::find(results.begin(), results.end(),
-                    WebString::FromUTF16(it->first)) == results.end());
-    results.push_back(WebString::FromUTF16(it->first));
-  }
-  return results;
-}
-
-blink::WebString MockWebClipboardImpl::ReadPlainText(
-    blink::mojom::ClipboardBuffer buffer) {
-  return WebString::FromUTF16(m_plainText);
-}
-
-// TODO(wtc): set output argument *url.
-blink::WebString MockWebClipboardImpl::ReadHTML(
-    blink::mojom::ClipboardBuffer buffer,
-    blink::WebURL* url,
-    unsigned* fragmentStart,
-    unsigned* fragmentEnd) {
-  *fragmentStart = 0;
-  *fragmentEnd = static_cast<unsigned>(m_htmlText.string().length());
-  return WebString::FromUTF16(m_htmlText);
-}
-
-blink::WebBlobInfo MockWebClipboardImpl::ReadImage(
-    blink::mojom::ClipboardBuffer buffer) {
-  std::vector<unsigned char> output;
-  const SkBitmap& bitmap = m_image.GetSkBitmap();
-  if (!gfx::PNGCodec::FastEncodeBGRASkBitmap(
-          bitmap, false /* discard_transparency */, &output)) {
-    return blink::WebBlobInfo();
-  }
-  return CreateBlobFromData(output,
-                            WebString::FromASCII(ui::Clipboard::kMimeTypePNG));
-}
-
-blink::WebImage MockWebClipboardImpl::ReadRawImage(
-    blink::mojom::ClipboardBuffer buffer) {
-  return m_image;
-}
-
-blink::WebString MockWebClipboardImpl::ReadCustomData(
-    blink::mojom::ClipboardBuffer buffer,
-    const blink::WebString& type) {
-  std::map<base::string16, base::string16>::const_iterator it =
-      m_customData.find(type.Utf16());
-  if (it != m_customData.end())
-    return WebString::FromUTF16(it->second);
-  return blink::WebString();
-}
-
-void MockWebClipboardImpl::WriteHTML(const blink::WebString& htmlText,
-                                     const blink::WebURL& url,
-                                     const blink::WebString& plainText,
-                                     bool writeSmartPaste) {
-  clear();
-
-  m_htmlText = WebString::ToNullableString16(htmlText);
-  m_plainText = WebString::ToNullableString16(plainText);
-  m_writeSmartPaste = writeSmartPaste;
-  ++m_sequenceNumber;
-}
-
-void MockWebClipboardImpl::WritePlainText(const blink::WebString& plain_text) {
-  clear();
-
-  m_plainText = WebString::ToNullableString16(plain_text);
-  ++m_sequenceNumber;
-}
-
-void MockWebClipboardImpl::WriteImage(const blink::WebImage& image,
-                                      const blink::WebURL& url,
-                                      const blink::WebString& title) {
-  if (!image.IsNull()) {
-    clear();
-
-    m_plainText = m_htmlText;
-    m_htmlText = base::NullableString16(
-        base::UTF8ToUTF16(URLToImageMarkup(url, title)), false /* is_null */);
-    m_image = image;
-    ++m_sequenceNumber;
-  }
-}
-
-void MockWebClipboardImpl::WriteDataObject(const WebDragData& data) {
-  clear();
-
-  const WebVector<WebDragData::Item>& itemList = data.Items();
-  for (size_t i = 0; i < itemList.size(); ++i) {
-    const WebDragData::Item& item = itemList[i];
-    switch (item.storage_type) {
-      case WebDragData::Item::kStorageTypeString: {
-        ++m_sequenceNumber;
-        base::string16 type(item.string_type.Utf16());
-        if (base::EqualsASCII(type, ui::Clipboard::kMimeTypeText)) {
-          m_plainText = WebString::ToNullableString16(item.string_data);
-          continue;
-        }
-        if (base::EqualsASCII(type, ui::Clipboard::kMimeTypeHTML)) {
-          m_htmlText = WebString::ToNullableString16(item.string_data);
-          continue;
-        }
-        m_customData.insert(std::make_pair(type, item.string_data.Utf16()));
-        continue;
-      }
-      default:
-        // Currently other types are unused by the clipboard implementation.
-        NOTREACHED();
-    }
-  }
-}
-
-void MockWebClipboardImpl::clear() {
-  m_plainText = base::NullableString16();
-  m_htmlText = base::NullableString16();
-  m_image.Reset();
-  m_customData.clear();
-  m_writeSmartPaste = false;
-}
-
-}  // namespace content
diff --git a/content/test/mock_webclipboard_impl.h b/content/test/mock_webclipboard_impl.h
deleted file mode 100644
index 7974248..0000000
--- a/content/test/mock_webclipboard_impl.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-//
-// This file mocks out just enough of the WebClipboard API for running the
-// webkit tests. This is so we can run webkit tests without them sharing a
-// clipboard, which allows for running them in parallel and having the tests
-// not interact with actual user actions.
-
-#ifndef CONTENT_TEST_MOCK_WEBCLIPBOARD_IMPL_H_
-#define CONTENT_TEST_MOCK_WEBCLIPBOARD_IMPL_H_
-
-#include <stdint.h>
-
-#include <map>
-
-#include "base/strings/nullable_string16.h"
-#include "base/strings/string16.h"
-#include "third_party/blink/public/platform/web_drag_data.h"
-#include "third_party/blink/public/platform/web_image.h"
-#include "third_party/blink/public/platform/web_mock_clipboard.h"
-
-namespace content {
-
-class MockWebClipboardImpl : public blink::WebMockClipboard {
- public:
-  MockWebClipboardImpl();
-  virtual ~MockWebClipboardImpl();
-
-  uint64_t SequenceNumber(blink::mojom::ClipboardBuffer) override;
-  bool IsFormatAvailable(blink::mojom::ClipboardFormat format,
-                         blink::mojom::ClipboardBuffer buffer) override;
-  blink::WebVector<blink::WebString> ReadAvailableTypes(
-      blink::mojom::ClipboardBuffer buffer,
-      bool* containsFilenames) override;
-
-  blink::WebString ReadPlainText(blink::mojom::ClipboardBuffer buffer) override;
-  blink::WebString ReadHTML(blink::mojom::ClipboardBuffer buffer,
-                            blink::WebURL* url,
-                            unsigned* fragmentStart,
-                            unsigned* fragmentEnd) override;
-  blink::WebBlobInfo ReadImage(blink::mojom::ClipboardBuffer buffer) override;
-  blink::WebImage ReadRawImage(blink::mojom::ClipboardBuffer buffer) override;
-  blink::WebString ReadCustomData(blink::mojom::ClipboardBuffer buffer,
-                                  const blink::WebString& type) override;
-
-  void WritePlainText(const blink::WebString& plain_text) override;
-  void WriteHTML(const blink::WebString& htmlText,
-                 const blink::WebURL& url,
-                 const blink::WebString& plainText,
-                 bool writeSmartPaste) override;
-  void WriteImage(const blink::WebImage& image,
-                  const blink::WebURL& url,
-                  const blink::WebString& title) override;
-  void WriteDataObject(const blink::WebDragData& data) override;
-
- private:
-  void clear();
-
-  uint64_t m_sequenceNumber;
-  base::NullableString16 m_plainText;
-  base::NullableString16 m_htmlText;
-  blink::WebImage m_image;
-  std::map<base::string16, base::string16> m_customData;
-  bool m_writeSmartPaste;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_TEST_MOCK_WEBCLIPBOARD_IMPL_H_
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index a681ff9..6ed97e9 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -18,14 +18,16 @@
 #include "cc/blink/web_layer_impl.h"
 #include "cc/trees/layer_tree_settings.h"
 #include "content/app/mojo/mojo_init.h"
+#include "content/public/common/service_names.mojom.h"
 #include "content/renderer/loader/web_data_consumer_handle_impl.h"
 #include "content/renderer/loader/web_url_loader_impl.h"
-#include "content/test/mock_webclipboard_impl.h"
+#include "content/test/mock_clipboard_host.h"
 #include "content/test/web_gesture_curve_mock.h"
 #include "media/base/media.h"
 #include "media/media_buildflags.h"
 #include "net/cookies/cookie_monster.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/scheduler/web_main_thread_scheduler.h"
 #include "third_party/blink/public/platform/web_connection_type.h"
@@ -135,7 +137,9 @@
 #endif
 
   url_loader_factory_ = blink::WebURLLoaderMockFactory::Create();
-  mock_clipboard_.reset(new MockWebClipboardImpl());
+  // Mock out clipboard calls so that tests don't mess
+  // with each other's copies/pastes when running in parallel.
+  mock_clipboard_host_ = std::make_unique<MockClipboardHost>(nullptr);
 
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
   gin::V8Initializer::LoadV8Snapshot(kSnapshotType);
@@ -164,6 +168,15 @@
   // Initialize mojo firstly to enable Blink initialization to use it.
   InitializeMojo();
 
+  connector_ = std::make_unique<service_manager::Connector>(
+      service_manager::mojom::ConnectorPtrInfo());
+  service_manager::Connector::TestApi test_api(connector_.get());
+  test_api.OverrideBinderForTesting(
+      service_manager::Identity(mojom::kBrowserServiceName),
+      blink::mojom::ClipboardHost::Name_,
+      base::BindRepeating(&TestBlinkWebUnitTestSupport::BindClipboardHost,
+                          weak_factory_.GetWeakPtr()));
+
   service_manager::BinderRegistry empty_registry;
   blink::Initialize(this, &empty_registry);
   blink::SetLayoutTestMode(true);
@@ -192,7 +205,7 @@
 
 TestBlinkWebUnitTestSupport::~TestBlinkWebUnitTestSupport() {
   url_loader_factory_.reset();
-  mock_clipboard_.reset();
+  mock_clipboard_host_.reset();
   if (main_thread_scheduler_)
     main_thread_scheduler_->Shutdown();
 }
@@ -201,12 +214,6 @@
   return &blob_registry_;
 }
 
-blink::WebClipboard* TestBlinkWebUnitTestSupport::Clipboard() {
-  // Mock out clipboard calls so that tests don't mess
-  // with each other's copies/pastes when running in parallel.
-  return mock_clipboard_.get();
-}
-
 blink::WebIDBFactory* TestBlinkWebUnitTestSupport::IdbFactory() {
   NOTREACHED() <<
       "IndexedDB cannot be tested with in-process harnesses.";
@@ -361,4 +368,14 @@
 #endif
 }
 
+service_manager::Connector* TestBlinkWebUnitTestSupport::GetConnector() {
+  return connector_.get();
+}
+
+void TestBlinkWebUnitTestSupport::BindClipboardHost(
+    mojo::ScopedMessagePipeHandle handle) {
+  mock_clipboard_host_->Bind(
+      blink::mojom::ClipboardHostRequest(std::move(handle)));
+}
+
 }  // namespace content
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h
index 869f24d..1381f83 100644
--- a/content/test/test_blink_web_unit_test_support.h
+++ b/content/test/test_blink_web_unit_test_support.h
@@ -15,7 +15,6 @@
 #include "cc/blink/web_compositor_support_impl.h"
 #include "content/child/blink_platform_impl.h"
 #include "content/test/mock_webblob_registry_impl.h"
-#include "content/test/mock_webclipboard_impl.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 
 namespace blink {
@@ -26,6 +25,8 @@
 
 namespace content {
 
+class MockClipboardHost;
+
 // An implementation of BlinkPlatformImpl for tests.
 class TestBlinkWebUnitTestSupport : public BlinkPlatformImpl {
  public:
@@ -33,7 +34,6 @@
   ~TestBlinkWebUnitTestSupport() override;
 
   blink::WebBlobRegistry* GetBlobRegistry() override;
-  blink::WebClipboard* Clipboard() override;
   blink::WebIDBFactory* IdbFactory() override;
 
   std::unique_ptr<blink::WebURLLoaderFactory> CreateDefaultURLLoaderFactory()
@@ -69,9 +69,14 @@
   std::unique_ptr<blink::WebRTCCertificateGenerator>
   CreateRTCCertificateGenerator() override;
 
+  service_manager::Connector* GetConnector() override;
+
  private:
+  void BindClipboardHost(mojo::ScopedMessagePipeHandle handle);
+
+  std::unique_ptr<service_manager::Connector> connector_;
   MockWebBlobRegistryImpl blob_registry_;
-  std::unique_ptr<MockWebClipboardImpl> mock_clipboard_;
+  std::unique_ptr<MockClipboardHost> mock_clipboard_host_;
   base::ScopedTempDir file_system_root_;
   std::unique_ptr<blink::WebURLLoaderMockFactory> url_loader_factory_;
   cc_blink::WebCompositorSupportImpl compositor_support_;
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 0e699bb..165c841 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -283,7 +283,7 @@
     ]
   }
 
-  if (enable_vr && is_android) {
+  if (enable_vr) {
     sources += [
       "vr/orientation/orientation_device_provider_unittest.cc",
       "vr/orientation/orientation_device_unittest.cc",
@@ -291,10 +291,15 @@
       "vr/vr_display_impl_unittest.cc",
     ]
 
+    if (is_android) {
+      deps += [ "//device/vr:java" ]
+    }
+
+    defines = [ "DEVICE_VR_IMPLEMENTATION" ]
+
     deps += [
       "//device/vr",
       "//device/vr:fakes",
-      "//device/vr:java",
       "//device/vr/public/mojom",
       "//services/device/public/cpp/generic_sensor",
       "//ui/display",
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 7b14c18..8d5ab6b 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -395,11 +395,6 @@
   GLES2_GET_FUN(UnlockDiscardableTextureCHROMIUM)
 #define glLockDiscardableTextureCHROMIUM \
   GLES2_GET_FUN(LockDiscardableTextureCHROMIUM)
-#define glBeginRasterCHROMIUM GLES2_GET_FUN(BeginRasterCHROMIUM)
-#define glMapRasterCHROMIUM GLES2_GET_FUN(MapRasterCHROMIUM)
-#define glMapFontBufferCHROMIUM GLES2_GET_FUN(MapFontBufferCHROMIUM)
-#define glUnmapRasterCHROMIUM GLES2_GET_FUN(UnmapRasterCHROMIUM)
-#define glEndRasterCHROMIUM GLES2_GET_FUN(EndRasterCHROMIUM)
 #define glTexStorage2DImageCHROMIUM GLES2_GET_FUN(TexStorage2DImageCHROMIUM)
 #define glSetColorSpaceMetadataCHROMIUM \
   GLES2_GET_FUN(SetColorSpaceMetadataCHROMIUM)
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index ee0b5058..4292ae2 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1770,29 +1770,6 @@
 bool GL_APIENTRY GLES2LockDiscardableTextureCHROMIUM(GLuint texture_id) {
   return gles2::GetGLContext()->LockDiscardableTextureCHROMIUM(texture_id);
 }
-void GL_APIENTRY
-GLES2BeginRasterCHROMIUM(GLuint texture_id,
-                         GLuint sk_color,
-                         GLuint msaa_sample_count,
-                         GLboolean can_use_lcd_text,
-                         GLint color_type,
-                         GLuint color_space_transfer_cache_id) {
-  gles2::GetGLContext()->BeginRasterCHROMIUM(
-      texture_id, sk_color, msaa_sample_count, can_use_lcd_text, color_type,
-      color_space_transfer_cache_id);
-}
-void* GL_APIENTRY GLES2MapRasterCHROMIUM(GLsizeiptr size) {
-  return gles2::GetGLContext()->MapRasterCHROMIUM(size);
-}
-void* GL_APIENTRY GLES2MapFontBufferCHROMIUM(GLsizeiptr size) {
-  return gles2::GetGLContext()->MapFontBufferCHROMIUM(size);
-}
-void GL_APIENTRY GLES2UnmapRasterCHROMIUM(GLsizeiptr written_size) {
-  gles2::GetGLContext()->UnmapRasterCHROMIUM(written_size);
-}
-void GL_APIENTRY GLES2EndRasterCHROMIUM() {
-  gles2::GetGLContext()->EndRasterCHROMIUM();
-}
 void GL_APIENTRY GLES2TexStorage2DImageCHROMIUM(GLenum target,
                                                 GLenum internalFormat,
                                                 GLenum bufferUsage,
@@ -3151,26 +3128,6 @@
             glLockDiscardableTextureCHROMIUM),
     },
     {
-        "glBeginRasterCHROMIUM",
-        reinterpret_cast<GLES2FunctionPointer>(glBeginRasterCHROMIUM),
-    },
-    {
-        "glMapRasterCHROMIUM",
-        reinterpret_cast<GLES2FunctionPointer>(glMapRasterCHROMIUM),
-    },
-    {
-        "glMapFontBufferCHROMIUM",
-        reinterpret_cast<GLES2FunctionPointer>(glMapFontBufferCHROMIUM),
-    },
-    {
-        "glUnmapRasterCHROMIUM",
-        reinterpret_cast<GLES2FunctionPointer>(glUnmapRasterCHROMIUM),
-    },
-    {
-        "glEndRasterCHROMIUM",
-        reinterpret_cast<GLES2FunctionPointer>(glEndRasterCHROMIUM),
-    },
-    {
         "glTexStorage2DImageCHROMIUM",
         reinterpret_cast<GLES2FunctionPointer>(glTexStorage2DImageCHROMIUM),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 40f741b..b2b1d52 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -3269,72 +3269,6 @@
   }
 }
 
-void BeginRasterCHROMIUM(GLuint texture_id,
-                         GLuint sk_color,
-                         GLuint msaa_sample_count,
-                         GLboolean can_use_lcd_text,
-                         GLint color_type,
-                         GLuint color_space_transfer_cache_id) {
-  gles2::cmds::BeginRasterCHROMIUM* c =
-      GetCmdSpace<gles2::cmds::BeginRasterCHROMIUM>();
-  if (c) {
-    c->Init(texture_id, sk_color, msaa_sample_count, can_use_lcd_text,
-            color_type, color_space_transfer_cache_id);
-  }
-}
-
-void RasterCHROMIUM(GLuint raster_shm_id,
-                    GLuint raster_shm_offset,
-                    GLsizeiptr raster_shm_size,
-                    GLuint font_shm_id,
-                    GLuint font_shm_offset,
-                    GLsizeiptr font_shm_size) {
-  gles2::cmds::RasterCHROMIUM* c = GetCmdSpace<gles2::cmds::RasterCHROMIUM>();
-  if (c) {
-    c->Init(raster_shm_id, raster_shm_offset, raster_shm_size, font_shm_id,
-            font_shm_offset, font_shm_size);
-  }
-}
-
-void EndRasterCHROMIUM() {
-  gles2::cmds::EndRasterCHROMIUM* c =
-      GetCmdSpace<gles2::cmds::EndRasterCHROMIUM>();
-  if (c) {
-    c->Init();
-  }
-}
-
-void CreateTransferCacheEntryINTERNAL(GLuint entry_type,
-                                      GLuint entry_id,
-                                      GLuint handle_shm_id,
-                                      GLuint handle_shm_offset,
-                                      GLuint data_shm_id,
-                                      GLuint data_shm_offset,
-                                      GLuint data_size) {
-  gles2::cmds::CreateTransferCacheEntryINTERNAL* c =
-      GetCmdSpace<gles2::cmds::CreateTransferCacheEntryINTERNAL>();
-  if (c) {
-    c->Init(entry_type, entry_id, handle_shm_id, handle_shm_offset, data_shm_id,
-            data_shm_offset, data_size);
-  }
-}
-
-void DeleteTransferCacheEntryINTERNAL(GLuint entry_type, GLuint entry_id) {
-  gles2::cmds::DeleteTransferCacheEntryINTERNAL* c =
-      GetCmdSpace<gles2::cmds::DeleteTransferCacheEntryINTERNAL>();
-  if (c) {
-    c->Init(entry_type, entry_id);
-  }
-}
-
-void UnlockTransferCacheEntryINTERNAL(GLuint entry_type, GLuint entry_id) {
-  gles2::cmds::UnlockTransferCacheEntryINTERNAL* c =
-      GetCmdSpace<gles2::cmds::UnlockTransferCacheEntryINTERNAL>();
-  if (c) {
-    c->Init(entry_type, entry_id);
-  }
-}
-
 void TexStorage2DImageCHROMIUM(GLenum target,
                                GLenum internalFormat,
                                GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index ed59f135e..4616347 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -5949,6 +5949,36 @@
   return manager->TextureIsDeletedForTracing(texture_id);
 }
 
+void* GLES2Implementation::MapTransferCacheEntry(size_t serialized_size) {
+  NOTREACHED();
+  return nullptr;
+}
+
+void GLES2Implementation::UnmapAndCreateTransferCacheEntry(uint32_t type,
+                                                           uint32_t id) {
+  NOTREACHED();
+}
+
+bool GLES2Implementation::ThreadsafeLockTransferCacheEntry(uint32_t type,
+                                                           uint32_t id) {
+  NOTREACHED();
+  return false;
+}
+
+void GLES2Implementation::UnlockTransferCacheEntries(
+    const std::vector<std::pair<uint32_t, uint32_t>>& entries) {
+  NOTREACHED();
+}
+
+void GLES2Implementation::DeleteTransferCacheEntry(uint32_t type, uint32_t id) {
+  NOTREACHED();
+}
+
+unsigned int GLES2Implementation::GetTransferBufferFreeSize() const {
+  NOTREACHED();
+  return 0;
+}
+
 void GLES2Implementation::GenSyncTokenCHROMIUM(GLbyte* sync_token) {
   if (!sync_token) {
     SetGLError(GL_INVALID_VALUE, "glGenSyncTokenCHROMIUM", "empty sync_token");
@@ -6482,7 +6512,7 @@
     coords_shm_offset = buffer.offset();
   }
 
-  DCHECK(num_commands > 0);
+  DCHECK_GT(num_commands, 0);
   unsigned char* commands_addr =
       static_cast<unsigned char*>(buffer.address()) + coords_size;
   memcpy(commands_addr, commands, num_commands);
@@ -6556,7 +6586,7 @@
   }
 
   // The multiplication below will not overflow.
-  DCHECK(transforms_component_count <= 12);
+  DCHECK_LE(transforms_component_count, 12U);
   uint32_t one_transform_size = sizeof(GLfloat) * transforms_component_count;
 
   uint32_t transforms_size;
@@ -6590,7 +6620,7 @@
     *out_transforms_offset = 0;
   }
 
-  DCHECK(paths_size > 0);
+  DCHECK_GT(paths_size, 0U);
   unsigned char* paths_addr =
       static_cast<unsigned char*>(buffer->address()) + transforms_size;
   memcpy(paths_addr, paths, paths_size);
@@ -6859,7 +6889,7 @@
       return;
     }
 
-    DCHECK(coeffs_size > 0);
+    DCHECK_GT(coeffs_size, 0U);
     unsigned char* addr = static_cast<unsigned char*>(buffer.address());
     memcpy(addr, coeffs, coeffs_size);
 
@@ -6953,83 +6983,6 @@
   CheckGLError();
 }
 
-void* GLES2Implementation::MapRasterCHROMIUM(GLsizeiptr size) {
-  if (size < 0) {
-    SetGLError(GL_INVALID_VALUE, "glMapRasterCHROMIUM", "negative size");
-    return nullptr;
-  }
-  if (raster_mapped_buffer_) {
-    SetGLError(GL_INVALID_OPERATION, "glMapRasterCHROMIUM", "already mapped");
-    return nullptr;
-  }
-  raster_mapped_buffer_.emplace(size, helper_, transfer_buffer_);
-  if (!raster_mapped_buffer_->valid()) {
-    SetGLError(GL_INVALID_OPERATION, "glMapRasterCHROMIUM", "size too big");
-    raster_mapped_buffer_ = base::nullopt;
-    return nullptr;
-  }
-  return raster_mapped_buffer_->address();
-}
-
-void* GLES2Implementation::MapFontBufferCHROMIUM(GLsizeiptr size) {
-  if (size < 0) {
-    SetGLError(GL_INVALID_VALUE, "glMapFontBufferCHROMIUM", "negative size");
-    return nullptr;
-  }
-  if (font_mapped_buffer_) {
-    SetGLError(GL_INVALID_OPERATION, "glMapFontBufferCHROMIUM",
-               "already mapped");
-    return nullptr;
-  }
-  if (!raster_mapped_buffer_) {
-    SetGLError(GL_INVALID_OPERATION, "glMapFontBufferCHROMIUM",
-               "mapped font buffer with no raster buffer");
-    return nullptr;
-  }
-
-  font_mapped_buffer_.emplace(size, helper_, mapped_memory_.get());
-  if (!font_mapped_buffer_->valid()) {
-    SetGLError(GL_INVALID_OPERATION, "glMapFontBufferCHROMIUM", "size too big");
-    font_mapped_buffer_ = base::nullopt;
-    return nullptr;
-  }
-  return font_mapped_buffer_->address();
-}
-
-void GLES2Implementation::UnmapRasterCHROMIUM(GLsizeiptr written_size) {
-  if (written_size < 0) {
-    SetGLError(GL_INVALID_VALUE, "glUnmapRasterCHROMIUM",
-               "negative written_size");
-    return;
-  }
-  if (!raster_mapped_buffer_) {
-    SetGLError(GL_INVALID_OPERATION, "glUnmapRasterCHROMIUM", "not mapped");
-    return;
-  }
-  DCHECK(raster_mapped_buffer_->valid());
-  if (written_size == 0) {
-    raster_mapped_buffer_->Discard();
-    raster_mapped_buffer_ = base::nullopt;
-    return;
-  }
-  raster_mapped_buffer_->Shrink(written_size);
-
-  GLuint font_shm_id = 0u;
-  GLuint font_shm_offset = 0u;
-  GLsizeiptr font_shm_size = 0u;
-  if (font_mapped_buffer_) {
-    font_shm_id = font_mapped_buffer_->shm_id();
-    font_shm_offset = font_mapped_buffer_->offset();
-    font_shm_size = font_mapped_buffer_->size();
-  }
-  helper_->RasterCHROMIUM(raster_mapped_buffer_->shm_id(),
-                          raster_mapped_buffer_->offset(), written_size,
-                          font_shm_id, font_shm_offset, font_shm_size);
-  raster_mapped_buffer_ = base::nullopt;
-  font_mapped_buffer_ = base::nullopt;
-  CheckGLError();
-}
-
 void GLES2Implementation::IssueBeginQuery(GLenum target,
                                           GLuint id,
                                           uint32_t sync_data_shm_id,
@@ -7076,29 +7029,6 @@
   return helper_;
 }
 
-void GLES2Implementation::IssueCreateTransferCacheEntry(
-    GLuint entry_type,
-    GLuint entry_id,
-    GLuint handle_shm_id,
-    GLuint handle_shm_offset,
-    GLuint data_shm_id,
-    GLuint data_shm_offset,
-    GLuint data_size) {
-  helper_->CreateTransferCacheEntryINTERNAL(entry_type, entry_id, handle_shm_id,
-                                            handle_shm_offset, data_shm_id,
-                                            data_shm_offset, data_size);
-}
-
-void GLES2Implementation::IssueDeleteTransferCacheEntry(GLuint entry_type,
-                                                        GLuint entry_id) {
-  helper_->DeleteTransferCacheEntryINTERNAL(entry_type, entry_id);
-}
-
-void GLES2Implementation::IssueUnlockTransferCacheEntry(GLuint entry_type,
-                                                        GLuint entry_id) {
-  helper_->UnlockTransferCacheEntryINTERNAL(entry_type, entry_id);
-}
-
 CommandBuffer* GLES2Implementation::command_buffer() const {
   return helper_->command_buffer();
 }
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index b3e8f1c..1cdbffa 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -128,7 +128,13 @@
       uint32_t texture_id) override;
   bool ThreadsafeDiscardableTextureIsDeletedForTracing(
       uint32_t texture_id) override;
-
+  void* MapTransferCacheEntry(size_t serialized_size) override;
+  void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override;
+  bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override;
+  void UnlockTransferCacheEntries(
+      const std::vector<std::pair<uint32_t, uint32_t>>& entries) override;
+  void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override;
+  unsigned int GetTransferBufferFreeSize() const override;
   void GetProgramInfoCHROMIUMHelper(GLuint program,
                                     std::vector<int8_t>* result);
   GLint GetAttribLocationHelper(GLuint program, const char* name);
@@ -196,19 +202,7 @@
                   const char* function_name,
                   const char* msg) override;
 
-  // ClientTransferCache::Client implementation.
-  void IssueCreateTransferCacheEntry(GLuint entry_type,
-                                     GLuint entry_id,
-                                     GLuint handle_shm_id,
-                                     GLuint handle_shm_offset,
-                                     GLuint data_shm_id,
-                                     GLuint data_shm_offset,
-                                     GLuint data_size) override;
-  void IssueDeleteTransferCacheEntry(GLuint entry_type,
-                                     GLuint entry_id) override;
-  void IssueUnlockTransferCacheEntry(GLuint entry_type,
-                                     GLuint entry_id) override;
-  CommandBuffer* command_buffer() const override;
+  CommandBuffer* command_buffer() const;
 
  private:
   friend class GLES2ImplementationTest;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 3ad0d1f..258b9c2 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1244,21 +1244,6 @@
 
 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override;
 
-void BeginRasterCHROMIUM(GLuint texture_id,
-                         GLuint sk_color,
-                         GLuint msaa_sample_count,
-                         GLboolean can_use_lcd_text,
-                         GLint color_type,
-                         GLuint color_space_transfer_cache_id) override;
-
-void* MapRasterCHROMIUM(GLsizeiptr size) override;
-
-void* MapFontBufferCHROMIUM(GLsizeiptr size) override;
-
-void UnmapRasterCHROMIUM(GLsizeiptr written_size) override;
-
-void EndRasterCHROMIUM() override;
-
 void TexStorage2DImageCHROMIUM(GLenum target,
                                GLenum internalFormat,
                                GLenum bufferUsage,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 64bc0f4..4a2358ee 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -3576,33 +3576,6 @@
   CheckGLError();
 }
 
-void GLES2Implementation::BeginRasterCHROMIUM(
-    GLuint texture_id,
-    GLuint sk_color,
-    GLuint msaa_sample_count,
-    GLboolean can_use_lcd_text,
-    GLint color_type,
-    GLuint color_space_transfer_cache_id) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG(
-      "[" << GetLogPrefix() << "] glBeginRasterCHROMIUM(" << texture_id << ", "
-          << sk_color << ", " << msaa_sample_count << ", "
-          << GLES2Util::GetStringBool(can_use_lcd_text) << ", " << color_type
-          << ", " << color_space_transfer_cache_id << ")");
-  helper_->BeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
-                               can_use_lcd_text, color_type,
-                               color_space_transfer_cache_id);
-  CheckGLError();
-}
-
-void GLES2Implementation::EndRasterCHROMIUM() {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEndRasterCHROMIUM("
-                     << ")");
-  helper_->EndRasterCHROMIUM();
-  CheckGLError();
-}
-
 void GLES2Implementation::TexStorage2DImageCHROMIUM(GLenum target,
                                                     GLenum internalFormat,
                                                     GLenum bufferUsage,
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index f73cba23..a00aeb5 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -3082,28 +3082,6 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
-TEST_F(GLES2ImplementationTest, BeginRasterCHROMIUM) {
-  struct Cmds {
-    cmds::BeginRasterCHROMIUM cmd;
-  };
-  Cmds expected;
-  expected.cmd.Init(1, 2, 3, true, 5, 6);
-
-  gl_->BeginRasterCHROMIUM(1, 2, 3, true, 5, 6);
-  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
-}
-
-TEST_F(GLES2ImplementationTest, EndRasterCHROMIUM) {
-  struct Cmds {
-    cmds::EndRasterCHROMIUM cmd;
-  };
-  Cmds expected;
-  expected.cmd.Init();
-
-  gl_->EndRasterCHROMIUM();
-  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
-}
-
 TEST_F(GLES2ImplementationTest, TexStorage2DImageCHROMIUM) {
   struct Cmds {
     cmds::TexStorage2DImageCHROMIUM cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 96cdec5..8ae17d8 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -925,16 +925,6 @@
 virtual void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) = 0;
 virtual void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) = 0;
 virtual bool LockDiscardableTextureCHROMIUM(GLuint texture_id) = 0;
-virtual void BeginRasterCHROMIUM(GLuint texture_id,
-                                 GLuint sk_color,
-                                 GLuint msaa_sample_count,
-                                 GLboolean can_use_lcd_text,
-                                 GLint color_type,
-                                 GLuint color_space_transfer_cache_id) = 0;
-virtual void* MapRasterCHROMIUM(GLsizeiptr size) = 0;
-virtual void* MapFontBufferCHROMIUM(GLsizeiptr size) = 0;
-virtual void UnmapRasterCHROMIUM(GLsizeiptr written_size) = 0;
-virtual void EndRasterCHROMIUM() = 0;
 virtual void TexStorage2DImageCHROMIUM(GLenum target,
                                        GLenum internalFormat,
                                        GLenum bufferUsage,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index e8887813..9b7ab78 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -898,16 +898,6 @@
 void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override;
 void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override;
 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override;
-void BeginRasterCHROMIUM(GLuint texture_id,
-                         GLuint sk_color,
-                         GLuint msaa_sample_count,
-                         GLboolean can_use_lcd_text,
-                         GLint color_type,
-                         GLuint color_space_transfer_cache_id) override;
-void* MapRasterCHROMIUM(GLsizeiptr size) override;
-void* MapFontBufferCHROMIUM(GLsizeiptr size) override;
-void UnmapRasterCHROMIUM(GLsizeiptr written_size) override;
-void EndRasterCHROMIUM() override;
 void TexStorage2DImageCHROMIUM(GLenum target,
                                GLenum internalFormat,
                                GLenum bufferUsage,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 9cb545a..5da71d4 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1206,21 +1206,6 @@
     GLuint /* texture_id */) {
   return 0;
 }
-void GLES2InterfaceStub::BeginRasterCHROMIUM(
-    GLuint /* texture_id */,
-    GLuint /* sk_color */,
-    GLuint /* msaa_sample_count */,
-    GLboolean /* can_use_lcd_text */,
-    GLint /* color_type */,
-    GLuint /* color_space_transfer_cache_id */) {}
-void* GLES2InterfaceStub::MapRasterCHROMIUM(GLsizeiptr /* size */) {
-  return 0;
-}
-void* GLES2InterfaceStub::MapFontBufferCHROMIUM(GLsizeiptr /* size */) {
-  return 0;
-}
-void GLES2InterfaceStub::UnmapRasterCHROMIUM(GLsizeiptr /* written_size */) {}
-void GLES2InterfaceStub::EndRasterCHROMIUM() {}
 void GLES2InterfaceStub::TexStorage2DImageCHROMIUM(GLenum /* target */,
                                                    GLenum /* internalFormat */,
                                                    GLenum /* bufferUsage */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 3ebafff6a..5820e10 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -898,16 +898,6 @@
 void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override;
 void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override;
 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override;
-void BeginRasterCHROMIUM(GLuint texture_id,
-                         GLuint sk_color,
-                         GLuint msaa_sample_count,
-                         GLboolean can_use_lcd_text,
-                         GLint color_type,
-                         GLuint color_space_transfer_cache_id) override;
-void* MapRasterCHROMIUM(GLsizeiptr size) override;
-void* MapFontBufferCHROMIUM(GLsizeiptr size) override;
-void UnmapRasterCHROMIUM(GLsizeiptr written_size) override;
-void EndRasterCHROMIUM() override;
 void TexStorage2DImageCHROMIUM(GLenum target,
                                GLenum internalFormat,
                                GLenum bufferUsage,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 7934e5b..36510df 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2569,39 +2569,6 @@
   return gl_->LockDiscardableTextureCHROMIUM(texture_id);
 }
 
-void GLES2TraceImplementation::BeginRasterCHROMIUM(
-    GLuint texture_id,
-    GLuint sk_color,
-    GLuint msaa_sample_count,
-    GLboolean can_use_lcd_text,
-    GLint color_type,
-    GLuint color_space_transfer_cache_id) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BeginRasterCHROMIUM");
-  gl_->BeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
-                           can_use_lcd_text, color_type,
-                           color_space_transfer_cache_id);
-}
-
-void* GLES2TraceImplementation::MapRasterCHROMIUM(GLsizeiptr size) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapRasterCHROMIUM");
-  return gl_->MapRasterCHROMIUM(size);
-}
-
-void* GLES2TraceImplementation::MapFontBufferCHROMIUM(GLsizeiptr size) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapFontBufferCHROMIUM");
-  return gl_->MapFontBufferCHROMIUM(size);
-}
-
-void GLES2TraceImplementation::UnmapRasterCHROMIUM(GLsizeiptr written_size) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapRasterCHROMIUM");
-  gl_->UnmapRasterCHROMIUM(written_size);
-}
-
-void GLES2TraceImplementation::EndRasterCHROMIUM() {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EndRasterCHROMIUM");
-  gl_->EndRasterCHROMIUM();
-}
-
 void GLES2TraceImplementation::TexStorage2DImageCHROMIUM(GLenum target,
                                                          GLenum internalFormat,
                                                          GLenum bufferUsage,
diff --git a/gpu/command_buffer/client/implementation_base.cc b/gpu/command_buffer/client/implementation_base.cc
index 06678ce..508cf12 100644
--- a/gpu/command_buffer/client/implementation_base.cc
+++ b/gpu/command_buffer/client/implementation_base.cc
@@ -4,6 +4,8 @@
 
 #include "gpu/command_buffer/client/implementation_base.h"
 
+#include <algorithm>
+
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
@@ -28,7 +30,6 @@
       gpu_control_(gpu_control),
       capabilities_(gpu_control->GetCapabilities()),
       helper_(helper),
-      transfer_cache_(this),
       weak_ptr_factory_(this) {}
 
 ImplementationBase::~ImplementationBase() {
@@ -101,33 +102,6 @@
   gpu_control_->GetGpuFence(gpu_fence_id, std::move(callback));
 }
 
-void* ImplementationBase::MapTransferCacheEntry(size_t serialized_size) {
-  return transfer_cache_.MapEntry(mapped_memory_.get(), serialized_size);
-}
-
-void ImplementationBase::UnmapAndCreateTransferCacheEntry(uint32_t type,
-                                                          uint32_t id) {
-  transfer_cache_.UnmapAndCreateEntry(type, id);
-}
-
-bool ImplementationBase::ThreadsafeLockTransferCacheEntry(uint32_t type,
-                                                          uint32_t id) {
-  return transfer_cache_.LockEntry(type, id);
-}
-
-void ImplementationBase::UnlockTransferCacheEntries(
-    const std::vector<std::pair<uint32_t, uint32_t>>& entries) {
-  transfer_cache_.UnlockEntries(entries);
-}
-
-void ImplementationBase::DeleteTransferCacheEntry(uint32_t type, uint32_t id) {
-  transfer_cache_.DeleteEntry(type, id);
-}
-
-unsigned int ImplementationBase::GetTransferBufferFreeSize() const {
-  return transfer_buffer_->GetFreeSize();
-}
-
 bool ImplementationBase::OnMemoryDump(
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* pmd) {
diff --git a/gpu/command_buffer/client/implementation_base.h b/gpu/command_buffer/client/implementation_base.h
index 81ca9c5..376ed98 100644
--- a/gpu/command_buffer/client/implementation_base.h
+++ b/gpu/command_buffer/client/implementation_base.h
@@ -42,8 +42,7 @@
 class GLES2_IMPL_EXPORT ImplementationBase
     : public base::trace_event::MemoryDumpProvider,
       public ContextSupport,
-      public GpuControlClient,
-      public ClientTransferCache::Client {
+      public GpuControlClient {
  public:
   // The maximum result size from simple GL get commands.
   static const size_t kMaxSizeOfSimpleResult =
@@ -84,13 +83,6 @@
   void GetGpuFence(uint32_t gpu_fence_id,
                    base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)>
                        callback) override;
-  void* MapTransferCacheEntry(size_t serialized_size) override;
-  void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override;
-  bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override;
-  void UnlockTransferCacheEntries(
-      const std::vector<std::pair<uint32_t, uint32_t>>& entries) override;
-  void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override;
-  unsigned int GetTransferBufferFreeSize() const override;
   void SetGrContext(GrContext* gr) override;
   bool HasGrContextSupport() const override;
   void WillCallGLFromSkia() override;
@@ -159,8 +151,6 @@
 
   CommandBufferHelper* helper_;
 
-  ClientTransferCache transfer_cache_;
-
   base::WeakPtrFactory<ImplementationBase> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ImplementationBase);
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index aa59eec..c18bda98 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -227,7 +227,8 @@
       current_trace_stack_(0),
       aggressively_free_resources_(false),
       font_manager_(this, helper->command_buffer()),
-      lost_(false) {
+      lost_(false),
+      transfer_cache_(this) {
   DCHECK(helper);
   DCHECK(transfer_buffer);
   DCHECK(gpu_control);
@@ -392,6 +393,34 @@
   return false;
 }
 
+void* RasterImplementation::MapTransferCacheEntry(size_t serialized_size) {
+  return transfer_cache_.MapEntry(mapped_memory_.get(), serialized_size);
+}
+
+void RasterImplementation::UnmapAndCreateTransferCacheEntry(uint32_t type,
+                                                            uint32_t id) {
+  transfer_cache_.UnmapAndCreateEntry(type, id);
+}
+
+bool RasterImplementation::ThreadsafeLockTransferCacheEntry(uint32_t type,
+                                                            uint32_t id) {
+  return transfer_cache_.LockEntry(type, id);
+}
+
+void RasterImplementation::UnlockTransferCacheEntries(
+    const std::vector<std::pair<uint32_t, uint32_t>>& entries) {
+  transfer_cache_.UnlockEntries(entries);
+}
+
+void RasterImplementation::DeleteTransferCacheEntry(uint32_t type,
+                                                    uint32_t id) {
+  transfer_cache_.DeleteEntry(type, id);
+}
+
+unsigned int RasterImplementation::GetTransferBufferFreeSize() const {
+  return transfer_buffer_->GetFreeSize();
+}
+
 const std::string& RasterImplementation::GetLogPrefix() const {
   const std::string& prefix(debug_marker_manager_.GetMarker());
   return prefix.empty() ? this_in_hex_ : prefix;
diff --git a/gpu/command_buffer/client/raster_implementation.h b/gpu/command_buffer/client/raster_implementation.h
index 88adb82..9ebd3c4 100644
--- a/gpu/command_buffer/client/raster_implementation.h
+++ b/gpu/command_buffer/client/raster_implementation.h
@@ -45,6 +45,7 @@
 // buffer management.
 class RASTER_EXPORT RasterImplementation : public RasterInterface,
                                            public ImplementationBase,
+                                           public ClientTransferCache::Client,
                                            public gles2::QueryTrackerClient,
                                            public ClientFontManager::Client {
  public:
@@ -145,6 +146,13 @@
       uint32_t texture_id) override;
   bool ThreadsafeDiscardableTextureIsDeletedForTracing(
       uint32_t texture_id) override;
+  void* MapTransferCacheEntry(size_t serialized_size) override;
+  void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override;
+  bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override;
+  void UnlockTransferCacheEntries(
+      const std::vector<std::pair<uint32_t, uint32_t>>& entries) override;
+  void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override;
+  unsigned int GetTransferBufferFreeSize() const override;
 
   bool GetQueryObjectValueHelper(const char* function_name,
                                  GLuint id,
@@ -292,6 +300,8 @@
   };
   base::Optional<RasterProperties> raster_properties_;
 
+  ClientTransferCache transfer_cache_;
+
   DISALLOW_COPY_AND_ASSIGN(RasterImplementation);
 };
 
diff --git a/gpu/command_buffer/client/raster_implementation_gles.cc b/gpu/command_buffer/client/raster_implementation_gles.cc
index 4ea1276..8630cf5 100644
--- a/gpu/command_buffer/client/raster_implementation_gles.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles.cc
@@ -20,7 +20,6 @@
 #include "cc/paint/transfer_cache_serialize_helper.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/common/capabilities.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
@@ -30,117 +29,6 @@
 namespace gpu {
 namespace raster {
 
-namespace {
-
-class TransferCacheSerializeHelperImpl
-    : public cc::TransferCacheSerializeHelper {
- public:
-  TransferCacheSerializeHelperImpl(ContextSupport* support)
-      : support_(support) {}
-  ~TransferCacheSerializeHelperImpl() final = default;
-
- private:
-  bool LockEntryInternal(const EntryKey& key) final {
-    return support_->ThreadsafeLockTransferCacheEntry(
-        static_cast<uint32_t>(key.first), key.second);
-  }
-
-  void CreateEntryInternal(const cc::ClientTransferCacheEntry& entry) final {
-    size_t size = entry.SerializedSize();
-    void* data = support_->MapTransferCacheEntry(size);
-    // TODO(piman): handle error (failed to allocate/map shm)
-    DCHECK(data);
-    bool succeeded = entry.Serialize(
-        base::make_span(reinterpret_cast<uint8_t*>(data), size));
-    DCHECK(succeeded);
-    support_->UnmapAndCreateTransferCacheEntry(entry.UnsafeType(), entry.Id());
-  }
-
-  void FlushEntriesInternal(std::set<EntryKey> entries) final {
-    std::vector<std::pair<uint32_t, uint32_t>> transformed;
-    transformed.reserve(entries.size());
-    for (const auto& e : entries)
-      transformed.emplace_back(static_cast<uint32_t>(e.first), e.second);
-    support_->UnlockTransferCacheEntries(transformed);
-  }
-
-  ContextSupport* support_;
-};
-
-struct PaintOpSerializer {
- public:
-  PaintOpSerializer(size_t initial_size,
-                    gles2::GLES2Interface* gl,
-                    cc::DecodeStashingImageProvider* stashing_image_provider,
-                    cc::TransferCacheSerializeHelper* transfer_cache_helper,
-                    ClientFontManager* font_manager)
-      : gl_(gl),
-        buffer_(static_cast<char*>(gl_->MapRasterCHROMIUM(initial_size))),
-        stashing_image_provider_(stashing_image_provider),
-        transfer_cache_helper_(transfer_cache_helper),
-        font_manager_(font_manager),
-        free_bytes_(buffer_ ? initial_size : 0) {}
-
-  ~PaintOpSerializer() {
-    // Need to call SendSerializedData;
-    DCHECK(!written_bytes_);
-  }
-
-  size_t Serialize(const cc::PaintOp* op,
-                   const cc::PaintOp::SerializeOptions& options) {
-    if (!valid())
-      return 0;
-    size_t size = op->Serialize(buffer_ + written_bytes_, free_bytes_, options);
-    if (!size) {
-      SendSerializedData();
-      buffer_ = static_cast<char*>(gl_->MapRasterCHROMIUM(kBlockAlloc));
-      if (!buffer_) {
-        free_bytes_ = 0;
-        return 0;
-      }
-      free_bytes_ = kBlockAlloc;
-      size = op->Serialize(buffer_ + written_bytes_, free_bytes_, options);
-    }
-    DCHECK_LE(size, free_bytes_);
-
-    written_bytes_ += size;
-    free_bytes_ -= size;
-    return size;
-  }
-
-  void SendSerializedData() {
-    if (!valid())
-      return;
-
-    // Serialize fonts before sending raster commands.
-    font_manager_->Serialize();
-    gl_->UnmapRasterCHROMIUM(written_bytes_);
-
-    // Now that we've issued the RasterCHROMIUM referencing the stashed
-    // images, Reset the |stashing_image_provider_|, causing us to issue
-    // unlock commands for these images.
-    stashing_image_provider_->Reset();
-    transfer_cache_helper_->FlushEntries();
-    written_bytes_ = 0;
-  }
-
-  bool valid() const { return !!buffer_; }
-
- private:
-  static constexpr unsigned int kBlockAlloc = 512 * 1024;
-
-  gles2::GLES2Interface* gl_;
-  char* buffer_;
-  cc::DecodeStashingImageProvider* stashing_image_provider_;
-  cc::TransferCacheSerializeHelper* transfer_cache_helper_;
-  ClientFontManager* font_manager_;
-
-  size_t written_bytes_ = 0;
-  size_t free_bytes_ = 0;
-};
-
-}  // anonymous namespace
-
 static GLenum GetImageTextureTarget(const gpu::Capabilities& caps,
                                     gfx::BufferUsage usage,
                                     viz::ResourceFormat format) {
@@ -159,16 +47,6 @@
       buffer_usage(buffer_usage),
       format(format) {}
 
-RasterImplementationGLES::RasterProperties::RasterProperties(
-    SkColor background_color,
-    bool can_use_lcd_text,
-    sk_sp<SkColorSpace> color_space)
-    : background_color(background_color),
-      can_use_lcd_text(can_use_lcd_text),
-      color_space(std::move(color_space)) {}
-
-RasterImplementationGLES::RasterProperties::~RasterProperties() = default;
-
 RasterImplementationGLES::Texture* RasterImplementationGLES::GetTexture(
     GLuint texture_id) {
   auto it = texture_info_.find(texture_id);
@@ -188,15 +66,12 @@
 
 RasterImplementationGLES::RasterImplementationGLES(
     gles2::GLES2Interface* gl,
-    ContextSupport* support,
     CommandBuffer* command_buffer,
     const gpu::Capabilities& caps)
     : gl_(gl),
-      support_(support),
       caps_(caps),
       use_texture_storage_(caps.texture_storage),
-      use_texture_storage_image_(caps.texture_storage_image),
-      font_manager_(this, command_buffer) {}
+      use_texture_storage_image_(caps.texture_storage_image) {}
 
 RasterImplementationGLES::~RasterImplementationGLES() {}
 
@@ -439,27 +314,7 @@
     GLboolean can_use_lcd_text,
     GLint color_type,
     const cc::RasterColorSpace& raster_color_space) {
-  DCHECK(!raster_properties_);
-
-  TransferCacheSerializeHelperImpl transfer_cache_serialize_helper(support_);
-  if (!transfer_cache_serialize_helper.LockEntry(
-          cc::TransferCacheEntryType::kColorSpace,
-          raster_color_space.color_space_id)) {
-    transfer_cache_serialize_helper.CreateEntry(
-        cc::ClientColorSpaceTransferCacheEntry(raster_color_space));
-  }
-  transfer_cache_serialize_helper.AssertLocked(
-      cc::TransferCacheEntryType::kColorSpace,
-      raster_color_space.color_space_id);
-
-  Texture* texture = GetTexture(texture_id);
-  gl_->BeginRasterCHROMIUM(texture->id, sk_color, msaa_sample_count,
-                           can_use_lcd_text, color_type,
-                           raster_color_space.color_space_id);
-  transfer_cache_serialize_helper.FlushEntries();
-
-  raster_properties_.emplace(sk_color, can_use_lcd_text,
-                             raster_color_space.color_space.ToSkColorSpace());
+  NOTREACHED();
 }
 
 void RasterImplementationGLES::RasterCHROMIUM(
@@ -471,58 +326,11 @@
     const gfx::Vector2dF& post_translate,
     GLfloat post_scale,
     bool requires_clear) {
-  if (std::abs(post_scale) < std::numeric_limits<float>::epsilon())
-    return;
-
-  gfx::Rect query_rect =
-      gfx::ScaleToEnclosingRect(playback_rect, 1.f / post_scale);
-  std::vector<size_t> offsets = list->rtree_.Search(query_rect);
-  if (offsets.empty())
-    return;
-
-  // TODO(enne): tune these numbers
-  // TODO(enne): convert these types here and in transfer buffer to be size_t.
-  static constexpr unsigned int kMinAlloc = 16 * 1024;
-  unsigned int free_size =
-      std::max(support_->GetTransferBufferFreeSize(), kMinAlloc);
-
-  // This section duplicates RasterSource::PlaybackToCanvas setup preamble.
-  cc::PaintOpBufferSerializer::Preamble preamble;
-  preamble.content_size = content_size;
-  preamble.full_raster_rect = full_raster_rect;
-  preamble.playback_rect = playback_rect;
-  preamble.post_translation = post_translate;
-  preamble.post_scale = gfx::SizeF(post_scale, post_scale);
-  preamble.requires_clear = requires_clear;
-  preamble.background_color = raster_properties_->background_color;
-
-  // Wrap the provided provider in a stashing provider so that we can delay
-  // unrefing images until we have serialized dependent commands.
-  cc::DecodeStashingImageProvider stashing_image_provider(provider);
-
-  // TODO(enne): don't access private members of DisplayItemList.
-  TransferCacheSerializeHelperImpl transfer_cache_serialize_helper(support_);
-  PaintOpSerializer op_serializer(free_size, gl_, &stashing_image_provider,
-                                  &transfer_cache_serialize_helper,
-                                  &font_manager_);
-
-  cc::PaintOpBufferSerializer::SerializeCallback serialize_cb =
-      base::BindRepeating(&PaintOpSerializer::Serialize,
-                          base::Unretained(&op_serializer));
-  cc::PaintOpBufferSerializer serializer(
-      serialize_cb, &stashing_image_provider, &transfer_cache_serialize_helper,
-      font_manager_.strike_server(), raster_properties_->color_space.get(),
-      raster_properties_->can_use_lcd_text);
-  serializer.Serialize(&list->paint_op_buffer_, &offsets, preamble);
-  // TODO(piman): raise error if !serializer.valid()?
-  op_serializer.SendSerializedData();
+  NOTREACHED();
 }
 
 void RasterImplementationGLES::EndRasterCHROMIUM() {
-  DCHECK(raster_properties_);
-
-  gl_->EndRasterCHROMIUM();
-  raster_properties_.reset();
+  NOTREACHED();
 }
 
 void RasterImplementationGLES::BeginGpuRaster() {
@@ -544,9 +352,5 @@
   gl_->ActiveTexture(GL_TEXTURE0);
 }
 
-void* RasterImplementationGLES::MapFontBuffer(size_t size) {
-  return gl_->MapFontBufferCHROMIUM(size);
-}
-
 }  // namespace raster
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/raster_implementation_gles.h b/gpu/command_buffer/client/raster_implementation_gles.h
index 7dd2682..a665567f 100644
--- a/gpu/command_buffer/client/raster_implementation_gles.h
+++ b/gpu/command_buffer/client/raster_implementation_gles.h
@@ -20,19 +20,15 @@
 
 namespace gpu {
 class CommandBuffer;
-class ContextSupport;
 
 namespace raster {
 
 struct Capabilities;
 
 // An implementation of RasterInterface on top of GLES2Interface.
-class RASTER_EXPORT RasterImplementationGLES
-    : public RasterInterface,
-      public ClientFontManager::Client {
+class RASTER_EXPORT RasterImplementationGLES : public RasterInterface {
  public:
   RasterImplementationGLES(gles2::GLES2Interface* gl,
-                           ContextSupport* support,
                            CommandBuffer* command_buffer,
                            const gpu::Capabilities& caps);
   ~RasterImplementationGLES() override;
@@ -132,9 +128,6 @@
   void BeginGpuRaster() override;
   void EndGpuRaster() override;
 
-  // ClientFontManager::Client implementation.
-  void* MapFontBuffer(size_t size) override;
-
  private:
   struct Texture {
     Texture(GLuint id,
@@ -153,7 +146,6 @@
   Texture* EnsureTextureBound(Texture* texture);
 
   gles2::GLES2Interface* gl_;
-  ContextSupport* support_;
   gpu::Capabilities caps_;
   bool use_texture_storage_;
   bool use_texture_storage_image_;
@@ -161,18 +153,6 @@
   std::unordered_map<GLuint, Texture> texture_info_;
   Texture* bound_texture_ = nullptr;
 
-  ClientFontManager font_manager_;
-  struct RasterProperties {
-    RasterProperties(SkColor background_color,
-                     bool can_use_lcd_text,
-                     sk_sp<SkColorSpace> color_space);
-    ~RasterProperties();
-    SkColor background_color = SK_ColorWHITE;
-    bool can_use_lcd_text = false;
-    sk_sp<SkColorSpace> color_space;
-  };
-  base::Optional<RasterProperties> raster_properties_;
-
   DISALLOW_COPY_AND_ASSIGN(RasterImplementationGLES);
 };
 
diff --git a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
index 533bb58..cb0d222 100644
--- a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
+++ b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
@@ -241,15 +241,15 @@
   void SetUp() override {
     gl_.reset(new RasterMockGLES2Interface());
 
-    ri_.reset(new RasterImplementationGLES(
-        gl_.get(), &support_, &command_buffer_, gpu::Capabilities()));
+    ri_.reset(new RasterImplementationGLES(gl_.get(), &command_buffer_,
+                                           gpu::Capabilities()));
   }
 
   void TearDown() override {}
 
   void SetUpWithCapabilities(const gpu::Capabilities& capabilities) {
-    ri_.reset(new RasterImplementationGLES(gl_.get(), &support_,
-                                           &command_buffer_, capabilities));
+    ri_.reset(new RasterImplementationGLES(gl_.get(), &command_buffer_,
+                                           capabilities));
   }
 
   void ExpectBindTexture(GLenum target, GLuint texture_id) {
@@ -636,52 +636,6 @@
   }
 }
 
-TEST_F(RasterImplementationGLESTest, RasterCHROMIUM) {
-  const GLuint texture_id = 23;
-  const GLuint sk_color = 0x226688AAu;
-  const GLuint msaa_sample_count = 4;
-  const GLboolean can_use_lcd_text = GL_TRUE;
-  const GLint color_type = kRGBA_8888_SkColorType;
-  const auto raster_color_space =
-      cc::RasterColorSpace(gfx::ColorSpace::CreateSRGB(), 2);
-
-  AllocTextureId(false, gfx::BufferUsage::GPU_READ, viz::RGBA_8888, texture_id);
-
-  EXPECT_CALL(*gl_, BeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
-                                        can_use_lcd_text, color_type, 2))
-      .Times(1);
-  ri_->BeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
-                           can_use_lcd_text, color_type, raster_color_space);
-
-  scoped_refptr<cc::DisplayItemList> display_list = new cc::DisplayItemList;
-  display_list->StartPaint();
-  display_list->push<cc::DrawColorOp>(SK_ColorRED, SkBlendMode::kSrc);
-  display_list->EndPaintOfUnpaired(gfx::Rect(100, 100));
-  display_list->Finalize();
-
-  ImageProviderStub image_provider;
-  const gfx::Size content_size(100, 200);
-  const gfx::Rect full_raster_rect(2, 3, 8, 9);
-  const gfx::Rect playback_rect(3, 4, 5, 6);
-  const gfx::Vector2dF post_translate(7.0f, 8.0f);
-  const GLfloat post_scale = 9.0f;
-  bool requires_clear = false;
-
-  constexpr const GLsizeiptr kBufferSize = 16 << 10;
-  char buffer[kBufferSize];
-
-  EXPECT_CALL(*gl_, MapRasterCHROMIUM(Le(kBufferSize)))
-      .WillOnce(Return(buffer));
-  EXPECT_CALL(*gl_, UnmapRasterCHROMIUM(Gt(0))).Times(1);
-
-  ri_->RasterCHROMIUM(display_list.get(), &image_provider, content_size,
-                      full_raster_rect, playback_rect, post_translate,
-                      post_scale, requires_clear);
-
-  EXPECT_CALL(*gl_, EndRasterCHROMIUM()).Times(1);
-  ri_->EndRasterCHROMIUM();
-}
-
 TEST_F(RasterImplementationGLESTest, BeginGpuRaster) {
   EXPECT_CALL(*gl_, TraceBeginCHROMIUM(StrEq("BeginGpuRaster"),
                                        StrEq("GpuRasterization")))
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index bef8ef8..3b2a6a5 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -16128,324 +16128,6 @@
     offsetof(LockDiscardableTextureCHROMIUM, texture_id) == 4,
     "offset of LockDiscardableTextureCHROMIUM texture_id should be 4");
 
-struct BeginRasterCHROMIUM {
-  typedef BeginRasterCHROMIUM ValueType;
-  static const CommandId kCmdId = kBeginRasterCHROMIUM;
-  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
-  static uint32_t ComputeSize() {
-    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
-  }
-
-  void SetHeader() { header.SetCmd<ValueType>(); }
-
-  void Init(GLuint _texture_id,
-            GLuint _sk_color,
-            GLuint _msaa_sample_count,
-            GLboolean _can_use_lcd_text,
-            GLint _color_type,
-            GLuint _color_space_transfer_cache_id) {
-    SetHeader();
-    texture_id = _texture_id;
-    sk_color = _sk_color;
-    msaa_sample_count = _msaa_sample_count;
-    can_use_lcd_text = _can_use_lcd_text;
-    color_type = _color_type;
-    color_space_transfer_cache_id = _color_space_transfer_cache_id;
-  }
-
-  void* Set(void* cmd,
-            GLuint _texture_id,
-            GLuint _sk_color,
-            GLuint _msaa_sample_count,
-            GLboolean _can_use_lcd_text,
-            GLint _color_type,
-            GLuint _color_space_transfer_cache_id) {
-    static_cast<ValueType*>(cmd)->Init(
-        _texture_id, _sk_color, _msaa_sample_count, _can_use_lcd_text,
-        _color_type, _color_space_transfer_cache_id);
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-  uint32_t texture_id;
-  uint32_t sk_color;
-  uint32_t msaa_sample_count;
-  uint32_t can_use_lcd_text;
-  int32_t color_type;
-  uint32_t color_space_transfer_cache_id;
-};
-
-static_assert(sizeof(BeginRasterCHROMIUM) == 28,
-              "size of BeginRasterCHROMIUM should be 28");
-static_assert(offsetof(BeginRasterCHROMIUM, header) == 0,
-              "offset of BeginRasterCHROMIUM header should be 0");
-static_assert(offsetof(BeginRasterCHROMIUM, texture_id) == 4,
-              "offset of BeginRasterCHROMIUM texture_id should be 4");
-static_assert(offsetof(BeginRasterCHROMIUM, sk_color) == 8,
-              "offset of BeginRasterCHROMIUM sk_color should be 8");
-static_assert(offsetof(BeginRasterCHROMIUM, msaa_sample_count) == 12,
-              "offset of BeginRasterCHROMIUM msaa_sample_count should be 12");
-static_assert(offsetof(BeginRasterCHROMIUM, can_use_lcd_text) == 16,
-              "offset of BeginRasterCHROMIUM can_use_lcd_text should be 16");
-static_assert(offsetof(BeginRasterCHROMIUM, color_type) == 20,
-              "offset of BeginRasterCHROMIUM color_type should be 20");
-static_assert(
-    offsetof(BeginRasterCHROMIUM, color_space_transfer_cache_id) == 24,
-    "offset of BeginRasterCHROMIUM color_space_transfer_cache_id should be 24");
-
-struct RasterCHROMIUM {
-  typedef RasterCHROMIUM ValueType;
-  static const CommandId kCmdId = kRasterCHROMIUM;
-  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
-  static uint32_t ComputeSize() {
-    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
-  }
-
-  void SetHeader() { header.SetCmd<ValueType>(); }
-
-  void Init(GLuint _raster_shm_id,
-            GLuint _raster_shm_offset,
-            GLsizeiptr _raster_shm_size,
-            GLuint _font_shm_id,
-            GLuint _font_shm_offset,
-            GLsizeiptr _font_shm_size) {
-    SetHeader();
-    raster_shm_id = _raster_shm_id;
-    raster_shm_offset = _raster_shm_offset;
-    raster_shm_size = _raster_shm_size;
-    font_shm_id = _font_shm_id;
-    font_shm_offset = _font_shm_offset;
-    font_shm_size = _font_shm_size;
-  }
-
-  void* Set(void* cmd,
-            GLuint _raster_shm_id,
-            GLuint _raster_shm_offset,
-            GLsizeiptr _raster_shm_size,
-            GLuint _font_shm_id,
-            GLuint _font_shm_offset,
-            GLsizeiptr _font_shm_size) {
-    static_cast<ValueType*>(cmd)->Init(_raster_shm_id, _raster_shm_offset,
-                                       _raster_shm_size, _font_shm_id,
-                                       _font_shm_offset, _font_shm_size);
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-  uint32_t raster_shm_id;
-  uint32_t raster_shm_offset;
-  int32_t raster_shm_size;
-  uint32_t font_shm_id;
-  uint32_t font_shm_offset;
-  int32_t font_shm_size;
-};
-
-static_assert(sizeof(RasterCHROMIUM) == 28,
-              "size of RasterCHROMIUM should be 28");
-static_assert(offsetof(RasterCHROMIUM, header) == 0,
-              "offset of RasterCHROMIUM header should be 0");
-static_assert(offsetof(RasterCHROMIUM, raster_shm_id) == 4,
-              "offset of RasterCHROMIUM raster_shm_id should be 4");
-static_assert(offsetof(RasterCHROMIUM, raster_shm_offset) == 8,
-              "offset of RasterCHROMIUM raster_shm_offset should be 8");
-static_assert(offsetof(RasterCHROMIUM, raster_shm_size) == 12,
-              "offset of RasterCHROMIUM raster_shm_size should be 12");
-static_assert(offsetof(RasterCHROMIUM, font_shm_id) == 16,
-              "offset of RasterCHROMIUM font_shm_id should be 16");
-static_assert(offsetof(RasterCHROMIUM, font_shm_offset) == 20,
-              "offset of RasterCHROMIUM font_shm_offset should be 20");
-static_assert(offsetof(RasterCHROMIUM, font_shm_size) == 24,
-              "offset of RasterCHROMIUM font_shm_size should be 24");
-
-struct EndRasterCHROMIUM {
-  typedef EndRasterCHROMIUM ValueType;
-  static const CommandId kCmdId = kEndRasterCHROMIUM;
-  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
-  static uint32_t ComputeSize() {
-    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
-  }
-
-  void SetHeader() { header.SetCmd<ValueType>(); }
-
-  void Init() { SetHeader(); }
-
-  void* Set(void* cmd) {
-    static_cast<ValueType*>(cmd)->Init();
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-};
-
-static_assert(sizeof(EndRasterCHROMIUM) == 4,
-              "size of EndRasterCHROMIUM should be 4");
-static_assert(offsetof(EndRasterCHROMIUM, header) == 0,
-              "offset of EndRasterCHROMIUM header should be 0");
-
-struct CreateTransferCacheEntryINTERNAL {
-  typedef CreateTransferCacheEntryINTERNAL ValueType;
-  static const CommandId kCmdId = kCreateTransferCacheEntryINTERNAL;
-  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
-  static uint32_t ComputeSize() {
-    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
-  }
-
-  void SetHeader() { header.SetCmd<ValueType>(); }
-
-  void Init(GLuint _entry_type,
-            GLuint _entry_id,
-            GLuint _handle_shm_id,
-            GLuint _handle_shm_offset,
-            GLuint _data_shm_id,
-            GLuint _data_shm_offset,
-            GLuint _data_size) {
-    SetHeader();
-    entry_type = _entry_type;
-    entry_id = _entry_id;
-    handle_shm_id = _handle_shm_id;
-    handle_shm_offset = _handle_shm_offset;
-    data_shm_id = _data_shm_id;
-    data_shm_offset = _data_shm_offset;
-    data_size = _data_size;
-  }
-
-  void* Set(void* cmd,
-            GLuint _entry_type,
-            GLuint _entry_id,
-            GLuint _handle_shm_id,
-            GLuint _handle_shm_offset,
-            GLuint _data_shm_id,
-            GLuint _data_shm_offset,
-            GLuint _data_size) {
-    static_cast<ValueType*>(cmd)->Init(_entry_type, _entry_id, _handle_shm_id,
-                                       _handle_shm_offset, _data_shm_id,
-                                       _data_shm_offset, _data_size);
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-  uint32_t entry_type;
-  uint32_t entry_id;
-  uint32_t handle_shm_id;
-  uint32_t handle_shm_offset;
-  uint32_t data_shm_id;
-  uint32_t data_shm_offset;
-  uint32_t data_size;
-};
-
-static_assert(sizeof(CreateTransferCacheEntryINTERNAL) == 32,
-              "size of CreateTransferCacheEntryINTERNAL should be 32");
-static_assert(offsetof(CreateTransferCacheEntryINTERNAL, header) == 0,
-              "offset of CreateTransferCacheEntryINTERNAL header should be 0");
-static_assert(
-    offsetof(CreateTransferCacheEntryINTERNAL, entry_type) == 4,
-    "offset of CreateTransferCacheEntryINTERNAL entry_type should be 4");
-static_assert(
-    offsetof(CreateTransferCacheEntryINTERNAL, entry_id) == 8,
-    "offset of CreateTransferCacheEntryINTERNAL entry_id should be 8");
-static_assert(
-    offsetof(CreateTransferCacheEntryINTERNAL, handle_shm_id) == 12,
-    "offset of CreateTransferCacheEntryINTERNAL handle_shm_id should be 12");
-static_assert(offsetof(CreateTransferCacheEntryINTERNAL, handle_shm_offset) ==
-                  16,
-              "offset of CreateTransferCacheEntryINTERNAL handle_shm_offset "
-              "should be 16");
-static_assert(
-    offsetof(CreateTransferCacheEntryINTERNAL, data_shm_id) == 20,
-    "offset of CreateTransferCacheEntryINTERNAL data_shm_id should be 20");
-static_assert(
-    offsetof(CreateTransferCacheEntryINTERNAL, data_shm_offset) == 24,
-    "offset of CreateTransferCacheEntryINTERNAL data_shm_offset should be 24");
-static_assert(
-    offsetof(CreateTransferCacheEntryINTERNAL, data_size) == 28,
-    "offset of CreateTransferCacheEntryINTERNAL data_size should be 28");
-
-struct DeleteTransferCacheEntryINTERNAL {
-  typedef DeleteTransferCacheEntryINTERNAL ValueType;
-  static const CommandId kCmdId = kDeleteTransferCacheEntryINTERNAL;
-  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
-  static uint32_t ComputeSize() {
-    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
-  }
-
-  void SetHeader() { header.SetCmd<ValueType>(); }
-
-  void Init(GLuint _entry_type, GLuint _entry_id) {
-    SetHeader();
-    entry_type = _entry_type;
-    entry_id = _entry_id;
-  }
-
-  void* Set(void* cmd, GLuint _entry_type, GLuint _entry_id) {
-    static_cast<ValueType*>(cmd)->Init(_entry_type, _entry_id);
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-  uint32_t entry_type;
-  uint32_t entry_id;
-};
-
-static_assert(sizeof(DeleteTransferCacheEntryINTERNAL) == 12,
-              "size of DeleteTransferCacheEntryINTERNAL should be 12");
-static_assert(offsetof(DeleteTransferCacheEntryINTERNAL, header) == 0,
-              "offset of DeleteTransferCacheEntryINTERNAL header should be 0");
-static_assert(
-    offsetof(DeleteTransferCacheEntryINTERNAL, entry_type) == 4,
-    "offset of DeleteTransferCacheEntryINTERNAL entry_type should be 4");
-static_assert(
-    offsetof(DeleteTransferCacheEntryINTERNAL, entry_id) == 8,
-    "offset of DeleteTransferCacheEntryINTERNAL entry_id should be 8");
-
-struct UnlockTransferCacheEntryINTERNAL {
-  typedef UnlockTransferCacheEntryINTERNAL ValueType;
-  static const CommandId kCmdId = kUnlockTransferCacheEntryINTERNAL;
-  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
-  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
-  static uint32_t ComputeSize() {
-    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
-  }
-
-  void SetHeader() { header.SetCmd<ValueType>(); }
-
-  void Init(GLuint _entry_type, GLuint _entry_id) {
-    SetHeader();
-    entry_type = _entry_type;
-    entry_id = _entry_id;
-  }
-
-  void* Set(void* cmd, GLuint _entry_type, GLuint _entry_id) {
-    static_cast<ValueType*>(cmd)->Init(_entry_type, _entry_id);
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-  uint32_t entry_type;
-  uint32_t entry_id;
-};
-
-static_assert(sizeof(UnlockTransferCacheEntryINTERNAL) == 12,
-              "size of UnlockTransferCacheEntryINTERNAL should be 12");
-static_assert(offsetof(UnlockTransferCacheEntryINTERNAL, header) == 0,
-              "offset of UnlockTransferCacheEntryINTERNAL header should be 0");
-static_assert(
-    offsetof(UnlockTransferCacheEntryINTERNAL, entry_type) == 4,
-    "offset of UnlockTransferCacheEntryINTERNAL entry_type should be 4");
-static_assert(
-    offsetof(UnlockTransferCacheEntryINTERNAL, entry_id) == 8,
-    "offset of UnlockTransferCacheEntryINTERNAL entry_id should be 8");
-
 struct TexStorage2DImageCHROMIUM {
   typedef TexStorage2DImageCHROMIUM ValueType;
   static const CommandId kCmdId = kTexStorage2DImageCHROMIUM;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 9bc651a1..ece4f7b 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -5341,100 +5341,6 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
-TEST_F(GLES2FormatTest, BeginRasterCHROMIUM) {
-  cmds::BeginRasterCHROMIUM& cmd = *GetBufferAs<cmds::BeginRasterCHROMIUM>();
-  void* next_cmd =
-      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
-              static_cast<GLuint>(13), static_cast<GLboolean>(14),
-              static_cast<GLint>(15), static_cast<GLuint>(16));
-  EXPECT_EQ(static_cast<uint32_t>(cmds::BeginRasterCHROMIUM::kCmdId),
-            cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
-  EXPECT_EQ(static_cast<GLuint>(12), cmd.sk_color);
-  EXPECT_EQ(static_cast<GLuint>(13), cmd.msaa_sample_count);
-  EXPECT_EQ(static_cast<GLboolean>(14), cmd.can_use_lcd_text);
-  EXPECT_EQ(static_cast<GLint>(15), cmd.color_type);
-  EXPECT_EQ(static_cast<GLuint>(16), cmd.color_space_transfer_cache_id);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, RasterCHROMIUM) {
-  cmds::RasterCHROMIUM& cmd = *GetBufferAs<cmds::RasterCHROMIUM>();
-  void* next_cmd =
-      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
-              static_cast<GLsizeiptr>(13), static_cast<GLuint>(14),
-              static_cast<GLuint>(15), static_cast<GLsizeiptr>(16));
-  EXPECT_EQ(static_cast<uint32_t>(cmds::RasterCHROMIUM::kCmdId),
-            cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  EXPECT_EQ(static_cast<GLuint>(11), cmd.raster_shm_id);
-  EXPECT_EQ(static_cast<GLuint>(12), cmd.raster_shm_offset);
-  EXPECT_EQ(static_cast<GLsizeiptr>(13), cmd.raster_shm_size);
-  EXPECT_EQ(static_cast<GLuint>(14), cmd.font_shm_id);
-  EXPECT_EQ(static_cast<GLuint>(15), cmd.font_shm_offset);
-  EXPECT_EQ(static_cast<GLsizeiptr>(16), cmd.font_shm_size);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, EndRasterCHROMIUM) {
-  cmds::EndRasterCHROMIUM& cmd = *GetBufferAs<cmds::EndRasterCHROMIUM>();
-  void* next_cmd = cmd.Set(&cmd);
-  EXPECT_EQ(static_cast<uint32_t>(cmds::EndRasterCHROMIUM::kCmdId),
-            cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, CreateTransferCacheEntryINTERNAL) {
-  cmds::CreateTransferCacheEntryINTERNAL& cmd =
-      *GetBufferAs<cmds::CreateTransferCacheEntryINTERNAL>();
-  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
-                           static_cast<GLuint>(12), static_cast<GLuint>(13),
-                           static_cast<GLuint>(14), static_cast<GLuint>(15),
-                           static_cast<GLuint>(16), static_cast<GLuint>(17));
-  EXPECT_EQ(
-      static_cast<uint32_t>(cmds::CreateTransferCacheEntryINTERNAL::kCmdId),
-      cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  EXPECT_EQ(static_cast<GLuint>(11), cmd.entry_type);
-  EXPECT_EQ(static_cast<GLuint>(12), cmd.entry_id);
-  EXPECT_EQ(static_cast<GLuint>(13), cmd.handle_shm_id);
-  EXPECT_EQ(static_cast<GLuint>(14), cmd.handle_shm_offset);
-  EXPECT_EQ(static_cast<GLuint>(15), cmd.data_shm_id);
-  EXPECT_EQ(static_cast<GLuint>(16), cmd.data_shm_offset);
-  EXPECT_EQ(static_cast<GLuint>(17), cmd.data_size);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, DeleteTransferCacheEntryINTERNAL) {
-  cmds::DeleteTransferCacheEntryINTERNAL& cmd =
-      *GetBufferAs<cmds::DeleteTransferCacheEntryINTERNAL>();
-  void* next_cmd =
-      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
-  EXPECT_EQ(
-      static_cast<uint32_t>(cmds::DeleteTransferCacheEntryINTERNAL::kCmdId),
-      cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  EXPECT_EQ(static_cast<GLuint>(11), cmd.entry_type);
-  EXPECT_EQ(static_cast<GLuint>(12), cmd.entry_id);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
-TEST_F(GLES2FormatTest, UnlockTransferCacheEntryINTERNAL) {
-  cmds::UnlockTransferCacheEntryINTERNAL& cmd =
-      *GetBufferAs<cmds::UnlockTransferCacheEntryINTERNAL>();
-  void* next_cmd =
-      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
-  EXPECT_EQ(
-      static_cast<uint32_t>(cmds::UnlockTransferCacheEntryINTERNAL::kCmdId),
-      cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  EXPECT_EQ(static_cast<GLuint>(11), cmd.entry_type);
-  EXPECT_EQ(static_cast<GLuint>(12), cmd.entry_id);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
 TEST_F(GLES2FormatTest, TexStorage2DImageCHROMIUM) {
   cmds::TexStorage2DImageCHROMIUM& cmd =
       *GetBufferAs<cmds::TexStorage2DImageCHROMIUM>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 047ff08..50e83cf 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -336,18 +336,12 @@
   OP(InitializeDiscardableTextureCHROMIUM)                 /* 577 */ \
   OP(UnlockDiscardableTextureCHROMIUM)                     /* 578 */ \
   OP(LockDiscardableTextureCHROMIUM)                       /* 579 */ \
-  OP(BeginRasterCHROMIUM)                                  /* 580 */ \
-  OP(RasterCHROMIUM)                                       /* 581 */ \
-  OP(EndRasterCHROMIUM)                                    /* 582 */ \
-  OP(CreateTransferCacheEntryINTERNAL)                     /* 583 */ \
-  OP(DeleteTransferCacheEntryINTERNAL)                     /* 584 */ \
-  OP(UnlockTransferCacheEntryINTERNAL)                     /* 585 */ \
-  OP(TexStorage2DImageCHROMIUM)                            /* 586 */ \
-  OP(SetColorSpaceMetadataCHROMIUM)                        /* 587 */ \
-  OP(WindowRectanglesEXTImmediate)                         /* 588 */ \
-  OP(CreateGpuFenceINTERNAL)                               /* 589 */ \
-  OP(WaitGpuFenceCHROMIUM)                                 /* 590 */ \
-  OP(DestroyGpuFenceCHROMIUM)                              /* 591 */
+  OP(TexStorage2DImageCHROMIUM)                            /* 580 */ \
+  OP(SetColorSpaceMetadataCHROMIUM)                        /* 581 */ \
+  OP(WindowRectanglesEXTImmediate)                         /* 582 */ \
+  OP(CreateGpuFenceINTERNAL)                               /* 583 */ \
+  OP(WaitGpuFenceCHROMIUM)                                 /* 584 */ \
+  OP(DestroyGpuFenceCHROMIUM)                              /* 585 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/gles2_cmd_buffer_functions.txt b/gpu/command_buffer/gles2_cmd_buffer_functions.txt
index f816ebb..cfebb94 100644
--- a/gpu/command_buffer/gles2_cmd_buffer_functions.txt
+++ b/gpu/command_buffer/gles2_cmd_buffer_functions.txt
@@ -376,17 +376,6 @@
 GL_APICALL void         GL_APIENTRY glUnlockDiscardableTextureCHROMIUM (GLuint texture_id);
 GL_APICALL bool         GL_APIENTRY glLockDiscardableTextureCHROMIUM (GLuint texture_id);
 
-// Extension CHROMIUM_raster_transport
-GL_APICALL void         GL_APIENTRY glBeginRasterCHROMIUM (GLuint texture_id, GLuint sk_color, GLuint msaa_sample_count, GLboolean can_use_lcd_text, GLint color_type, GLuint color_space_transfer_cache_id);
-GL_APICALL void         GL_APIENTRY glRasterCHROMIUM (GLuint raster_shm_id, GLuint raster_shm_offset, GLsizeiptr raster_shm_size, GLuint font_shm_id, GLuint font_shm_offset, GLsizeiptr font_shm_size);
-GL_APICALL void*        GL_APIENTRY glMapRasterCHROMIUM (GLsizeiptr size);
-GL_APICALL void*        GL_APIENTRY glMapFontBufferCHROMIUM (GLsizeiptr size);
-GL_APICALL void         GL_APIENTRY glUnmapRasterCHROMIUM (GLsizeiptr written_size);
-GL_APICALL void         GL_APIENTRY glEndRasterCHROMIUM (void);
-GL_APICALL void         GL_APIENTRY glCreateTransferCacheEntryINTERNAL (GLuint entry_type, GLuint entry_id, GLuint handle_shm_id, GLuint handle_shm_offset, GLuint data_shm_id, GLuint data_shm_offset, GLuint data_size);
-GL_APICALL void         GL_APIENTRY glDeleteTransferCacheEntryINTERNAL (GLuint entry_type, GLuint entry_id);
-GL_APICALL void         GL_APIENTRY glUnlockTransferCacheEntryINTERNAL (GLuint entry_type, GLuint entry_id);
-
 // Extension CHROMIUM_texture_storage_image
 GL_APICALL void         GL_APIENTRY glTexStorage2DImageCHROMIUM (GLenumTextureBindTarget target, GLenumTextureInternalFormatStorage internalFormat, GLenumClientBufferUsage bufferUsage, GLsizei width, GLsizei height);
 
diff --git a/gpu/command_buffer/service/decoder_context.h b/gpu/command_buffer/service/decoder_context.h
index 0be8902..2c2ab08 100644
--- a/gpu/command_buffer/service/decoder_context.h
+++ b/gpu/command_buffer/service/decoder_context.h
@@ -27,7 +27,6 @@
 
 namespace gpu {
 class QueryManager;
-class ServiceTransferCache;
 class TextureBase;
 struct ContextCreationAttribs;
 
@@ -217,9 +216,6 @@
   //
   // Methods required by InProcessCommandBuffer
   //
-  // Gets the ServiceTransferCache for this context.
-  virtual ServiceTransferCache* GetTransferCacheForTest() = 0;
-
   // Set to true to LOG every command.
   virtual void SetLogCommands(bool log_commands) = 0;
 };
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index dca71dc..00a82d0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -21,6 +21,7 @@
 #include "base/callback_helpers.h"
 #include "base/containers/queue.h"
 #include "base/containers/span.h"
+#include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/ranges.h"
@@ -29,9 +30,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "cc/paint/color_space_transfer_cache_entry.h"
-#include "cc/paint/paint_op_buffer.h"
-#include "cc/paint/transfer_cache_entry.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
@@ -69,8 +67,6 @@
 #include "gpu/command_buffer/service/renderbuffer_manager.h"
 #include "gpu/command_buffer/service/sampler_manager.h"
 #include "gpu/command_buffer/service/service_discardable_manager.h"
-#include "gpu/command_buffer/service/service_font_manager.h"
-#include "gpu/command_buffer/service/service_transfer_cache.h"
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "gpu/command_buffer/service/shader_translator.h"
 #include "gpu/command_buffer/service/texture_manager.h"
@@ -78,14 +74,6 @@
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "third_party/angle/src/image_util/loadimage.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColorSpaceXformCanvas.h"
-#include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/core/SkSurfaceProps.h"
-#include "third_party/skia/include/core/SkTypeface.h"
-#include "third_party/skia/include/gpu/GrBackendSurface.h"
-#include "third_party/skia/include/gpu/GrContext.h"
-#include "third_party/skia/src/core/SkRemoteGlyphCache.h"
 #include "third_party/smhasher/src/City.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/color_space.h"
@@ -574,9 +562,7 @@
 
 // This class implements GLES2Decoder so we don't have to expose all the GLES2
 // cmd stuff to outside this class.
-class GLES2DecoderImpl : public GLES2Decoder,
-                         public ErrorStateClient,
-                         public ServiceFontManager::Client {
+class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
  public:
   GLES2DecoderImpl(DecoderClient* client,
                    CommandBufferServiceBase* command_buffer_service,
@@ -670,9 +656,6 @@
   ImageManager* GetImageManagerForTest() override {
     return group_->image_manager();
   }
-  ServiceTransferCache* GetTransferCacheForTest() override {
-    return transfer_cache_.get();
-  }
 
   bool HasPendingQueries() const override;
   void ProcessPendingQueries(bool did_finish) override;
@@ -757,7 +740,7 @@
   }
 
   // ServiceFontManager::Client implementation.
-  scoped_refptr<gpu::Buffer> GetShmBuffer(uint32_t shm_id) override;
+  scoped_refptr<gpu::Buffer> GetShmBuffer(uint32_t shm_id);
 
  private:
   friend class ScopedFramebufferBinder;
@@ -2039,30 +2022,6 @@
                                     GLenum textarget,
                                     GLuint texture_unit);
 
-  void DoBeginRasterCHROMIUM(GLuint texture_id,
-                             GLuint sk_color,
-                             GLuint msaa_sample_count,
-                             GLboolean can_use_lcd_text,
-                             GLint color_type,
-                             GLuint color_space_transfer_cache_id);
-  void DoRasterCHROMIUM(GLuint raster_shm_id,
-                        GLuint raster_shm_offset,
-                        GLsizeiptr raster_shm_size,
-                        GLuint font_shm_id,
-                        GLuint font_shm_offset,
-                        GLsizeiptr font_shm_size);
-  void DoEndRasterCHROMIUM();
-
-  void DoCreateTransferCacheEntryINTERNAL(GLuint entry_type,
-                                          GLuint entry_id,
-                                          GLuint handle_shm_id,
-                                          GLuint handle_shm_offset,
-                                          GLuint data_shm_id,
-                                          GLuint data_shm_offset,
-                                          GLuint data_size);
-  void DoUnlockTransferCacheEntryINTERNAL(GLuint entry_type, GLuint entry_id);
-  void DoDeleteTransferCacheEntryINTERNAL(GLuint entry_type, GLuint entry_id);
-
   void DoUnpremultiplyAndDitherCopyCHROMIUM(GLuint source_id,
                                             GLuint dest_id,
                                             GLint x,
@@ -2497,14 +2456,6 @@
 
   std::unique_ptr<VertexArrayManager> vertex_array_manager_;
 
-  // ServiceTransferCache uses Ids based on transfer buffer shm_id+offset, which
-  // are guaranteed to be unique within the scope of the TransferBufferManager
-  // which generates them. Because of this, |transfer_cache_| must have a
-  // narrower scope than |transfer_buffer_manager_|.
-  // In the future, we could add necessary scoping Id(s) to allow a single
-  // ServiceTransferCache to be shared among multiple contexts / channels.
-  std::unique_ptr<ServiceTransferCache> transfer_cache_;
-
   // The format of the back buffer_
   GLenum back_buffer_color_format_;
   bool back_buffer_has_depth_;
@@ -2549,7 +2500,6 @@
   bool supports_swap_buffers_with_bounds_;
   bool supports_commit_overlay_planes_;
   bool supports_async_swap_;
-  bool supports_oop_raster_;
   bool supports_dc_layers_ = false;
 
   // These flags are used to override the state of the shared feature_info_
@@ -2640,12 +2590,6 @@
   std::unique_ptr<CALayerSharedState> ca_layer_shared_state_;
   std::unique_ptr<DCLayerSharedState> dc_layer_shared_state_;
 
-  // Raster helpers.
-  ServiceFontManager font_manager_;
-  sk_sp<GrContext> gr_context_;
-  sk_sp<SkSurface> sk_surface_;
-  std::unique_ptr<SkCanvas> raster_canvas_;
-
   base::WeakPtrFactory<GLES2DecoderImpl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
@@ -3287,7 +3231,6 @@
       supports_swap_buffers_with_bounds_(false),
       supports_commit_overlay_planes_(false),
       supports_async_swap_(false),
-      supports_oop_raster_(false),
       derivatives_explicitly_enabled_(false),
       frag_depth_explicitly_enabled_(false),
       draw_buffers_explicitly_enabled_(false),
@@ -3310,7 +3253,6 @@
       validation_fbo_(0),
       texture_manager_service_id_generation_(0),
       force_shader_name_hashing_for_test(false),
-      font_manager_(this),
       weak_ptr_factory_(this) {
   DCHECK(client);
   DCHECK(group);
@@ -3884,49 +3826,6 @@
     api()->glHintFn(GL_TEXTURE_FILTERING_HINT_CHROMIUM, GL_NICEST);
   }
 
-  if (attrib_helper.enable_oop_rasterization) {
-    if (!features().chromium_raster_transport) {
-      LOG(ERROR) << "ContextResult::kFatalFailure: "
-                    "chromium_raster_transport not present";
-      return gpu::ContextResult::kFatalFailure;
-    }
-    // Assume that we can create a GrContext. This will be set to false if
-    // there's a failure.
-    supports_oop_raster_ = true;
-    sk_sp<const GrGLInterface> interface(
-        gl::init::CreateGrGLInterface(gl_version_info()));
-    if (!interface) {
-      DLOG(ERROR) << "OOP raster support disabled: GrGLInterface creation "
-                     "failed.";
-      supports_oop_raster_ = false;
-    }
-
-    if (supports_oop_raster_) {
-      gr_context_ = GrContext::MakeGL(std::move(interface));
-      if (gr_context_) {
-        // TODO(enne): this cache is for this decoder only and each decoder has
-        // its own cache.  This is pretty unfortunate.  This really needs to be
-        // rethought before shipping.  Most likely a different command buffer
-        // context for raster-in-gpu, with a shared gl context / gr context
-        // that different decoders can use.
-        static const int kMaxGaneshResourceCacheCount = 8196;
-        static const size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024;
-        gr_context_->setResourceCacheLimits(kMaxGaneshResourceCacheCount,
-                                            kMaxGaneshResourceCacheBytes);
-        transfer_cache_ = std::make_unique<ServiceTransferCache>();
-      } else {
-        bool was_lost = CheckResetStatus();
-        if (was_lost) {
-          DLOG(ERROR)
-              << "ContextResult::kTransientFailure: Could not create GrContext";
-          return gpu::ContextResult::kTransientFailure;
-        }
-        DLOG(ERROR) << "OOP raster support disabled: GrContext creation "
-                       "failed.";
-        supports_oop_raster_ = false;
-      }
-    }
-  }
   return gpu::ContextResult::kSuccess;
 }
 
@@ -4129,7 +4028,7 @@
   caps.texture_npot = feature_info_->feature_flags().npot_ok;
   caps.texture_storage_image =
       feature_info_->feature_flags().chromium_texture_storage_image;
-  caps.supports_oop_raster = supports_oop_raster_;
+  caps.supports_oop_raster = false;
   caps.chromium_gpu_fence = feature_info_->feature_flags().chromium_gpu_fence;
   caps.unpremultiply_and_dither_copy =
       feature_info_->feature_flags().unpremultiply_and_dither_copy;
@@ -5137,8 +5036,6 @@
 
     if (group_ && group_->texture_manager())
       group_->texture_manager()->MarkContextLost();
-    if (gr_context_)
-      gr_context_->abandonContext();
     state_.MarkContextLost();
   }
   deschedule_until_finished_fences_.clear();
@@ -5175,7 +5072,6 @@
   copy_texture_chromium_.reset();
   srgb_converter_.reset();
   clear_framebuffer_blit_.reset();
-  transfer_cache_.reset();
 
   if (framebuffer_manager_.get()) {
     framebuffer_manager_->Destroy(have_context);
@@ -20173,290 +20069,11 @@
   return error::kNoError;
 }
 
-namespace {
-
-class TransferCacheDeserializeHelperImpl
-    : public cc::TransferCacheDeserializeHelper {
- public:
-  explicit TransferCacheDeserializeHelperImpl(
-      ServiceTransferCache* transfer_cache)
-      : transfer_cache_(transfer_cache) {
-    DCHECK(transfer_cache_);
-  }
-  ~TransferCacheDeserializeHelperImpl() override = default;
-
-  void CreateLocalEntry(
-      uint32_t id,
-      std::unique_ptr<cc::ServiceTransferCacheEntry> entry) override {
-    transfer_cache_->CreateLocalEntry(id, std::move(entry));
-  }
-
- private:
-  cc::ServiceTransferCacheEntry* GetEntryInternal(
-      cc::TransferCacheEntryType entry_type,
-      uint32_t entry_id) override {
-    return transfer_cache_->GetEntry(entry_type, entry_id);
-  }
-  ServiceTransferCache* transfer_cache_;
-};
-
-}  // namespace
-
-void GLES2DecoderImpl::DoBeginRasterCHROMIUM(
-    GLuint texture_id,
-    GLuint sk_color,
-    GLuint msaa_sample_count,
-    GLboolean can_use_lcd_text,
-    GLint color_type,
-    GLuint color_space_transfer_cache_id) {
-  if (!gr_context_) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "chromium_raster_transport not enabled via attribs");
-    return;
-  }
-  if (sk_surface_) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "BeginRasterCHROMIUM without EndRasterCHROMIUM");
-    return;
-  }
-
-  DCHECK(!raster_canvas_);
-  gr_context_->resetContext();
-
-  // This function should look identical to
-  // ResourceProvider::ScopedSkSurfaceProvider.
-  GrGLTextureInfo texture_info;
-  auto* texture_ref = GetTexture(texture_id);
-  if (!texture_ref) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "unknown texture id");
-    return;
-  }
-  auto* texture = texture_ref->texture();
-  int width;
-  int height;
-  int depth;
-  if (!texture->GetLevelSize(texture->target(), 0, &width, &height, &depth)) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "missing texture size info");
-    return;
-  }
-  GLenum type;
-  GLenum internal_format;
-  if (!texture->GetLevelType(texture->target(), 0, &type, &internal_format)) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "missing texture type info");
-    return;
-  }
-  texture_info.fID = texture_ref->service_id();
-  texture_info.fTarget = texture->target();
-
-  if (texture->target() != GL_TEXTURE_2D &&
-      texture->target() != GL_TEXTURE_RECTANGLE_ARB) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "invalid texture target");
-    return;
-  }
-
-  // GetInternalFormat may return a base internal format but Skia requires a
-  // sized internal format. So this may be adjusted below.
-  texture_info.fFormat = GetInternalFormat(&gl_version_info(), internal_format);
-  switch (color_type) {
-    case kARGB_4444_SkColorType:
-      if (internal_format != GL_RGBA4 && internal_format != GL_RGBA) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                           "color type mismatch");
-        return;
-      }
-      if (texture_info.fFormat == GL_RGBA)
-        texture_info.fFormat = GL_RGBA4;
-      break;
-    case kRGBA_8888_SkColorType:
-      if (internal_format != GL_RGBA8_OES && internal_format != GL_RGBA) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                           "color type mismatch");
-        return;
-      }
-      if (texture_info.fFormat == GL_RGBA)
-        texture_info.fFormat = GL_RGBA8_OES;
-      break;
-    case kBGRA_8888_SkColorType:
-      if (internal_format != GL_BGRA_EXT && internal_format != GL_BGRA8_EXT) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                           "color type mismatch");
-        return;
-      }
-      if (texture_info.fFormat == GL_BGRA_EXT)
-        texture_info.fFormat = GL_BGRA8_EXT;
-      if (texture_info.fFormat == GL_RGBA)
-        texture_info.fFormat = GL_RGBA8_OES;
-      break;
-    default:
-      LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                         "unsupported color type");
-      return;
-  }
-
-  GrBackendTexture gr_texture(width, height, GrMipMapped::kNo, texture_info);
-
-  uint32_t flags = 0;
-
-  // Use unknown pixel geometry to disable LCD text.
-  SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
-  if (can_use_lcd_text) {
-    // LegacyFontHost will get LCD text and skia figures out what type to use.
-    surface_props =
-        SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
-  }
-
-  SkColorType sk_color_type = static_cast<SkColorType>(color_type);
-  // If we can't match requested MSAA samples, don't use MSAA.
-  int final_msaa_count = std::max(static_cast<int>(msaa_sample_count), 0);
-  if (final_msaa_count >
-      gr_context_->maxSurfaceSampleCountForColorType(sk_color_type))
-    final_msaa_count = 0;
-  sk_surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
-      gr_context_.get(), gr_texture, kTopLeft_GrSurfaceOrigin, final_msaa_count,
-      sk_color_type, nullptr, &surface_props);
-
-  if (!sk_surface_) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "failed to create surface");
-    return;
-  }
-
-  TransferCacheDeserializeHelperImpl transfer_cache_deserializer(
-      transfer_cache_.get());
-  auto* color_space_entry =
-      transfer_cache_deserializer
-          .GetEntryAs<cc::ServiceColorSpaceTransferCacheEntry>(
-              color_space_transfer_cache_id);
-  if (!color_space_entry || !color_space_entry->color_space().IsValid()) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "failed to find valid color space");
-    return;
-  }
-  raster_canvas_ = SkCreateColorSpaceXformCanvas(
-      sk_surface_->getCanvas(),
-      color_space_entry->color_space().ToSkColorSpace());
-
-  // All or nothing clearing, as no way to validate the client's input on what
-  // is the "used" part of the texture.
-  if (texture->IsLevelCleared(texture->target(), 0))
-    return;
-
-  // TODO(enne): this doesn't handle the case where the background color
-  // changes and so any extra pixels outside the raster area that get
-  // sampled may be incorrect.
-  raster_canvas_->drawColor(sk_color);
-  texture_manager()->SetLevelCleared(texture_ref, texture->target(), 0, true);
-}
 
 scoped_refptr<gpu::Buffer> GLES2DecoderImpl::GetShmBuffer(uint32_t shm_id) {
   return GetSharedMemoryBuffer(shm_id);
 }
 
-void GLES2DecoderImpl::DoRasterCHROMIUM(GLuint raster_shm_id,
-                                        GLuint raster_shm_offset,
-                                        GLsizeiptr raster_shm_size,
-                                        GLuint font_shm_id,
-                                        GLuint font_shm_offset,
-                                        GLsizeiptr font_shm_size) {
-  TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoRasterCHROMIUM");
-
-  if (!sk_surface_) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glRasterCHROMIUM",
-                       "RasterCHROMIUM without BeginRasterCHROMIUM");
-    return;
-  }
-  DCHECK(transfer_cache_);
-
-  std::vector<SkDiscardableHandleId> locked_handles;
-  if (font_shm_size > 0) {
-    // Deserialize fonts before raster.
-    volatile char* font_buffer_memory =
-        GetSharedMemoryAs<char*>(font_shm_id, font_shm_offset, font_shm_size);
-    if (!font_buffer_memory) {
-      LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRasterCHROMIUM",
-                         "Can not read font buffer.");
-      return;
-    }
-
-    if (!font_manager_.Deserialize(font_buffer_memory, font_shm_size,
-                                   &locked_handles)) {
-      LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRasterCHROMIUM",
-                         "Invalid font buffer.");
-      return;
-    }
-  }
-
-  char* paint_buffer_memory = GetSharedMemoryAs<char*>(
-      raster_shm_id, raster_shm_offset, raster_shm_size);
-  if (!paint_buffer_memory) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRasterCHROMIUM",
-                       "Can not read paint buffer.");
-    return;
-  }
-
-  alignas(
-      cc::PaintOpBuffer::PaintOpAlign) char data[sizeof(cc::LargestPaintOp)];
-
-  SkCanvas* canvas = raster_canvas_.get();
-  SkMatrix original_ctm;
-  cc::PlaybackParams playback_params(nullptr, original_ctm);
-  cc::PaintOp::DeserializeOptions options;
-  TransferCacheDeserializeHelperImpl impl(transfer_cache_.get());
-  options.transfer_cache = &impl;
-  options.strike_client = font_manager_.strike_client();
-
-  int op_idx = 0;
-  size_t paint_buffer_size = raster_shm_size;
-  while (paint_buffer_size > 4) {
-    size_t skip = 0;
-    cc::PaintOp* deserialized_op = cc::PaintOp::Deserialize(
-        paint_buffer_memory, paint_buffer_size, &data[0],
-        sizeof(cc::LargestPaintOp), &skip, options);
-    if (!deserialized_op) {
-      std::string msg =
-          base::StringPrintf("RasterCHROMIUM: bad op: %i", op_idx);
-      LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glRasterCHROMIUM", msg.c_str());
-      return;
-    }
-
-    deserialized_op->Raster(canvas, playback_params);
-    deserialized_op->DestroyThis();
-
-    paint_buffer_size -= skip;
-    paint_buffer_memory += skip;
-    op_idx++;
-  }
-
-  // Unlock all font handles.
-  // TODO(khushalsagar): We just unlocked a bunch of handles, do we need to give
-  // a call to skia to attempt to purge any unlocked handles?
-  if (!font_manager_.Unlock(locked_handles)) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRasterCHROMIUM",
-                       "Invalid font discardable handle.");
-  }
-}
-
-void GLES2DecoderImpl::DoEndRasterCHROMIUM() {
-  if (!sk_surface_) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginRasterCHROMIUM",
-                       "EndRasterCHROMIUM without BeginRasterCHROMIUM");
-    return;
-  }
-
-  raster_canvas_ = nullptr;
-  sk_surface_->prepareForExternalIO();
-  sk_surface_.reset();
-
-  // It is important to reset state after each RasterCHROMIUM since skia can
-  // change the GL state which can invalidate the tracking done in this
-  // decoder.
-  RestoreState(nullptr);
-}
-
 void GLES2DecoderImpl::DoWindowRectanglesEXT(GLenum mode,
                                              GLsizei n,
                                              const volatile GLint* box) {
@@ -20478,109 +20095,6 @@
   state_.UpdateWindowRectangles();
 }
 
-void GLES2DecoderImpl::DoCreateTransferCacheEntryINTERNAL(
-    GLuint raw_entry_type,
-    GLuint entry_id,
-    GLuint handle_shm_id,
-    GLuint handle_shm_offset,
-    GLuint data_shm_id,
-    GLuint data_shm_offset,
-    GLuint data_size) {
-  if (!supports_oop_raster_) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, "glCreateTransferCacheEntryINTERNAL",
-        "Attempt to use OOP transfer cache on a context without OOP raster.");
-    return;
-  }
-  DCHECK(gr_context_);
-  DCHECK(transfer_cache_);
-
-  // Validate the type we are about to create.
-  cc::TransferCacheEntryType entry_type;
-  if (!cc::ServiceTransferCacheEntry::SafeConvertToType(raw_entry_type,
-                                                        &entry_type)) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, "glCreateTransferCacheEntryINTERNAL",
-        "Attempt to use OOP transfer cache with an invalid cache entry type.");
-    return;
-  }
-
-  uint8_t* data_memory =
-      GetSharedMemoryAs<uint8_t*>(data_shm_id, data_shm_offset, data_size);
-  if (!data_memory) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCreateTransferCacheEntryINTERNAL",
-                       "Can not read transfer cache entry data.");
-    return;
-  }
-
-  scoped_refptr<gpu::Buffer> handle_buffer =
-      GetSharedMemoryBuffer(handle_shm_id);
-  if (!DiscardableHandleBase::ValidateParameters(handle_buffer.get(),
-                                                 handle_shm_offset)) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCreateTransferCacheEntryINTERNAL",
-                       "Invalid shm for discardable handle.");
-    return;
-  }
-  ServiceDiscardableHandle handle(std::move(handle_buffer), handle_shm_offset,
-                                  handle_shm_id);
-
-  if (!transfer_cache_->CreateLockedEntry(
-          entry_type, entry_id, handle, gr_context_.get(),
-          base::make_span(data_memory, data_size))) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCreateTransferCacheEntryINTERNAL",
-                       "Failure to deserialize transfer cache entry.");
-    return;
-  }
-}
-
-void GLES2DecoderImpl::DoUnlockTransferCacheEntryINTERNAL(GLuint raw_entry_type,
-                                                          GLuint entry_id) {
-  if (!supports_oop_raster_) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, "glUnlockTransferCacheEntryINTERNAL",
-        "Attempt to use OOP transfer cache on a context without OOP raster.");
-    return;
-  }
-  DCHECK(transfer_cache_);
-  cc::TransferCacheEntryType entry_type;
-  if (!cc::ServiceTransferCacheEntry::SafeConvertToType(raw_entry_type,
-                                                        &entry_type)) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, "glUnlockTransferCacheEntryINTERNAL",
-        "Attempt to use OOP transfer cache with an invalid cache entry type.");
-    return;
-  }
-
-  if (!transfer_cache_->UnlockEntry(entry_type, entry_id)) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glUnlockTransferCacheEntryINTERNAL",
-                       "Attempt to unlock an invalid ID");
-  }
-}
-
-void GLES2DecoderImpl::DoDeleteTransferCacheEntryINTERNAL(GLuint raw_entry_type,
-                                                          GLuint entry_id) {
-  if (!supports_oop_raster_) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, "glDeleteTransferCacheEntryINTERNAL",
-        "Attempt to use OOP transfer cache on a context without OOP raster.");
-    return;
-  }
-  DCHECK(transfer_cache_);
-  cc::TransferCacheEntryType entry_type;
-  if (!cc::ServiceTransferCacheEntry::SafeConvertToType(raw_entry_type,
-                                                        &entry_type)) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, "glDeleteTransferCacheEntryINTERNAL",
-        "Attempt to use OOP transfer cache with an invalid cache entry type.");
-    return;
-  }
-
-  if (!transfer_cache_->DeleteEntry(entry_type, entry_id)) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glDeleteTransferCacheEntryINTERNAL",
-                       "Attempt to delete an invalid ID");
-  }
-}
-
 void GLES2DecoderImpl::DoUnpremultiplyAndDitherCopyCHROMIUM(GLuint source_id,
                                                             GLuint dest_id,
                                                             GLint x,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 1ed0b20..0e00579 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5186,115 +5186,6 @@
   return error::kNoError;
 }
 
-error::Error GLES2DecoderImpl::HandleBeginRasterCHROMIUM(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::BeginRasterCHROMIUM& c =
-      *static_cast<const volatile gles2::cmds::BeginRasterCHROMIUM*>(cmd_data);
-  if (!features().chromium_raster_transport) {
-    return error::kUnknownCommand;
-  }
-
-  GLuint texture_id = static_cast<GLuint>(c.texture_id);
-  GLuint sk_color = static_cast<GLuint>(c.sk_color);
-  GLuint msaa_sample_count = static_cast<GLuint>(c.msaa_sample_count);
-  GLboolean can_use_lcd_text = static_cast<GLboolean>(c.can_use_lcd_text);
-  GLint color_type = static_cast<GLint>(c.color_type);
-  GLuint color_space_transfer_cache_id =
-      static_cast<GLuint>(c.color_space_transfer_cache_id);
-  DoBeginRasterCHROMIUM(texture_id, sk_color, msaa_sample_count,
-                        can_use_lcd_text, color_type,
-                        color_space_transfer_cache_id);
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleRasterCHROMIUM(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::RasterCHROMIUM& c =
-      *static_cast<const volatile gles2::cmds::RasterCHROMIUM*>(cmd_data);
-  if (!features().chromium_raster_transport) {
-    return error::kUnknownCommand;
-  }
-
-  GLuint raster_shm_id = static_cast<GLuint>(c.raster_shm_id);
-  GLuint raster_shm_offset = static_cast<GLuint>(c.raster_shm_offset);
-  GLsizeiptr raster_shm_size = static_cast<GLsizeiptr>(c.raster_shm_size);
-  GLuint font_shm_id = static_cast<GLuint>(c.font_shm_id);
-  GLuint font_shm_offset = static_cast<GLuint>(c.font_shm_offset);
-  GLsizeiptr font_shm_size = static_cast<GLsizeiptr>(c.font_shm_size);
-  if (raster_shm_size < 0) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRasterCHROMIUM",
-                       "raster_shm_size < 0");
-    return error::kNoError;
-  }
-  if (font_shm_size < 0) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRasterCHROMIUM",
-                       "font_shm_size < 0");
-    return error::kNoError;
-  }
-  DoRasterCHROMIUM(raster_shm_id, raster_shm_offset, raster_shm_size,
-                   font_shm_id, font_shm_offset, font_shm_size);
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleEndRasterCHROMIUM(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  if (!features().chromium_raster_transport) {
-    return error::kUnknownCommand;
-  }
-
-  DoEndRasterCHROMIUM();
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleCreateTransferCacheEntryINTERNAL(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::CreateTransferCacheEntryINTERNAL& c =
-      *static_cast<
-          const volatile gles2::cmds::CreateTransferCacheEntryINTERNAL*>(
-          cmd_data);
-  GLuint entry_type = static_cast<GLuint>(c.entry_type);
-  GLuint entry_id = static_cast<GLuint>(c.entry_id);
-  GLuint handle_shm_id = static_cast<GLuint>(c.handle_shm_id);
-  GLuint handle_shm_offset = static_cast<GLuint>(c.handle_shm_offset);
-  GLuint data_shm_id = static_cast<GLuint>(c.data_shm_id);
-  GLuint data_shm_offset = static_cast<GLuint>(c.data_shm_offset);
-  GLuint data_size = static_cast<GLuint>(c.data_size);
-  DoCreateTransferCacheEntryINTERNAL(entry_type, entry_id, handle_shm_id,
-                                     handle_shm_offset, data_shm_id,
-                                     data_shm_offset, data_size);
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleDeleteTransferCacheEntryINTERNAL(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::DeleteTransferCacheEntryINTERNAL& c =
-      *static_cast<
-          const volatile gles2::cmds::DeleteTransferCacheEntryINTERNAL*>(
-          cmd_data);
-  GLuint entry_type = static_cast<GLuint>(c.entry_type);
-  GLuint entry_id = static_cast<GLuint>(c.entry_id);
-  DoDeleteTransferCacheEntryINTERNAL(entry_type, entry_id);
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleUnlockTransferCacheEntryINTERNAL(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::UnlockTransferCacheEntryINTERNAL& c =
-      *static_cast<
-          const volatile gles2::cmds::UnlockTransferCacheEntryINTERNAL*>(
-          cmd_data);
-  GLuint entry_type = static_cast<GLuint>(c.entry_type);
-  GLuint entry_id = static_cast<GLuint>(c.entry_id);
-  DoUnlockTransferCacheEntryINTERNAL(entry_type, entry_id);
-  return error::kNoError;
-}
-
 error::Error GLES2DecoderImpl::HandleTexStorage2DImageCHROMIUM(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 21366933..53fc3af 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -100,7 +100,6 @@
       GetTransformFeedbackManager, gpu::gles2::TransformFeedbackManager*());
   MOCK_METHOD0(GetVertexArrayManager, gpu::gles2::VertexArrayManager*());
   MOCK_METHOD0(GetImageManagerForTest, gpu::gles2::ImageManager*());
-  MOCK_METHOD0(GetTransferCacheForTest, gpu::ServiceTransferCache*());
   MOCK_METHOD1(
       SetResizeCallback, void(const base::Callback<void(gfx::Size, float)>&));
   MOCK_METHOD1(SetIgnoreCachedStateForTest, void(bool ignore));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index 5a7f0fa..ed5d2dbe 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -4,6 +4,9 @@
 
 #include "gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h"
 
+#include <string>
+#include <utility>
+
 #include "base/callback.h"
 #include "base/strings/string_split.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
@@ -43,7 +46,7 @@
   }
   *result = static_cast<ResultType>(client_id);
   return true;
-};
+}
 
 void ResizeRenderbuffer(gl::GLApi* api,
                         GLuint renderbuffer,
@@ -1226,7 +1229,6 @@
 }
 
 void GLES2DecoderPassthroughImpl::RestoreState(const ContextState* prev_state) {
-
 }
 
 void GLES2DecoderPassthroughImpl::RestoreActiveTexture() const {}
@@ -1268,7 +1270,6 @@
 void GLES2DecoderPassthroughImpl::SetIgnoreCachedStateForTest(bool ignore) {}
 
 void GLES2DecoderPassthroughImpl::SetForceShaderNameHashingForTest(bool force) {
-
 }
 
 size_t GLES2DecoderPassthroughImpl::GetSavedBackTextureCountForTest() {
@@ -1307,10 +1308,6 @@
   return group_->image_manager();
 }
 
-ServiceTransferCache* GLES2DecoderPassthroughImpl::GetTransferCacheForTest() {
-  return nullptr;
-}
-
 bool GLES2DecoderPassthroughImpl::HasPendingQueries() const {
   return !pending_queries_.empty();
 }
@@ -1633,8 +1630,8 @@
   }
 
   // Buffer is mapped, patch the result with the original access flags
-  DCHECK(bufsize >= 1);
-  DCHECK(*length == 1);
+  DCHECK_GE(bufsize, 1);
+  DCHECK_EQ(*length, 1);
   params[0] = mapped_buffer_info_iter->second.original_access;
   return error::kNoError;
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index d5265a9..67ebd52c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -7,6 +7,12 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_PASSTHROUGH_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_PASSTHROUGH_H_
 
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
 #include "base/containers/circular_deque.h"
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
@@ -216,8 +222,6 @@
   // Gets the ImageManager for this context.
   ImageManager* GetImageManagerForTest() override;
 
-  ServiceTransferCache* GetTransferCacheForTest() override;
-
   // Returns false if there are no pending queries.
   bool HasPendingQueries() const override;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 2a43665..9291238 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -4550,127 +4550,6 @@
   return error::kNoError;
 }
 
-error::Error GLES2DecoderPassthroughImpl::HandleBeginRasterCHROMIUM(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::BeginRasterCHROMIUM& c =
-      *static_cast<const volatile gles2::cmds::BeginRasterCHROMIUM*>(cmd_data);
-  if (!features().chromium_raster_transport) {
-    return error::kUnknownCommand;
-  }
-
-  GLuint texture_id = static_cast<GLuint>(c.texture_id);
-  GLuint sk_color = static_cast<GLuint>(c.sk_color);
-  GLuint msaa_sample_count = static_cast<GLuint>(c.msaa_sample_count);
-  GLboolean can_use_lcd_text = static_cast<GLboolean>(c.can_use_lcd_text);
-  GLint color_type = static_cast<GLint>(c.color_type);
-  GLuint color_space_transfer_cache_id =
-      static_cast<GLuint>(c.color_space_transfer_cache_id);
-  error::Error error = DoBeginRasterCHROMIUM(
-      texture_id, sk_color, msaa_sample_count, can_use_lcd_text, color_type,
-      color_space_transfer_cache_id);
-  if (error != error::kNoError) {
-    return error;
-  }
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderPassthroughImpl::HandleRasterCHROMIUM(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::RasterCHROMIUM& c =
-      *static_cast<const volatile gles2::cmds::RasterCHROMIUM*>(cmd_data);
-  if (!features().chromium_raster_transport) {
-    return error::kUnknownCommand;
-  }
-
-  GLuint raster_shm_id = static_cast<GLuint>(c.raster_shm_id);
-  GLuint raster_shm_offset = static_cast<GLuint>(c.raster_shm_offset);
-  GLsizeiptr raster_shm_size = static_cast<GLsizeiptr>(c.raster_shm_size);
-  GLuint font_shm_id = static_cast<GLuint>(c.font_shm_id);
-  GLuint font_shm_offset = static_cast<GLuint>(c.font_shm_offset);
-  GLsizeiptr font_shm_size = static_cast<GLsizeiptr>(c.font_shm_size);
-  error::Error error =
-      DoRasterCHROMIUM(raster_shm_id, raster_shm_offset, raster_shm_size,
-                       font_shm_id, font_shm_offset, font_shm_size);
-  if (error != error::kNoError) {
-    return error;
-  }
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderPassthroughImpl::HandleEndRasterCHROMIUM(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  if (!features().chromium_raster_transport) {
-    return error::kUnknownCommand;
-  }
-
-  error::Error error = DoEndRasterCHROMIUM();
-  if (error != error::kNoError) {
-    return error;
-  }
-  return error::kNoError;
-}
-
-error::Error
-GLES2DecoderPassthroughImpl::HandleCreateTransferCacheEntryINTERNAL(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::CreateTransferCacheEntryINTERNAL& c =
-      *static_cast<
-          const volatile gles2::cmds::CreateTransferCacheEntryINTERNAL*>(
-          cmd_data);
-  GLuint entry_type = static_cast<GLuint>(c.entry_type);
-  GLuint entry_id = static_cast<GLuint>(c.entry_id);
-  GLuint handle_shm_id = static_cast<GLuint>(c.handle_shm_id);
-  GLuint handle_shm_offset = static_cast<GLuint>(c.handle_shm_offset);
-  GLuint data_shm_id = static_cast<GLuint>(c.data_shm_id);
-  GLuint data_shm_offset = static_cast<GLuint>(c.data_shm_offset);
-  GLuint data_size = static_cast<GLuint>(c.data_size);
-  error::Error error = DoCreateTransferCacheEntryINTERNAL(
-      entry_type, entry_id, handle_shm_id, handle_shm_offset, data_shm_id,
-      data_shm_offset, data_size);
-  if (error != error::kNoError) {
-    return error;
-  }
-  return error::kNoError;
-}
-
-error::Error
-GLES2DecoderPassthroughImpl::HandleDeleteTransferCacheEntryINTERNAL(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::DeleteTransferCacheEntryINTERNAL& c =
-      *static_cast<
-          const volatile gles2::cmds::DeleteTransferCacheEntryINTERNAL*>(
-          cmd_data);
-  GLuint entry_type = static_cast<GLuint>(c.entry_type);
-  GLuint entry_id = static_cast<GLuint>(c.entry_id);
-  error::Error error = DoDeleteTransferCacheEntryINTERNAL(entry_type, entry_id);
-  if (error != error::kNoError) {
-    return error;
-  }
-  return error::kNoError;
-}
-
-error::Error
-GLES2DecoderPassthroughImpl::HandleUnlockTransferCacheEntryINTERNAL(
-    uint32_t immediate_data_size,
-    const volatile void* cmd_data) {
-  const volatile gles2::cmds::UnlockTransferCacheEntryINTERNAL& c =
-      *static_cast<
-          const volatile gles2::cmds::UnlockTransferCacheEntryINTERNAL*>(
-          cmd_data);
-  GLuint entry_type = static_cast<GLuint>(c.entry_type);
-  GLuint entry_id = static_cast<GLuint>(c.entry_id);
-  error::Error error = DoUnlockTransferCacheEntryINTERNAL(entry_type, entry_id);
-  if (error != error::kNoError) {
-    return error;
-  }
-  return error::kNoError;
-}
-
 error::Error GLES2DecoderPassthroughImpl::HandleTexStorage2DImageCHROMIUM(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 25e2fd6..29b4b12 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -947,6 +947,9 @@
     if (group_ && group_->texture_manager()) {
       group_->texture_manager()->MarkContextLost();
     }
+    if (gr_context_) {
+      gr_context_->abandonContext();
+    }
     state_.MarkContextLost();
   }
 
diff --git a/gpu/command_buffer/service/raster_decoder.h b/gpu/command_buffer/service/raster_decoder.h
index cd1afdf..c2ce9cc5c 100644
--- a/gpu/command_buffer/service/raster_decoder.h
+++ b/gpu/command_buffer/service/raster_decoder.h
@@ -13,6 +13,7 @@
 namespace gpu {
 
 class DecoderClient;
+class ServiceTransferCache;
 
 namespace gles2 {
 class CopyTextureCHROMIUMResourceManager;
@@ -73,6 +74,8 @@
       gles2::CopyTextureCHROMIUMResourceManager*
           copy_texture_resource_manager) = 0;
 
+  virtual ServiceTransferCache* GetTransferCacheForTest() = 0;
+
  protected:
   RasterDecoder(CommandBufferServiceBase* command_buffer_service);
 
diff --git a/gpu/ipc/gl_in_process_context.cc b/gpu/ipc/gl_in_process_context.cc
index 9837987..d3da675c 100644
--- a/gpu/ipc/gl_in_process_context.cc
+++ b/gpu/ipc/gl_in_process_context.cc
@@ -64,7 +64,6 @@
   void SetPresentationCallback(
       const InProcessCommandBuffer::PresentationCallback& callback) override;
   void SetLock(base::Lock* lock) override;
-  ServiceTransferCache* GetTransferCacheForTest() const override;
 
  private:
   std::unique_ptr<gles2::GLES2CmdHelper> gles2_helper_;
@@ -120,10 +119,6 @@
   NOTREACHED();
 }
 
-ServiceTransferCache* GLInProcessContextImpl::GetTransferCacheForTest() const {
-  return command_buffer_->GetTransferCacheForTest();
-}
-
 ContextResult GLInProcessContextImpl::Initialize(
     scoped_refptr<InProcessCommandBuffer::Service> service,
     scoped_refptr<gl::GLSurface> surface,
diff --git a/gpu/ipc/gl_in_process_context.h b/gpu/ipc/gl_in_process_context.h
index bf4cec82..160c3b2 100644
--- a/gpu/ipc/gl_in_process_context.h
+++ b/gpu/ipc/gl_in_process_context.h
@@ -16,7 +16,6 @@
 
 namespace gpu {
 struct GpuFeatureInfo;
-class ServiceTransferCache;
 struct SharedMemoryLimits;
 
 namespace gles2 {
@@ -67,9 +66,6 @@
 
   virtual void SetPresentationCallback(
       const InProcessCommandBuffer::PresentationCallback& callback) = 0;
-
-  // Test only functions.
-  virtual ServiceTransferCache* GetTransferCacheForTest() const = 0;
 };
 
 }  // namespace gpu
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 8a1e7f3..cca06289 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -238,6 +238,12 @@
   g_default_service.Get().SetGpuFeatureInfo(gpu_feature_info);
 }
 
+gpu::ServiceTransferCache* InProcessCommandBuffer::GetTransferCacheForTest()
+    const {
+  return static_cast<raster::RasterDecoder*>(decoder_.get())
+      ->GetTransferCacheForTest();
+}
+
 bool InProcessCommandBuffer::MakeCurrent() {
   CheckSequencedThread();
   command_buffer_lock_.AssertAcquired();
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index d3e7ea6..5f111d2 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -209,9 +209,7 @@
   static void InitializeDefaultServiceForTesting(
       const GpuFeatureInfo& gpu_feature_info);
 
-  gpu::ServiceTransferCache* GetTransferCacheForTest() const {
-    return decoder_->GetTransferCacheForTest();
-  }
+  gpu::ServiceTransferCache* GetTransferCacheForTest() const;
 
   static const int kGpuMemoryBufferClientId;
 
diff --git a/gpu/ipc/raster_in_process_context.cc b/gpu/ipc/raster_in_process_context.cc
index 8504141..d45bfdd 100644
--- a/gpu/ipc/raster_in_process_context.cc
+++ b/gpu/ipc/raster_in_process_context.cc
@@ -20,7 +20,6 @@
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_switches.h"
 #include "gpu/ipc/common/surface_handle.h"
-#include "gpu/skia_bindings/gles2_implementation_with_grcontext_support.h"
 
 namespace gpu {
 
@@ -36,11 +35,6 @@
     raster_implementation_->Flush();
     raster_implementation_.reset();
   }
-  if (gles2_implementation_) {
-    gles2_implementation_->Flush();
-    gles2_implementation_.reset();
-  }
-
   transfer_buffer_.reset();
   helper_.reset();
   command_buffer_.reset();
@@ -58,6 +52,10 @@
   if (!attribs.enable_raster_interface) {
     return ContextResult::kFatalFailure;
   }
+  DCHECK(!attribs.enable_gles2_interface);
+  if (attribs.enable_gles2_interface) {
+    return ContextResult::kFatalFailure;
+  }
 
   // TODO(backer): Remove this. Currently used to set
   // |chromium_raster_transport| features flag (https://crbug.com/786591) and
@@ -82,52 +80,28 @@
   // Check for consistency.
   DCHECK(!attribs.bind_generates_resource);
   constexpr bool bind_generates_resource = false;
-  constexpr bool support_client_side_arrays = false;
 
-  if (attribs.enable_gles2_interface) {
-    auto gles2_helper =
-        std::make_unique<gles2::GLES2CmdHelper>(command_buffer_.get());
-    result = gles2_helper->Initialize(memory_limits.command_buffer_size);
-    if (result != ContextResult::kSuccess) {
-      LOG(ERROR) << "Failed to initialize GLES2CmdHelper";
-      return result;
-    }
-    transfer_buffer_ = std::make_unique<TransferBuffer>(gles2_helper.get());
+  // TODO(https://crbug.com/829469): Remove check once we fuzz RasterDecoder.
+  // enable_oop_rasterization is currently necessary to create RasterDecoder
+  // in InProcessCommandBuffer.
+  DCHECK(attribs.enable_oop_rasterization);
 
-    // Create the object exposing the OpenGL API.
-    gles2_implementation_ = std::make_unique<
-        skia_bindings::GLES2ImplementationWithGrContextSupport>(
-        gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer_.get(),
-        bind_generates_resource, attribs.lose_context_when_out_of_memory,
-        support_client_side_arrays, command_buffer_.get());
-    result = gles2_implementation_->Initialize(memory_limits);
-    raster_implementation_ = std::make_unique<raster::RasterImplementationGLES>(
-        gles2_implementation_.get(), gles2_implementation_.get(),
-        gles2_implementation_->command_buffer(), GetCapabilities());
-    helper_ = std::move(gles2_helper);
-  } else {
-    // TODO(https://crbug.com/829469): Remove check once we fuzz RasterDecoder.
-    // enable_oop_rasterization is currently necessary to create RasterDecoder
-    // in InProcessCommandBuffer.
-    DCHECK(attribs.enable_oop_rasterization);
-
-    // Create the RasterCmdHelper, which writes the command buffer protocol.
-    auto raster_helper =
-        std::make_unique<raster::RasterCmdHelper>(command_buffer_.get());
-    result = raster_helper->Initialize(memory_limits.command_buffer_size);
-    if (result != ContextResult::kSuccess) {
-      LOG(ERROR) << "Failed to initialize RasterCmdHelper";
-      return result;
-    }
-    transfer_buffer_ = std::make_unique<TransferBuffer>(raster_helper.get());
-
-    auto raster_implementation = std::make_unique<raster::RasterImplementation>(
-        raster_helper.get(), transfer_buffer_.get(), bind_generates_resource,
-        attribs.lose_context_when_out_of_memory, command_buffer_.get());
-    result = raster_implementation->Initialize(memory_limits);
-    raster_implementation_ = std::move(raster_implementation);
-    helper_ = std::move(raster_helper);
+  // Create the RasterCmdHelper, which writes the command buffer protocol.
+  auto raster_helper =
+      std::make_unique<raster::RasterCmdHelper>(command_buffer_.get());
+  result = raster_helper->Initialize(memory_limits.command_buffer_size);
+  if (result != ContextResult::kSuccess) {
+    LOG(ERROR) << "Failed to initialize RasterCmdHelper";
+    return result;
   }
+  transfer_buffer_ = std::make_unique<TransferBuffer>(raster_helper.get());
+
+  auto raster_implementation = std::make_unique<raster::RasterImplementation>(
+      raster_helper.get(), transfer_buffer_.get(), bind_generates_resource,
+      attribs.lose_context_when_out_of_memory, command_buffer_.get());
+  result = raster_implementation->Initialize(memory_limits);
+  raster_implementation_ = std::move(raster_implementation);
+  helper_ = std::move(raster_helper);
   return result;
 }
 
@@ -144,12 +118,7 @@
 }
 
 ContextSupport* RasterInProcessContext::GetContextSupport() {
-  if (gles2_implementation_) {
-    return gles2_implementation_.get();
-  } else {
-    return static_cast<raster::RasterImplementation*>(
-        raster_implementation_.get());
-  }
+  return raster_implementation_.get();
 }
 
 ServiceTransferCache* RasterInProcessContext::GetTransferCacheForTest() const {
diff --git a/gpu/ipc/raster_in_process_context.h b/gpu/ipc/raster_in_process_context.h
index aa34d8b51..ee9be759 100644
--- a/gpu/ipc/raster_in_process_context.h
+++ b/gpu/ipc/raster_in_process_context.h
@@ -20,12 +20,9 @@
 struct GpuFeatureInfo;
 struct SharedMemoryLimits;
 
-namespace gles2 {
-class GLES2Implementation;
-}
-
 namespace raster {
 class RasterInterface;
+class RasterImplementation;
 }  // namespace raster
 
 // Runs client and server side command buffer code in process. Only supports
@@ -62,12 +59,7 @@
  private:
   std::unique_ptr<CommandBufferHelper> helper_;
   std::unique_ptr<TransferBuffer> transfer_buffer_;
-  std::unique_ptr<raster::RasterInterface> raster_implementation_;
-
-  // TODO(backer): Nix this once RasterDecoder launches.
-  // Only created if attribs.enable_gles2_interface.
-  std::unique_ptr<gles2::GLES2Implementation> gles2_implementation_;
-
+  std::unique_ptr<raster::RasterImplementation> raster_implementation_;
   std::unique_ptr<InProcessCommandBuffer> command_buffer_;
 
   DISALLOW_COPY_AND_ASSIGN(RasterInProcessContext);
diff --git a/gpu/skia_bindings/gles2_implementation_with_grcontext_support.cc b/gpu/skia_bindings/gles2_implementation_with_grcontext_support.cc
index 37820e9b..1d1e0c6 100644
--- a/gpu/skia_bindings/gles2_implementation_with_grcontext_support.cc
+++ b/gpu/skia_bindings/gles2_implementation_with_grcontext_support.cc
@@ -4,6 +4,8 @@
 
 #include "gpu/skia_bindings/gles2_implementation_with_grcontext_support.h"
 
+#include <utility>
+
 #include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "third_party/skia/include/gpu/GrContext.h"
@@ -54,13 +56,6 @@
   using_gl_from_skia_ = false;
 }
 
-void GLES2ImplementationWithGrContextSupport::EndRasterCHROMIUM() {
-  BaseClass::EndRasterCHROMIUM();
-  // Assume that invoking the GLES2-backed version of the raster interface
-  // invalidates everything.
-  ResetGrContextIfNeeded(kALL_GrGLBackendState);
-}
-
 // Calls that invalidate kRenderTarget_GrGLBackendState
 void GLES2ImplementationWithGrContextSupport::BindFramebuffer(
     GLenum target,
diff --git a/gpu/skia_bindings/gles2_implementation_with_grcontext_support.h b/gpu/skia_bindings/gles2_implementation_with_grcontext_support.h
index baadbeef..01cacea 100644
--- a/gpu/skia_bindings/gles2_implementation_with_grcontext_support.h
+++ b/gpu/skia_bindings/gles2_implementation_with_grcontext_support.h
@@ -38,9 +38,6 @@
   // These must be kept in sync with the invalidation defines in
   // GrGLGpu::onResetContext()
 
-  // Calls that invalidate arbitrary state
-  void EndRasterCHROMIUM() override;
-
   // Calls that invalidate kRenderTarget_GrGLBackendState
   void BindFramebuffer(GLenum target, GLuint framebuffer) override;
   void BindRenderbuffer(GLenum target, GLuint renderbuffer) override;
@@ -193,4 +190,4 @@
 
 }  // namespace skia_bindings
 
-#endif
+#endif  // GPU_SKIA_BINDINGS_GLES2_IMPLEMENTATION_WITH_GRCONTEXT_SUPPORT_H_
diff --git a/infra/config/global/luci-milo-dev.cfg b/infra/config/global/luci-milo-dev.cfg
index 518f5677..e066ff7 100644
--- a/infra/config/global/luci-milo-dev.cfg
+++ b/infra/config/global/luci-milo-dev.cfg
@@ -1258,11 +1258,6 @@
     short_name: "32"
   }
   builders: {
-    name: "buildbot/chromium.perf/Win 7 Intel GPU Perf"
-    category: "perf|win|7"
-    short_name: "int"
-  }
-  builders: {
     name: "buildbot/chromium.perf/Win 7 Nvidia GPU Perf"
     category: "perf|win|7"
     short_name: "nvi"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 65f17d7..f9f3be9 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -1318,11 +1318,6 @@
     short_name: "32"
   }
   builders: {
-    name: "buildbot/chromium.perf/Win 7 Intel GPU Perf"
-    category: "perf|win|7"
-    short_name: "int"
-  }
-  builders: {
     name: "buildbot/chromium.perf/Win 7 Nvidia GPU Perf"
     category: "perf|win|7"
     short_name: "nvi"
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 5e823ca..dd283f4 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -116,7 +116,7 @@
     "//ios/chrome/browser/browsing_data:features",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/drag_and_drop",
-    "//ios/chrome/browser/itunes_links",
+    "//ios/chrome/browser/itunes_urls",
     "//ios/chrome/browser/mailto:features",
     "//ios/chrome/browser/payments:constants",
     "//ios/chrome/browser/ssl:features",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 5a3c906..31ffbb6e 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -42,7 +42,7 @@
 #include "ios/chrome/browser/chrome_switches.h"
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
-#include "ios/chrome/browser/itunes_links/itunes_links_flag.h"
+#include "ios/chrome/browser/itunes_urls/itunes_urls_flag.h"
 #include "ios/chrome/browser/mailto/features.h"
 #include "ios/chrome/browser/ssl/captive_portal_features.h"
 #include "ios/chrome/browser/ui/external_search/features.h"
@@ -216,6 +216,13 @@
      flag_descriptions::kWKHTTPSystemCookieStoreName,
      flag_descriptions::kWKHTTPSystemCookieStoreName, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(web::features::kWKHTTPSystemCookieStore)},
+    {"enable-autofill-credit-card-upload-google-pay-branding",
+     flag_descriptions::kAutofillUpstreamUseGooglePayBrandingOnMobileName,
+     flag_descriptions::
+         kAutofillUpstreamUseGooglePayBrandingOnMobileDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillUpstreamUseGooglePayBrandingOnMobile)},
     {"show-autofill-type-predictions",
      flag_descriptions::kShowAutofillTypePredictionsName,
      flag_descriptions::kShowAutofillTypePredictionsDescription,
@@ -257,10 +264,10 @@
     {"new-tools_menu", flag_descriptions::kNewToolsMenuName,
      flag_descriptions::kNewToolsMenuDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kNewToolsMenu)},
-    {"itunes-links-store-kit-handling",
-     flag_descriptions::kITunesLinksStoreKitHandlingName,
-     flag_descriptions::kITunesLinksStoreKitHandlingDescription,
-     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kITunesLinksStoreKitHandling)},
+    {"itunes-urls-store-kit-handling",
+     flag_descriptions::kITunesUrlsStoreKitHandlingName,
+     flag_descriptions::kITunesUrlsStoreKitHandlingDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kITunesUrlsStoreKitHandling)},
     {"unified-consent", flag_descriptions::kUnifiedConsentName,
      flag_descriptions::kUnifiedConsentDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(signin::kUnifiedConsent)},
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index d2d5c6d..9c17f1267 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -11,6 +11,12 @@
 
 namespace flag_descriptions {
 
+const char kAutofillUpstreamUseGooglePayBrandingOnMobileName[] =
+    "Enable Google Pay branding when offering credit card upload";
+const char kAutofillUpstreamUseGooglePayBrandingOnMobileDescription[] =
+    "If enabled, shows the Google Pay logo and a shorter header message when "
+    "credit card upload to Google Payments is offered.";
+
 const char kAutofillIOSDelayBetweenFieldsName[] = "Autofill delay";
 const char kAutofillIOSDelayBetweenFieldsDescription[] =
     "Delay between the different fields of a form being autofilled. In "
@@ -108,10 +114,11 @@
     "an individual promotion causes that promotion but no other promotions to "
     "occur.";
 
-const char kITunesLinksStoreKitHandlingName[] = "Store kit for ITunes links";
-const char kITunesLinksStoreKitHandlingDescription[] =
-    "When enabled, opening itunes product links will be handled using the "
-    "store kit.";
+const char kITunesUrlsStoreKitHandlingName[] =
+    "Store kit handling for ITunes links";
+const char kITunesUrlsStoreKitHandlingDescription[] =
+    "When enabled, opening itunes product URLs will be handled using the store "
+    "kit.";
 
 const char kMailtoHandlingWithGoogleUIName[] = "Mailto Handling with Google UI";
 const char kMailtoHandlingWithGoogleUIDescription[] =
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index b1ae1cd..59c9a52 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -7,11 +7,16 @@
 
 namespace flag_descriptions {
 
-// Title and description for the flag to controll the autofill delay.
+// Title and description for the flag to control GPay branding in credit card
+// upstream infobar.
+extern const char kAutofillUpstreamUseGooglePayBrandingOnMobileName[];
+extern const char kAutofillUpstreamUseGooglePayBrandingOnMobileDescription[];
+
+// Title and description for the flag to control the autofill delay.
 extern const char kAutofillIOSDelayBetweenFieldsName[];
 extern const char kAutofillIOSDelayBetweenFieldsDescription[];
 
-// Title and description for the flag to controll the dynamic autofill.
+// Title and description for the flag to control the dynamic autofill.
 extern const char kAutofillDynamicFormsName[];
 extern const char kAutofillDynamicFormsDescription[];
 
@@ -87,8 +92,8 @@
 extern const char kInProductHelpDemoModeDescription[];
 
 // Title and description for the flag to enable ITunes links store kit handling.
-extern const char kITunesLinksStoreKitHandlingName[];
-extern const char kITunesLinksStoreKitHandlingDescription[];
+extern const char kITunesUrlsStoreKitHandlingName[];
+extern const char kITunesUrlsStoreKitHandlingDescription[];
 
 // Title, description, and options for Google UI menu for handling mailto links.
 extern const char kMailtoHandlingWithGoogleUIName[];
diff --git a/ios/chrome/browser/itunes_links/OWNERS b/ios/chrome/browser/itunes_links/OWNERS
deleted file mode 100644
index c85e66a..0000000
--- a/ios/chrome/browser/itunes_links/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-jif@chromium.org
-
-# TEAM: ios-directory-owners@chromium.org
-# OS: iOS
diff --git a/ios/chrome/browser/itunes_links/itunes_links_flag.h b/ios/chrome/browser/itunes_links/itunes_links_flag.h
deleted file mode 100644
index 5f548559..0000000
--- a/ios/chrome/browser/itunes_links/itunes_links_flag.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_ITUNES_LINKS_ITUNES_LINKS_FLAG_H_
-#define IOS_CHROME_BROWSER_ITUNES_LINKS_ITUNES_LINKS_FLAG_H_
-
-#include "base/feature_list.h"
-
-extern const base::Feature kITunesLinksStoreKitHandling;
-
-#endif  // IOS_CHROME_BROWSER_ITUNES_LINKS_ITUNES_LINKS_FLAG_H
diff --git a/ios/chrome/browser/itunes_links/itunes_links_flag.mm b/ios/chrome/browser/itunes_links/itunes_links_flag.mm
deleted file mode 100644
index a2f6f7a..0000000
--- a/ios/chrome/browser/itunes_links/itunes_links_flag.mm
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/itunes_links/itunes_links_flag.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-const base::Feature kITunesLinksStoreKitHandling{
-    "ITunesLinksStoreKitHandling", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/itunes_links/BUILD.gn b/ios/chrome/browser/itunes_urls/BUILD.gn
similarity index 76%
rename from ios/chrome/browser/itunes_links/BUILD.gn
rename to ios/chrome/browser/itunes_urls/BUILD.gn
index ad2ccf1..1a7608b 100644
--- a/ios/chrome/browser/itunes_links/BUILD.gn
+++ b/ios/chrome/browser/itunes_urls/BUILD.gn
@@ -2,13 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("itunes_links") {
+source_set("itunes_urls") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "itunes_links_flag.h",
-    "itunes_links_flag.mm",
-    "itunes_links_handler_tab_helper.h",
-    "itunes_links_handler_tab_helper.mm",
+    "itunes_urls_flag.h",
+    "itunes_urls_flag.mm",
+    "itunes_urls_handler_tab_helper.h",
+    "itunes_urls_handler_tab_helper.mm",
   ]
   deps = [
     "//base",
@@ -22,10 +22,10 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
-    "itunes_links_handler_tab_helper_unittest.mm",
+    "itunes_urls_handler_tab_helper_unittest.mm",
   ]
   deps = [
-    ":itunes_links",
+    ":itunes_urls",
     "//base",
     "//base/test:test_support",
     "//ios/chrome/browser/browser_state:test_support",
diff --git a/ios/chrome/browser/itunes_urls/OWNERS b/ios/chrome/browser/itunes_urls/OWNERS
new file mode 100644
index 0000000..e7b3304
--- /dev/null
+++ b/ios/chrome/browser/itunes_urls/OWNERS
@@ -0,0 +1,5 @@
+eugenebut@chromium.org
+mrefaat@chromium.org
+
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_flag.h b/ios/chrome/browser/itunes_urls/itunes_urls_flag.h
new file mode 100644
index 0000000..607a43c
--- /dev/null
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_flag.h
@@ -0,0 +1,12 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_FLAG_H_
+#define IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_FLAG_H_
+
+#include "base/feature_list.h"
+
+extern const base::Feature kITunesUrlsStoreKitHandling;
+
+#endif  // IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_FLAG_H
diff --git a/ios/chrome/browser/itunes_urls/itunes_urls_flag.mm b/ios/chrome/browser/itunes_urls/itunes_urls_flag.mm
new file mode 100644
index 0000000..aed47f7b
--- /dev/null
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_flag.mm
@@ -0,0 +1,12 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/itunes_urls/itunes_urls_flag.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+const base::Feature kITunesUrlsStoreKitHandling{
+    "ITunesUrlsStoreKitHandling", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.h b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
similarity index 79%
rename from ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.h
rename to ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
index d4ab5f9..b875176 100644
--- a/ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.h
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_ITUNES_LINKS_ITUNES_LINKS_HANDLER_TAB_HELPER_H_
-#define IOS_CHROME_BROWSER_ITUNES_LINKS_ITUNES_LINKS_HANDLER_TAB_HELPER_H_
+#ifndef IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_HANDLER_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_HANDLER_TAB_HELPER_H_
 
 #include "base/macros.h"
 #import "ios/web/public/web_state/web_state_policy_decider.h"
@@ -33,12 +33,12 @@
 // StoreKitTabHelper to present the information of that product. The goal of
 // this class is to workaround a bug where appstore website serves the wrong
 // content for itunes.apple.com pages, see http://crbug.com/623016.
-class ITunesLinksHandlerTabHelper
+class ITunesUrlsHandlerTabHelper
     : public web::WebStatePolicyDecider,
-      public web::WebStateUserData<ITunesLinksHandlerTabHelper> {
+      public web::WebStateUserData<ITunesUrlsHandlerTabHelper> {
  public:
-  ~ITunesLinksHandlerTabHelper() override;
-  explicit ITunesLinksHandlerTabHelper(web::WebState* web_state);
+  ~ITunesUrlsHandlerTabHelper() override;
+  explicit ITunesUrlsHandlerTabHelper(web::WebState* web_state);
   // web::WebStatePolicyDecider implementation
   bool ShouldAllowRequest(NSURLRequest* request,
                           ui::PageTransition transition,
@@ -48,7 +48,7 @@
   // Opens the StoreKit for the given iTunes app |url|.
   void HandleITunesUrl(const GURL& url);
 
-  DISALLOW_COPY_AND_ASSIGN(ITunesLinksHandlerTabHelper);
+  DISALLOW_COPY_AND_ASSIGN(ITunesUrlsHandlerTabHelper);
 };
 
-#endif  // IOS_CHROME_BROWSER_ITUNES_LINKS_ITUNES_LINKS_HANDLER_TAB_HELPER_H_
+#endif  // IOS_CHROME_BROWSER_ITUNES_URLS_ITUNES_URLS_HANDLER_TAB_HELPER_H_
diff --git a/ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
similarity index 89%
rename from ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.mm
rename to ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
index d3bb5642..34f9216 100644
--- a/ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.mm
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.h"
+#import "ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h"
 
 #import <Foundation/Foundation.h>
 #import <StoreKit/StoreKit.h>
@@ -28,11 +28,11 @@
 #error "This file requires ARC support."
 #endif
 
-DEFINE_WEB_STATE_USER_DATA_KEY(ITunesLinksHandlerTabHelper);
+DEFINE_WEB_STATE_USER_DATA_KEY(ITunesUrlsHandlerTabHelper);
 
 namespace {
 
-// The domain for iTunes appstore links.
+// The domain for iTunes appstore URLs.
 const char kITunesUrlDomain[] = "itunes.apple.com";
 const char kITunesProductIdPrefix[] = "id";
 const char kITunesAppPathIdentifier[] = "app";
@@ -77,7 +77,7 @@
   return params_dictionary;
 }
 
-// Returns true, if ITunesLinksHandlerTabHelper can handle the given |url|.
+// Returns true, if ITunesUrlsHandlerTabHelper can handle the given |url|.
 bool CanHandleUrl(const GURL& url) {
   if (!IsITunesProductUrl(url))
     return false;
@@ -103,13 +103,12 @@
 
 }  // namespace
 
-ITunesLinksHandlerTabHelper::~ITunesLinksHandlerTabHelper() = default;
+ITunesUrlsHandlerTabHelper::~ITunesUrlsHandlerTabHelper() = default;
 
-ITunesLinksHandlerTabHelper::ITunesLinksHandlerTabHelper(
-    web::WebState* web_state)
+ITunesUrlsHandlerTabHelper::ITunesUrlsHandlerTabHelper(web::WebState* web_state)
     : web::WebStatePolicyDecider(web_state) {}
 
-bool ITunesLinksHandlerTabHelper::ShouldAllowRequest(
+bool ITunesUrlsHandlerTabHelper::ShouldAllowRequest(
     NSURLRequest* request,
     ui::PageTransition transition,
     bool from_main_frame) {
@@ -128,7 +127,7 @@
 }
 
 // private
-void ITunesLinksHandlerTabHelper::HandleITunesUrl(const GURL& url) {
+void ITunesUrlsHandlerTabHelper::HandleITunesUrl(const GURL& url) {
   ITunesUrlsStoreKitHandlingResult handling_result =
       ITunesUrlsStoreKitHandlingResult::kSingleAppUrlHandled;
   StoreKitTabHelper* tab_helper = StoreKitTabHelper::FromWebState(web_state());
diff --git a/ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper_unittest.mm b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
similarity index 92%
rename from ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper_unittest.mm
rename to ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
index b05cd208..8df78fd77 100644
--- a/ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper_unittest.mm
+++ b/ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.h"
+#import "ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h"
 
 #import <Foundation/Foundation.h>
 
@@ -25,15 +25,15 @@
     "IOS.StoreKit.ITunesURLsHandlingResult";
 }  // namespace
 
-class ITunesLinksHandlerTabHelperTest : public PlatformTest {
+class ITunesUrlsHandlerTabHelperTest : public PlatformTest {
  protected:
-  ITunesLinksHandlerTabHelperTest()
+  ITunesUrlsHandlerTabHelperTest()
       : fake_launcher_([[FakeStoreKitLauncher alloc] init]),
         chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
     web_state_.SetBrowserState(
         chrome_browser_state_->GetOriginalChromeBrowserState());
     StoreKitTabHelper::CreateForWebState(&web_state_);
-    ITunesLinksHandlerTabHelper::CreateForWebState(&web_state_);
+    ITunesUrlsHandlerTabHelper::CreateForWebState(&web_state_);
     StoreKitTabHelper::FromWebState(&web_state_)->SetLauncher(fake_launcher_);
   }
 
@@ -57,7 +57,7 @@
 };
 
 // Verifies that iTunes URLs are not handled when in off the record mode.
-TEST_F(ITunesLinksHandlerTabHelperTest, NoHandlingInOffTheRecordMode) {
+TEST_F(ITunesUrlsHandlerTabHelperTest, NoHandlingInOffTheRecordMode) {
   NSString* url = @"http://itunes.apple.com/us/app/app_name/id123";
   EXPECT_TRUE(VerifyStoreKitLaunched(url, /*main_frame=*/true));
   web_state_.SetBrowserState(
@@ -66,7 +66,7 @@
 }
 
 // Verifies that iTunes URLs are not handled when the request is from iframe.
-TEST_F(ITunesLinksHandlerTabHelperTest, NoHandlingInIframes) {
+TEST_F(ITunesUrlsHandlerTabHelperTest, NoHandlingInIframes) {
   EXPECT_TRUE(VerifyStoreKitLaunched(
       @"http://itunes.apple.com/us/app/app_name/id123", /*main_frame=*/true));
   EXPECT_FALSE(VerifyStoreKitLaunched(
@@ -79,7 +79,7 @@
 
 // Verifies that navigating to non iTunes product URLs, or not supported iTunes
 // product type URLs does not launch storekit.
-TEST_F(ITunesLinksHandlerTabHelperTest, NonMatchingUrlsDoesntLaunchStoreKit) {
+TEST_F(ITunesUrlsHandlerTabHelperTest, NonMatchingUrlsDoesntLaunchStoreKit) {
   EXPECT_FALSE(VerifyStoreKitLaunched(@"", /*main_frame=*/true));
   EXPECT_FALSE(VerifyStoreKitLaunched(@"foobar", /*main_frame=*/true));
   EXPECT_FALSE(VerifyStoreKitLaunched(@"foo://bar", /*main_frame=*/true));
@@ -108,7 +108,7 @@
 
 // Verifies that navigating to URLs for a product hosted on iTunes AppStore
 // with supported media type launches storekit.
-TEST_F(ITunesLinksHandlerTabHelperTest, MatchingUrlsLaunchesStoreKit) {
+TEST_F(ITunesUrlsHandlerTabHelperTest, MatchingUrlsLaunchesStoreKit) {
   EXPECT_TRUE(VerifyStoreKitLaunched(
       @"http://itunes.apple.com/us/app/app_name/id123", /*main_frame=*/true));
   NSString* product_id = @"id";
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index ff4cafb27..cca1c88 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -97,7 +97,7 @@
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/history:tab_helper",
     "//ios/chrome/browser/infobars",
-    "//ios/chrome/browser/itunes_links",
+    "//ios/chrome/browser/itunes_urls",
     "//ios/chrome/browser/language",
     "//ios/chrome/browser/metrics",
     "//ios/chrome/browser/metrics:metrics_internal",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index a0c9ff3..0cca4da 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -24,8 +24,8 @@
 #include "ios/chrome/browser/history/history_tab_helper.h"
 #include "ios/chrome/browser/history/top_sites_factory.h"
 #import "ios/chrome/browser/infobars/infobar_manager_impl.h"
-#include "ios/chrome/browser/itunes_links/itunes_links_flag.h"
-#import "ios/chrome/browser/itunes_links/itunes_links_handler_tab_helper.h"
+#include "ios/chrome/browser/itunes_urls/itunes_urls_flag.h"
+#import "ios/chrome/browser/itunes_urls/itunes_urls_handler_tab_helper.h"
 #import "ios/chrome/browser/metrics/ukm_url_recorder.h"
 #import "ios/chrome/browser/passwords/password_tab_helper.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
@@ -80,8 +80,8 @@
   BlockedPopupTabHelper::CreateForWebState(web_state);
   FindTabHelper::CreateForWebState(web_state);
   StoreKitTabHelper::CreateForWebState(web_state);
-  if (base::FeatureList::IsEnabled(kITunesLinksStoreKitHandling)) {
-    ITunesLinksHandlerTabHelper::CreateForWebState(web_state);
+  if (base::FeatureList::IsEnabled(kITunesUrlsStoreKitHandling)) {
+    ITunesUrlsHandlerTabHelper::CreateForWebState(web_state);
   }
   HistoryTabHelper::CreateForWebState(web_state);
   LoadTimingTabHelper::CreateForWebState(web_state);
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 1a84806e..d9bdc71 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -7,8 +7,6 @@
   sources = [
     "bookmark_edit_view_controller.h",
     "bookmark_edit_view_controller.mm",
-    "bookmark_elevated_toolbar.h",
-    "bookmark_elevated_toolbar.mm",
     "bookmark_empty_background.h",
     "bookmark_empty_background.mm",
     "bookmark_folder_editor_view_controller.h",
@@ -46,6 +44,7 @@
     "undo_manager_wrapper.mm",
   ]
   deps = [
+    ":bookmarks_ui",
     "resources:bookmark_bar_innershadow",
     "resources:bookmark_bar_shadow",
     "resources:bookmark_black_delete",
@@ -132,6 +131,15 @@
   ]
 }
 
+source_set("bookmarks_ui") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "bookmark_ui_constants.h",
+    "bookmark_ui_constants.mm",
+  ]
+  deps = []
+}
+
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
@@ -164,6 +172,7 @@
     "bookmarks_egtest.mm",
   ]
   deps = [
+    ":bookmarks_ui",
     "//base",
     "//components/bookmarks/browser",
     "//components/prefs",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
index d90fd18..a7c91de 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -21,6 +21,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h"
@@ -38,6 +39,7 @@
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
 #import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
@@ -224,14 +226,24 @@
   self.doneItem = doneItem;
 
   // Setup the bottom toolbar.
+  self.navigationController.toolbar.barTintColor = [UIColor whiteColor];
   NSString* titleString = l10n_util::GetNSString(IDS_IOS_BOOKMARK_DELETE);
+  titleString = [titleString uppercaseString];
   UIBarButtonItem* deleteButton =
       [[UIBarButtonItem alloc] initWithTitle:titleString
                                        style:UIBarButtonItemStylePlain
                                       target:self
                                       action:@selector(deleteBookmark)];
-  deleteButton.accessibilityIdentifier = @"Delete_action";
-  deleteButton.tintColor = [UIColor blackColor];
+  deleteButton.accessibilityIdentifier = kBookmarkEditDeleteButtonIdentifier;
+  [deleteButton
+      setTitleTextAttributes:[NSDictionary
+                                 dictionaryWithObjectsAndKeys:
+                                     [[MDCTypography fontLoader]
+                                         mediumFontOfSize:14],
+                                     NSFontAttributeName, [UIColor blackColor],
+                                     NSForegroundColorAttributeName, nil]
+                    forState:UIControlStateNormal];
+
   UIBarButtonItem* spaceButton = [[UIBarButtonItem alloc]
       initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                            target:nil
@@ -455,8 +467,8 @@
       cell.selectionStyle = UITableViewCellSelectionStyleNone;
       break;
     case ItemTypeURL: {
-      BookmarkTextFieldCell* URLCell =
-          base::mac::ObjCCastStrict<BookmarkTextFieldCell>(cell);
+      LegacyBookmarkTextFieldCell* URLCell =
+          base::mac::ObjCCastStrict<LegacyBookmarkTextFieldCell>(cell);
       URLCell.textField.textValidator = self;
       URLCell.selectionStyle = UITableViewCellSelectionStyleNone;
       break;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.h b/ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.h
deleted file mode 100644
index 91a00195..0000000
--- a/ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_ELEVATED_TOOLBAR_H_
-#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_ELEVATED_TOOLBAR_H_
-
-#import <UIKit/UIKit.h>
-
-@class MDCButton;
-
-// A class containing one button that has a Material shadow.
-@interface BookmarksElevatedToolbar : UIView
-
-@property(nonatomic, assign) CGFloat shadowElevation;
-
-- (void)setButton:(MDCButton*)button;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_ELEVATED_TOOLBAR_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.mm b/ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.mm
deleted file mode 100644
index 1dc74d7..0000000
--- a/ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.mm
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/bookmarks/bookmark_elevated_toolbar.h"
-
-#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Buttons/src/MDCButton.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-const CGFloat kButtonHeight = 48;
-}
-
-@interface BookmarksElevatedToolbar ()
-
-@property(nonatomic, readonly) MDCShadowLayer* shadowLayer;
-@property(nonatomic, strong) MDCButton* currentButton;
-
-@end
-
-@implementation BookmarksElevatedToolbar
-
-@synthesize currentButton = _currentButton;
-@synthesize shadowLayer = _shadowLayer;
-
-- (instancetype)init {
-  self = [super init];
-  if (self) {
-    [self.layer addSublayer:[[MDCShadowLayer alloc] init]];
-    self.shadowElevation = MDCShadowElevationSearchBarResting;
-    self.backgroundColor = [UIColor whiteColor];
-  }
-  return self;
-}
-
-- (void)setButton:(MDCButton*)button {
-  [self.currentButton removeFromSuperview];
-  self.currentButton = button;
-  if (!button)
-    return;
-
-  [self addSubview:button];
-  button.translatesAutoresizingMaskIntoConstraints = NO;
-
-  id<LayoutGuideProvider> safeAreaLayoutGuide =
-      SafeAreaLayoutGuideForView(self);
-  [NSLayoutConstraint activateConstraints:@[
-    [button.leadingAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.leadingAnchor],
-    [button.topAnchor constraintEqualToAnchor:safeAreaLayoutGuide.topAnchor],
-    [button.bottomAnchor
-        constraintEqualToAnchor:safeAreaLayoutGuide.bottomAnchor],
-    [button.heightAnchor constraintEqualToConstant:kButtonHeight],
-  ]];
-}
-
-#pragma mark - Properties
-
-- (MDCShadowLayer*)shadowLayer {
-  if (!_shadowLayer) {
-    _shadowLayer = [[MDCShadowLayer alloc] init];
-    _shadowLayer.elevation = MDCShadowElevationNone;
-    [self.layer addSublayer:self.shadowLayer];
-  }
-  return _shadowLayer;
-}
-
-- (void)setShadowElevation:(CGFloat)shadowElevation {
-  self.shadowLayer.elevation = shadowElevation;
-}
-
-- (CGFloat)shadowElevation {
-  return self.shadowLayer.elevation;
-}
-
-#pragma mark - UIView
-
-- (void)layoutSubviews {
-  [super layoutSubviews];
-  self.shadowLayer.frame = self.layer.bounds;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
index 12b688ab..0baccf99f 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
@@ -16,6 +16,7 @@
 #include "components/bookmarks/browser/bookmark_node.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h"
@@ -450,14 +451,24 @@
 
 - (void)addToolbar {
   self.navigationController.toolbarHidden = NO;
+  self.navigationController.toolbar.barTintColor = [UIColor whiteColor];
   NSString* titleString = l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_DELETE);
+  titleString = [titleString uppercaseString];
   UIBarButtonItem* deleteButton =
       [[UIBarButtonItem alloc] initWithTitle:titleString
                                        style:UIBarButtonItemStylePlain
                                       target:self
                                       action:@selector(deleteFolder)];
-  deleteButton.accessibilityIdentifier = @"Delete Folder";
-  deleteButton.tintColor = [UIColor blackColor];
+  deleteButton.accessibilityIdentifier =
+      kBookmarkFolderEditorDeleteButtonIdentifier;
+  [deleteButton
+      setTitleTextAttributes:[NSDictionary
+                                 dictionaryWithObjectsAndKeys:
+                                     [[MDCTypography fontLoader]
+                                         mediumFontOfSize:14],
+                                     NSFontAttributeName, [UIColor blackColor],
+                                     NSForegroundColorAttributeName, nil]
+                    forState:UIControlStateNormal];
 
   UIBarButtonItem* spaceButton = [[UIBarButtonItem alloc]
       initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_consumer.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_consumer.h
index 8d8a4c3..f24f0ba5 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_consumer.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_consumer.h
@@ -7,6 +7,10 @@
 
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_consumer.h"
 
+@class NSIndexPath;
+@class ShowSigninCommand;
+@class SigninPromoViewConfigurator;
+
 typedef NS_ENUM(NSInteger, BookmarkHomeBackgroundStyle) {
   // The default background style.
   BookmarkHomeBackgroundStyleDefault,
@@ -33,6 +37,16 @@
 // Displays the table view background for the given |style|.
 - (void)updateTableViewBackgroundStyle:(BookmarkHomeBackgroundStyle)style;
 
+// Displays the signin UI configured by |command|.
+- (void)showSignin:(ShowSigninCommand*)command;
+
+// Reconfigures the cell at the given |indexPath| with the given |configurator|.
+// If |forceReloadCell| is YES, reloads the section when complete.
+- (void)configureSigninPromoWithConfigurator:
+            (SigninPromoViewConfigurator*)configurator
+                                 atIndexPath:(NSIndexPath*)indexPath
+                             forceReloadCell:(BOOL)forceReloadCell;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_HOME_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm
index 64d0017..689ef23 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm
@@ -9,10 +9,14 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/sync/synced_sessions_bridge.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_consumer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.h"
 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.h"
+#import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -21,7 +25,10 @@
 
 using bookmarks::BookmarkNode;
 
-@interface BookmarkHomeMediator ()<BookmarkModelBridgeObserver,
+@interface BookmarkHomeMediator ()<BookmarkHomePromoItemDelegate,
+                                   BookmarkModelBridgeObserver,
+                                   BookmarkPromoControllerDelegate,
+                                   SigninPresenter,
                                    SyncedSessionsObserver> {
   // Bridge to register for bookmark changes.
   std::unique_ptr<bookmarks::BookmarkModelBridge> _modelBridge;
@@ -31,13 +38,20 @@
       _syncedSessionsObserver;
 }
 
+// Shared state between Bookmark home classes.
 @property(nonatomic, strong) BookmarkHomeSharedState* sharedState;
 
+// The browser state for this mediator.
 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
 
+// The controller managing the display of the promo cell and the promo view
+// controller.
+@property(nonatomic, strong) BookmarkPromoController* bookmarkPromoController;
+
 @end
 
 @implementation BookmarkHomeMediator
+@synthesize bookmarkPromoController = _bookmarkPromoController;
 @synthesize browserState = _browserState;
 @synthesize consumer = _consumer;
 @synthesize sharedState = _sharedState;
@@ -61,7 +75,12 @@
   _syncedSessionsObserver =
       std::make_unique<synced_sessions::SyncedSessionsObserverBridge>(
           self, self.browserState);
+  _bookmarkPromoController =
+      [[BookmarkPromoController alloc] initWithBrowserState:self.browserState
+                                                   delegate:self
+                                                  presenter:self];
 
+  [self computePromoTableViewData];
   [self computeBookmarkTableViewData];
 }
 
@@ -185,6 +204,49 @@
   }
 }
 
+#pragma mark - Public
+
+- (void)computePromoTableViewData {
+  // We show promo cell only on the root view, that is when showing
+  // the permanent nodes.
+  BOOL promoVisible = ((self.sharedState.tableViewDisplayedRootNode ==
+                        self.sharedState.bookmarkModel->root_node()) &&
+                       self.bookmarkPromoController.shouldShowSigninPromo);
+
+  if (promoVisible == self.sharedState.promoVisible) {
+    return;
+  }
+  self.sharedState.promoVisible = promoVisible;
+
+  SigninPromoViewMediator* mediator = self.signinPromoViewMediator;
+  if (self.sharedState.promoVisible) {
+    DCHECK(![self.sharedState.tableViewModel
+        hasSectionForSectionIdentifier:BookmarkHomeSectionIdentifierPromo]);
+    [self.sharedState.tableViewModel
+        insertSectionWithIdentifier:BookmarkHomeSectionIdentifierPromo
+                            atIndex:0];
+    BookmarkHomePromoItem* item =
+        [[BookmarkHomePromoItem alloc] initWithType:BookmarkHomeItemTypePromo];
+    item.delegate = self;
+    [self.sharedState.tableViewModel
+                        addItem:item
+        toSectionWithIdentifier:BookmarkHomeSectionIdentifierPromo];
+    [mediator signinPromoViewVisible];
+  } else {
+    if (![mediator isInvalidClosedOrNeverVisible]) {
+      // When the sign-in view is closed, the promo state changes, but
+      // -[SigninPromoViewMediator signinPromoViewHidden] should not be called.
+      [mediator signinPromoViewHidden];
+    }
+
+    DCHECK([self.sharedState.tableViewModel
+        hasSectionForSectionIdentifier:BookmarkHomeSectionIdentifierPromo]);
+    [self.sharedState.tableViewModel
+        removeSectionWithIdentifier:BookmarkHomeSectionIdentifierPromo];
+  }
+  [self.sharedState.tableView reloadData];
+}
+
 #pragma mark - BookmarkModelBridgeObserver Callbacks
 
 // BookmarkModelBridgeObserver Callbacks
@@ -283,6 +345,41 @@
   return nil;
 }
 
+#pragma mark - BookmarkHomePromoItemDelegate
+
+- (SigninPromoViewMediator*)signinPromoViewMediator {
+  return self.bookmarkPromoController.signinPromoViewMediator;
+}
+
+#pragma mark - BookmarkPromoControllerDelegate
+
+- (void)promoStateChanged:(BOOL)promoEnabled {
+  [self computePromoTableViewData];
+}
+
+- (void)configureSigninPromoWithConfigurator:
+            (SigninPromoViewConfigurator*)configurator
+                             identityChanged:(BOOL)identityChanged {
+  if (![self.sharedState.tableViewModel
+          hasSectionForSectionIdentifier:BookmarkHomeSectionIdentifierPromo]) {
+    return;
+  }
+
+  NSIndexPath* indexPath = [self.sharedState.tableViewModel
+      indexPathForItemType:BookmarkHomeItemTypePromo
+         sectionIdentifier:BookmarkHomeSectionIdentifierPromo];
+  [self.consumer configureSigninPromoWithConfigurator:configurator
+                                          atIndexPath:indexPath
+                                      forceReloadCell:identityChanged];
+}
+
+#pragma mark - SigninPresenter
+
+- (void)showSignin:(ShowSigninCommand*)command {
+  // Proxy this call along to the consumer.
+  [self.consumer showSignin:command];
+}
+
 #pragma mark - SyncedSessionsObserver
 
 - (void)reloadSessions {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 9893581e..f60515cd 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -4,15 +4,22 @@
 
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h"
 
+#include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/favicon/core/fallback_url_util.h"
+#include "components/favicon/core/favicon_server_fetcher_params.h"
+#include "components/favicon/core/large_icon_service.h"
+#include "components/favicon_base/fallback_icon_style.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
 #import "ios/chrome/browser/metrics/new_tab_page_uma.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/bookmarks/bars/bookmark_context_bar.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h"
@@ -24,18 +31,16 @@
 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h"
-#import "ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_table_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/material_components/utils.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
-#import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 #import "ios/chrome/browser/ui/ui_util.h"
@@ -46,11 +51,16 @@
 #import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/referrer.h"
+#include "skia/ext/skia_utils_ios.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 using bookmarks::BookmarkNode;
 
+// Used to store a pair of NSIntegers when storing a NSIndexPath in C++
+// collections.
+using IntegerPair = std::pair<NSInteger, NSInteger>;
+
 namespace {
 typedef NS_ENUM(NSInteger, BookmarksContextBarState) {
   BookmarksContextBarNone,            // No state.
@@ -65,6 +75,27 @@
   BookmarksContextBarMixedSelection,  // Multiple URL / Folders selected.
 };
 
+// NetworkTrafficAnnotationTag for fetching favicon from a Google server.
+const net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("bookmarks_get_large_icon", R"(
+                                        semantics {
+                                        sender: "Bookmarks"
+                                        description:
+                                          "Sends a request to a Google server to retrieve the favicon bitmap "
+                                          "for a bookmark."
+                                        trigger:
+                                          "A request can be sent if Chrome does not have a favicon for a "
+                                          "bookmark."
+                                        data: "Page URL and desired icon size."
+                                        destination: GOOGLE_OWNED_SERVICE
+                                        }
+                                        policy {
+                                        cookies_allowed: NO
+                                        setting: "This feature cannot be disabled by settings."
+                                        policy_exception_justification: "Not implemented."
+                                        }
+                                        )");
+
 // Returns a vector of all URLs in |nodes|.
 std::vector<GURL> GetUrlsToOpen(const std::vector<const BookmarkNode*>& nodes) {
   std::vector<GURL> urls;
@@ -84,11 +115,9 @@
     BookmarkHomeConsumer,
     BookmarkHomeSharedStateObserver,
     BookmarkModelBridgeObserver,
-    BookmarkPromoControllerDelegate,
     BookmarkTableCellTitleEditDelegate,
     BookmarkTableViewDelegate,
     ContextBarDelegate,
-    SigninPresenter,
     UIGestureRecognizerDelegate,
     UITableViewDataSource,
     UITableViewDelegate> {
@@ -97,8 +126,16 @@
 
   // The root node, whose child nodes are shown in the bookmark table view.
   const bookmarks::BookmarkNode* _rootNode;
+
   // YES if NSLayoutConstraits were added.
   BOOL _addedConstraints;
+
+  // Map of favicon load tasks for each index path. Used to keep track of
+  // pending favicon load operations so that they can be cancelled upon cell
+  // reuse. Keys are (section, item) pairs of cell index paths.
+  std::map<IntegerPair, base::CancelableTaskTracker::TaskId> _faviconLoadTasks;
+  // Task tracker used for async favicon loads.
+  base::CancelableTaskTracker _faviconTaskTracker;
 }
 
 // Shared state between BookmarkHome classes.  Used as a temporary refactoring
@@ -143,10 +180,6 @@
 // The view controller to present when editing the current folder.
 @property(nonatomic, strong) BookmarkFolderEditorViewController* folderEditor;
 
-// The controller managing the display of the promo cell and the promo view
-// controller.
-@property(nonatomic, strong) BookmarkPromoController* bookmarkPromoController;
-
 // The current state of the context bar UI.
 @property(nonatomic, assign) BookmarksContextBarState contextBarState;
 
@@ -162,7 +195,6 @@
 @implementation BookmarkHomeViewController
 
 @synthesize appBar = _appBar;
-@synthesize bookmarkPromoController = _bookmarkPromoController;
 @synthesize bookmarks = _bookmarks;
 @synthesize browserState = _browserState;
 @synthesize editViewController = _editViewController;
@@ -200,13 +232,6 @@
     _bookmarks = ios::BookmarkModelFactory::GetForBrowserState(browserState);
 
     _bridge.reset(new bookmarks::BookmarkModelBridge(self, _bookmarks));
-
-    // It is important to initialize the promo controller with the browser state
-    // passed in, as it could be incognito.
-    _bookmarkPromoController = [[BookmarkPromoController alloc]
-        initWithBrowserState:browserState
-                    delegate:self
-                   presenter:self /* id<SigninPresenter> */];
   }
   return self;
 }
@@ -214,6 +239,7 @@
 - (void)dealloc {
   [self.mediator disconnect];
   [self removeKeyboardObservers];
+  _faviconTaskTracker.TryCancelAll();
   _sharedState.tableView.dataSource = nil;
   _sharedState.tableView.delegate = nil;
 }
@@ -247,8 +273,7 @@
   // Set the content position after views are laid out, to ensure the right
   // window of rows is shown. Once used, reset self.cachedContentPosition.
   if (self.cachedContentPosition) {
-    [self.bookmarksTableView
-        setContentPosition:self.cachedContentPosition.floatValue];
+    [self setContentPosition:self.cachedContentPosition.floatValue];
     self.cachedContentPosition = nil;
   }
   // The height of contextBar might change due to word wrapping of buttons
@@ -260,6 +285,12 @@
   return NO;
 }
 
+- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
+  [super traitCollectionDidChange:previousTraitCollection];
+  // Stop edit of current bookmark folder name, if any.
+  [self.sharedState.editingFolderCell stopEdit];
+}
+
 - (NSArray*)keyCommands {
   __weak BookmarkHomeViewController* weakSelf = self;
   return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
@@ -357,8 +388,7 @@
       cacheBookmarkUIPositionWithPrefService:self.browserState->GetPrefs()
                                     folderId:_rootNode->id()
                               scrollPosition:static_cast<double>(
-                                                 self.bookmarksTableView
-                                                     .contentPosition)];
+                                                 self.contentPosition)];
 }
 
 #pragma mark - BookmarkHomeConsumer
@@ -379,20 +409,90 @@
 
 - (void)refreshContents {
   [self.mediator computeBookmarkTableViewData];
-  [self.bookmarksTableView cancelAllFaviconLoads];
+  [self cancelAllFaviconLoads];
   [self bookmarkTableViewRefreshContextBar:self.bookmarksTableView];
   [self.sharedState.editingFolderCell stopEdit];
   [self.sharedState.tableView reloadData];
   if (self.sharedState.currentlyInEditMode &&
       !self.sharedState.editNodes.empty()) {
-    [self.bookmarksTableView restoreRowSelection];
+    [self restoreRowSelection];
   }
 }
 
+// Asynchronously loads favicon for given index path. The loads are cancelled
+// upon cell reuse automatically.  When the favicon is not found in cache, try
+// loading it from a Google server if |continueToGoogleServer| is YES,
+// otherwise, use the fall back icon style.
 - (void)loadFaviconAtIndexPath:(NSIndexPath*)indexPath
         continueToGoogleServer:(BOOL)continueToGoogleServer {
-  [self.bookmarksTableView loadFaviconAtIndexPath:indexPath
-                           continueToGoogleServer:continueToGoogleServer];
+  const bookmarks::BookmarkNode* node = [self nodeAtIndexPath:indexPath];
+  if (node->is_folder()) {
+    return;
+  }
+
+  CGFloat scale = [UIScreen mainScreen].scale;
+  CGFloat desiredFaviconSizeInPixel =
+      scale * [BookmarkHomeSharedState desiredFaviconSizePt];
+  CGFloat minFaviconSizeInPixel =
+      scale * [BookmarkHomeSharedState minFaviconSizePt];
+
+  // Start loading a favicon.
+  __weak BookmarkHomeViewController* weakSelf = self;
+  GURL blockURL(node->url());
+  NSString* fallbackText =
+      base::SysUTF16ToNSString(favicon::GetFallbackIconText(blockURL));
+  void (^faviconLoadedFromCacheBlock)(const favicon_base::LargeIconResult&) = ^(
+      const favicon_base::LargeIconResult& result) {
+    BookmarkHomeViewController* strongSelf = weakSelf;
+    if (!strongSelf) {
+      return;
+    }
+    // TODO(crbug.com/697329) When fetching icon from server to replace existing
+    // cache is allowed, fetch icon from server here when cached icon is smaller
+    // than the desired size.
+    if (!result.bitmap.is_valid() && continueToGoogleServer &&
+        strongSelf.sharedState.faviconDownloadCount <
+            [BookmarkHomeSharedState maxDownloadFaviconCount]) {
+      void (^faviconLoadedFromServerBlock)(
+          favicon_base::GoogleFaviconServerRequestStatus status) =
+          ^(const favicon_base::GoogleFaviconServerRequestStatus status) {
+            if (status ==
+                favicon_base::GoogleFaviconServerRequestStatus::SUCCESS) {
+              BookmarkHomeViewController* strongSelf = weakSelf;
+              // GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache
+              // is not cancellable.  So need to check if node has been changed
+              // before proceeding to favicon update.
+              if (!strongSelf ||
+                  [strongSelf nodeAtIndexPath:indexPath] != node) {
+                return;
+              }
+              // Favicon should be ready in cache now.  Fetch it again.
+              [strongSelf loadFaviconAtIndexPath:indexPath
+                          continueToGoogleServer:NO];
+            }
+          };  // faviconLoadedFromServerBlock
+
+      strongSelf.sharedState.faviconDownloadCount++;
+      IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState)
+          ->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+              favicon::FaviconServerFetcherParams::CreateForMobile(
+                  node->url(), minFaviconSizeInPixel,
+                  desiredFaviconSizeInPixel),
+              /*may_page_url_be_private=*/true, kTrafficAnnotation,
+              base::BindBlockArc(faviconLoadedFromServerBlock));
+    }
+    [strongSelf updateCellAtIndexPath:indexPath
+                  withLargeIconResult:result
+                         fallbackText:fallbackText];
+  };  // faviconLoadedFromCacheBlock
+
+  base::CancelableTaskTracker::TaskId taskId =
+      IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState)
+          ->GetLargeIconOrFallbackStyle(
+              node->url(), minFaviconSizeInPixel, desiredFaviconSizeInPixel,
+              base::BindBlockArc(faviconLoadedFromCacheBlock),
+              &_faviconTaskTracker);
+  _faviconLoadTasks[IntegerPair(indexPath.section, indexPath.item)] = taskId;
 }
 
 - (void)updateTableViewBackgroundStyle:(BookmarkHomeBackgroundStyle)style {
@@ -408,21 +508,32 @@
   }
 }
 
-#pragma mark - BookmarkPromoControllerDelegate
-
-- (void)promoStateChanged:(BOOL)promoEnabled {
-  [self.bookmarksTableView promoStateChangedAnimated:YES];
+- (void)showSignin:(ShowSigninCommand*)command {
+  [self.dispatcher showSignin:command baseViewController:self];
 }
 
 - (void)configureSigninPromoWithConfigurator:
             (SigninPromoViewConfigurator*)configurator
-                             identityChanged:(BOOL)identityChanged {
-  [self.bookmarksTableView
-      configureSigninPromoWithConfigurator:configurator
-                           identityChanged:identityChanged];
+                                 atIndexPath:(NSIndexPath*)indexPath
+                             forceReloadCell:(BOOL)forceReloadCell {
+  BookmarkTableSigninPromoCell* signinPromoCell =
+      base::mac::ObjCCast<BookmarkTableSigninPromoCell>(
+          [self.sharedState.tableView cellForRowAtIndexPath:indexPath]);
+  if (!signinPromoCell) {
+    return;
+  }
+  // Should always reconfigure the cell size even if it has to be reloaded,
+  // to make sure it has the right size to compute the cell size.
+  [configurator configureSigninPromoView:signinPromoCell.signinPromoView];
+  if (forceReloadCell) {
+    // The section should be reload to update the cell height.
+    NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:indexPath.section];
+    [self.sharedState.tableView reloadSections:indexSet
+                              withRowAnimation:UITableViewRowAnimationNone];
+  }
 }
 
-#pragma mark Action sheet callbacks
+#pragma mark - Action sheet callbacks
 
 // Opens the folder move editor for the given node.
 - (void)moveNodes:(const std::set<const BookmarkNode*>&)nodes {
@@ -494,16 +605,12 @@
 #pragma mark - Navigation Bar Callbacks
 
 - (void)navigationBarCancel:(id)sender {
-  [self.bookmarksTableView navigateAway];
+  [self navigateAway];
   [self dismissWithURL:GURL()];
 }
 
 #pragma mark - BookmarkTableViewDelegate
 
-- (SigninPromoViewMediator*)signinPromoViewMediator {
-  return self.bookmarkPromoController.signinPromoViewMediator;
-}
-
 - (void)bookmarkTableView:(BookmarkTableView*)view
     selectedUrlForNavigation:(const GURL&)url {
   [self dismissWithURL:url];
@@ -522,10 +629,6 @@
   [self deleteNodes:nodes];
 }
 
-- (BOOL)bookmarkTableViewShouldShowPromoCell:(BookmarkTableView*)tableView {
-  return self.bookmarkPromoController.shouldShowSigninPromo;
-}
-
 - (void)bookmarkTableView:(BookmarkTableView*)view
         selectedEditNodes:
             (const std::set<const bookmarks::BookmarkNode*>&)nodes {
@@ -885,7 +988,7 @@
 
 // Back button callback for the new ui.
 - (void)back {
-  [self.bookmarksTableView navigateAway];
+  [self navigateAway];
   [self.navigationController popViewControllerAnimated:YES];
 }
 
@@ -962,6 +1065,45 @@
   [super updateViewConstraints];
 }
 
+- (void)addNewFolder {
+  [self.sharedState.editingFolderCell stopEdit];
+  if (!self.sharedState.tableViewDisplayedRootNode) {
+    return;
+  }
+  self.sharedState.addingNewFolder = YES;
+  base::string16 folderTitle = base::SysNSStringToUTF16(
+      l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_GROUP_DEFAULT_NAME));
+  self.sharedState.editingFolderNode =
+      self.sharedState.bookmarkModel->AddFolder(
+          self.sharedState.tableViewDisplayedRootNode,
+          self.sharedState.tableViewDisplayedRootNode->child_count(),
+          folderTitle);
+
+  BookmarkHomeNodeItem* nodeItem = [[BookmarkHomeNodeItem alloc]
+      initWithType:BookmarkHomeItemTypeBookmark
+      bookmarkNode:self.sharedState.editingFolderNode];
+  [self.sharedState.tableViewModel
+                      addItem:nodeItem
+      toSectionWithIdentifier:BookmarkHomeSectionIdentifierBookmarks];
+
+  // Insert the new folder cell at the end of the table.
+  NSIndexPath* newRowIndexPath =
+      [self.sharedState.tableViewModel indexPathForItem:nodeItem];
+  NSMutableArray* newRowIndexPaths =
+      [[NSMutableArray alloc] initWithObjects:newRowIndexPath, nil];
+  [self.sharedState.tableView beginUpdates];
+  [self.sharedState.tableView
+      insertRowsAtIndexPaths:newRowIndexPaths
+            withRowAnimation:UITableViewRowAnimationNone];
+  [self.sharedState.tableView endUpdates];
+
+  // Scroll to the end of the table
+  [self.sharedState.tableView
+      scrollToRowAtIndexPath:newRowIndexPath
+            atScrollPosition:UITableViewScrollPositionBottom
+                    animated:YES];
+}
+
 - (BookmarkHomeViewController*)createControllerWithRootFolder:
     (const bookmarks::BookmarkNode*)folder {
   BookmarkHomeViewController* controller =
@@ -980,6 +1122,71 @@
                                    : BookmarksContextBarDefault];
 }
 
+// Row selection of the tableView will be cleared after reloadData.  This
+// function is used to restore the row selection.  It also updates editNodes in
+// case some selected nodes are removed.
+- (void)restoreRowSelection {
+  // Create a new editNodes set to check if some selected nodes are removed.
+  std::set<const bookmarks::BookmarkNode*> newEditNodes;
+
+  // Add selected nodes to editNodes only if they are not removed (still exist
+  // in the table).
+  NSArray<TableViewItem*>* items = [self.sharedState.tableViewModel
+      itemsInSectionWithIdentifier:BookmarkHomeSectionIdentifierBookmarks];
+  for (TableViewItem* item in items) {
+    BookmarkHomeNodeItem* nodeItem =
+        base::mac::ObjCCastStrict<BookmarkHomeNodeItem>(item);
+    const BookmarkNode* node = nodeItem.bookmarkNode;
+    if (self.sharedState.editNodes.find(node) !=
+        self.sharedState.editNodes.end()) {
+      newEditNodes.insert(node);
+      // Reselect the row of this node.
+      NSIndexPath* itemPath =
+          [self.sharedState.tableViewModel indexPathForItem:nodeItem];
+      [self.sharedState.tableView
+          selectRowAtIndexPath:itemPath
+                      animated:NO
+                scrollPosition:UITableViewScrollPositionNone];
+    }
+  }
+
+  // if editNodes is changed, update it and tell BookmarkTableViewDelegate.
+  if (self.sharedState.editNodes.size() != newEditNodes.size()) {
+    self.sharedState.editNodes = newEditNodes;
+    [self bookmarkTableView:self.bookmarksTableView
+          selectedEditNodes:self.sharedState.editNodes];
+  }
+}
+
+- (BOOL)allowsNewFolder {
+  // When the current root node has been removed remotely (becomes NULL),
+  // creating new folder is forbidden.
+  return self.sharedState.tableViewDisplayedRootNode != NULL;
+}
+
+- (CGFloat)contentPosition {
+  if (self.sharedState.tableViewDisplayedRootNode ==
+      self.sharedState.bookmarkModel->root_node()) {
+    return 0;
+  }
+  // Divided the scroll position by cell height so that it will stay correct in
+  // case the cell height is changed in future.
+  return self.sharedState.tableView.contentOffset.y /
+         [BookmarkHomeSharedState cellHeightPt];
+}
+
+- (void)setContentPosition:(CGFloat)position {
+  // The scroll position was divided by the cell height when stored.
+  [self.sharedState.tableView
+      setContentOffset:CGPointMake(
+                           0,
+                           position * [BookmarkHomeSharedState cellHeightPt])];
+}
+
+- (void)navigateAway {
+  [self.sharedState.editingFolderCell stopEdit];
+}
+
 // Returns YES if the given node is a url or folder node.
 - (BOOL)isUrlOrFolder:(const BookmarkNode*)node {
   return node->type() == BookmarkNode::URL ||
@@ -1006,6 +1213,21 @@
          !self.sharedState.tableViewDisplayedRootNode->empty();
 }
 
+- (std::vector<const bookmarks::BookmarkNode*>)getEditNodesInVector {
+  // Create a vector of edit nodes in the same order as the nodes in folder.
+  std::vector<const bookmarks::BookmarkNode*> nodes;
+  int childCount = self.sharedState.tableViewDisplayedRootNode->child_count();
+  for (int i = 0; i < childCount; ++i) {
+    const BookmarkNode* node =
+        self.sharedState.tableViewDisplayedRootNode->GetChild(i);
+    if (self.sharedState.editNodes.find(node) !=
+        self.sharedState.editNodes.end()) {
+      nodes.push_back(node);
+    }
+  }
+  return nodes;
+}
+
 #pragma mark - ContextBarDelegate implementation
 
 // Called when the leading button is clicked.
@@ -1019,7 +1241,7 @@
   switch (self.contextBarState) {
     case BookmarksContextBarDefault:
       // New Folder clicked.
-      [self.bookmarksTableView addNewFolder];
+      [self addNewFolder];
       break;
     case BookmarksContextBarBeginSelection:
       // This must never happen, as the leading button is disabled at this
@@ -1139,7 +1361,7 @@
                                       IDS_IOS_BOOKMARK_CONTEXT_BAR_NEW_FOLDER)
                         forButton:ContextBarLeadingButton];
   [self.contextBar setButtonVisibility:YES forButton:ContextBarLeadingButton];
-  [self.contextBar setButtonEnabled:[self.bookmarksTableView allowsNewFolder]
+  [self.contextBar setButtonEnabled:[self allowsNewFolder]
                           forButton:ContextBarLeadingButton];
   [self.contextBar setButtonStyle:ContextBarButtonStyleDefault
                         forButton:ContextBarLeadingButton];
@@ -1201,7 +1423,7 @@
                 style:UIAlertActionStyleDefault
               handler:^(UIAlertAction* _Nonnull action) {
                 std::vector<const BookmarkNode*> nodes =
-                    [weakSelf.bookmarksTableView getEditNodesInVector];
+                    [weakSelf getEditNodesInVector];
                 [weakSelf openAllNodes:nodes inIncognito:NO newTab:NO];
               }];
 
@@ -1211,7 +1433,7 @@
                 style:UIAlertActionStyleDefault
               handler:^(UIAlertAction* _Nonnull action) {
                 std::vector<const BookmarkNode*> nodes =
-                    [weakSelf.bookmarksTableView getEditNodesInVector];
+                    [weakSelf getEditNodesInVector];
                 [weakSelf openAllNodes:nodes inIncognito:YES newTab:NO];
               }];
 
@@ -1348,6 +1570,71 @@
   return alert;
 }
 
+#pragma mark - Favicon Handling
+
+- (void)updateCellAtIndexPath:(NSIndexPath*)indexPath
+                    withImage:(UIImage*)image
+              backgroundColor:(UIColor*)backgroundColor
+                    textColor:(UIColor*)textColor
+                 fallbackText:(NSString*)fallbackText {
+  BookmarkTableCell* cell =
+      [self.sharedState.tableView cellForRowAtIndexPath:indexPath];
+  if (!cell) {
+    return;
+  }
+
+  if (image) {
+    [cell setImage:image];
+  } else {
+    [cell setPlaceholderText:fallbackText
+                   textColor:textColor
+             backgroundColor:backgroundColor];
+  }
+}
+
+- (void)updateCellAtIndexPath:(NSIndexPath*)indexPath
+          withLargeIconResult:(const favicon_base::LargeIconResult&)result
+                 fallbackText:(NSString*)fallbackText {
+  UIImage* favIcon = nil;
+  UIColor* backgroundColor = nil;
+  UIColor* textColor = nil;
+
+  if (result.bitmap.is_valid()) {
+    scoped_refptr<base::RefCountedMemory> data = result.bitmap.bitmap_data;
+    favIcon = [UIImage
+        imageWithData:[NSData dataWithBytes:data->front() length:data->size()]];
+    fallbackText = nil;
+    // Update the time when the icon was last requested - postpone thus the
+    // automatic eviction of the favicon from the favicon database.
+    IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState)
+        ->TouchIconFromGoogleServer(result.bitmap.icon_url);
+  } else if (result.fallback_icon_style) {
+    backgroundColor =
+        skia::UIColorFromSkColor(result.fallback_icon_style->background_color);
+    textColor =
+        skia::UIColorFromSkColor(result.fallback_icon_style->text_color);
+  }
+
+  [self updateCellAtIndexPath:indexPath
+                    withImage:favIcon
+              backgroundColor:backgroundColor
+                    textColor:textColor
+                 fallbackText:fallbackText];
+}
+
+// Cancels all async loads of favicons. Subclasses should call this method when
+// the bookmark model is going through significant changes, then manually call
+// loadFaviconAtIndexPath: for everything that needs to be loaded; or
+// just reload relevant cells.
+- (void)cancelAllFaviconLoads {
+  _faviconTaskTracker.TryCancelAll();
+}
+
+- (void)cancelLoadingFaviconAtIndexPath:(NSIndexPath*)indexPath {
+  _faviconTaskTracker.TryCancel(
+      _faviconLoadTasks[IntegerPair(indexPath.section, indexPath.item)]);
+}
+
 #pragma mark - UIGestureRecognizerDelegate and gesture handling
 
 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
@@ -1458,12 +1745,6 @@
   self.sharedState.tableView.scrollIndicatorInsets = contentInsets;
 }
 
-#pragma mark - SigninPresenter
-
-- (void)showSignin:(ShowSigninCommand*)command {
-  [self.dispatcher showSignin:command baseViewController:self];
-}
-
 #pragma mark - BookmarkHomeSharedStateObserver
 
 - (void)sharedStateDidClearEditNodes:(BookmarkHomeSharedState*)sharedState {
@@ -1542,11 +1823,10 @@
     }
 
     // Cancel previous load attempts.
-    [self.bookmarksTableView cancelLoadingFaviconAtIndexPath:indexPath];
+    [self cancelLoadingFaviconAtIndexPath:indexPath];
     // Load the favicon from cache.  If not found, try fetching it from a Google
     // Server.
-    [self.bookmarksTableView loadFaviconAtIndexPath:indexPath
-                             continueToGoogleServer:YES];
+    [self loadFaviconAtIndexPath:indexPath continueToGoogleServer:YES];
   }
 
   return cell;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
index f267306..ec415b3a 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
@@ -8,14 +8,9 @@
 #import <UIKit/UIKit.h>
 #include <set>
 
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.h"
-
 @class BookmarkHomeSharedState;
 @class BookmarkTableView;
 class GURL;
-@protocol SigninPresenter;
-@class SigninPromoViewConfigurator;
-@class SigninPromoViewMediator;
 
 namespace bookmarks {
 class BookmarkNode;
@@ -26,11 +21,7 @@
 }
 
 // Delegate to handle actions on the table.
-@protocol BookmarkTableViewDelegate<BookmarkHomePromoItemDelegate>
-
-// Returns the SigninPromoViewMediator to use for the sign-in promo view in the
-// bookmark table view.
-@property(nonatomic, readonly) SigninPromoViewMediator* signinPromoViewMediator;
+@protocol BookmarkTableViewDelegate
 
 // Tells the delegate that a URL was selected for navigation.
 - (void)bookmarkTableView:(BookmarkTableView*)view
@@ -45,9 +36,6 @@
     selectedNodesForDeletion:
         (const std::set<const bookmarks::BookmarkNode*>&)nodes;
 
-// Returns true if a bookmarks promo cell should be shown.
-- (BOOL)bookmarkTableViewShouldShowPromoCell:(BookmarkTableView*)view;
-
 // Tells the delegate that nodes were selected in edit mode.
 - (void)bookmarkTableView:(BookmarkTableView*)view
         selectedEditNodes:
@@ -92,42 +80,11 @@
 - (instancetype)init NS_UNAVAILABLE;
 + (instancetype) new NS_UNAVAILABLE;
 
-// Called when something outside the view causes the promo state to change.
-- (void)promoStateChangedAnimated:(BOOL)animated;
-
-// Configures the sign-in promo view using |configurator|, and reloads the table
-// view if |identityChanged| is YES.
-- (void)configureSigninPromoWithConfigurator:
-            (SigninPromoViewConfigurator*)configurator
-                             identityChanged:(BOOL)identityChanged;
-
-// Called when adding a new folder
-- (void)addNewFolder;
-
-// Returns a vector of edit nodes.
-- (std::vector<const bookmarks::BookmarkNode*>)getEditNodesInVector;
-
-// Returns if current root node allows new folder to be created on it.
-- (BOOL)allowsNewFolder;
-
-// Returns the row position that is visible.
-- (CGFloat)contentPosition;
-
-// Scrolls the table view to the desired row position.
-- (void)setContentPosition:(CGFloat)position;
-
-// Called when back or done button of navigation bar is tapped.
-- (void)navigateAway;
-
-// TODO(crbug.com/840381): Temporarily made public while migrating code
-// out of BookmarkTableView.
-- (void)loadFaviconAtIndexPath:(NSIndexPath*)indexPath
-        continueToGoogleServer:(BOOL)continueToGoogleServer;
-- (void)cancelLoadingFaviconAtIndexPath:(NSIndexPath*)indexPath;
-- (void)cancelAllFaviconLoads;
-- (void)restoreRowSelection;
+// Methods to show and hide the loading spinner.
 - (void)showLoadingSpinnerBackground;
 - (void)hideLoadingSpinnerBackground;
+
+// Methods to show and hide the "no bookmarks" background.
 - (void)showEmptyBackground;
 - (void)hideEmptyBackground;
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
index 31c807a65b..f1c71c4 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
@@ -17,19 +17,13 @@
 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
 #include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
-#import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
-#import "ios/chrome/browser/ui/authentication/signin_promo_view_configurator.h"
-#import "ios/chrome/browser/ui/authentication/signin_promo_view_consumer.h"
-#import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
 #include "ios/chrome/browser/ui/bookmarks/bookmark_empty_background.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
 #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
@@ -42,45 +36,9 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-
-// NetworkTrafficAnnotationTag for fetching favicon from a Google server.
-const net::NetworkTrafficAnnotationTag kTrafficAnnotation =
-    net::DefineNetworkTrafficAnnotation("bookmarks_get_large_icon", R"(
-        semantics {
-          sender: "Bookmarks"
-          description:
-            "Sends a request to a Google server to retrieve the favicon bitmap "
-            "for a bookmark."
-          trigger:
-            "A request can be sent if Chrome does not have a favicon for a "
-            "bookmark."
-          data: "Page URL and desired icon size."
-          destination: GOOGLE_OWNED_SERVICE
-        }
-        policy {
-          cookies_allowed: NO
-          setting: "This feature cannot be disabled by settings."
-          policy_exception_justification: "Not implemented."
-        }
-      )");
-
-}  // namespace
-
 using bookmarks::BookmarkNode;
 
-// Used to store a pair of NSIntegers when storing a NSIndexPath in C++
-// collections.
-using IntegerPair = std::pair<NSInteger, NSInteger>;
-
-@interface BookmarkTableView () {
-  // Map of favicon load tasks for each index path. Used to keep track of
-  // pending favicon load operations so that they can be cancelled upon cell
-  // reuse. Keys are (section, item) pairs of cell index paths.
-  std::map<IntegerPair, base::CancelableTaskTracker::TaskId> _faviconLoadTasks;
-  // Task tracker used for async favicon loads.
-  base::CancelableTaskTracker _faviconTaskTracker;
-}
+@interface BookmarkTableView ()
 
 // State used by this table view.
 @property(nonatomic, strong) BookmarkHomeSharedState* sharedState;
@@ -119,9 +77,6 @@
     DCHECK_EQ(self.sharedState.bookmarkModel,
               ios::BookmarkModelFactory::GetForBrowserState(browserState));
 
-    // Set promo state before the tableview is created.
-    [self promoStateChangedAnimated:NO];
-
     // Create and setup tableview.
     self.sharedState.tableView =
         [[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain];
@@ -135,228 +90,8 @@
   return self;
 }
 
-- (void)dealloc {
-  _faviconTaskTracker.TryCancelAll();
-}
-
 #pragma mark - Public
 
-- (void)promoStateChangedAnimated:(BOOL)animated {
-  // We show promo cell only on the root view, that is when showing
-  // the permanent nodes.
-  BOOL promoVisible =
-      ((self.sharedState.tableViewDisplayedRootNode ==
-        self.sharedState.bookmarkModel->root_node()) &&
-       [self.delegate bookmarkTableViewShouldShowPromoCell:self]);
-
-  if (promoVisible == self.sharedState.promoVisible) {
-    return;
-  }
-  self.sharedState.promoVisible = promoVisible;
-
-  SigninPromoViewMediator* mediator = self.delegate.signinPromoViewMediator;
-  if (self.sharedState.promoVisible) {
-    DCHECK(![self.sharedState.tableViewModel
-        hasSectionForSectionIdentifier:BookmarkHomeSectionIdentifierPromo]);
-    [self.sharedState.tableViewModel
-        insertSectionWithIdentifier:BookmarkHomeSectionIdentifierPromo
-                            atIndex:0];
-    BookmarkHomePromoItem* item =
-        [[BookmarkHomePromoItem alloc] initWithType:BookmarkHomeItemTypePromo];
-    item.delegate = self.delegate;
-    [self.sharedState.tableViewModel
-                        addItem:item
-        toSectionWithIdentifier:BookmarkHomeSectionIdentifierPromo];
-    [mediator signinPromoViewVisible];
-  } else {
-    if (![mediator isInvalidClosedOrNeverVisible]) {
-      // When the sign-in view is closed, the promo state changes, but
-      // -[SigninPromoViewMediator signinPromoViewHidden] should not be called.
-      [mediator signinPromoViewHidden];
-    }
-
-    DCHECK([self.sharedState.tableViewModel
-        hasSectionForSectionIdentifier:BookmarkHomeSectionIdentifierPromo]);
-    [self.sharedState.tableViewModel
-        removeSectionWithIdentifier:BookmarkHomeSectionIdentifierPromo];
-  }
-  [self.sharedState.tableView reloadData];
-}
-
-- (void)configureSigninPromoWithConfigurator:
-            (SigninPromoViewConfigurator*)configurator
-                             identityChanged:(BOOL)identityChanged {
-  if (![self.sharedState.tableViewModel
-          hasSectionForSectionIdentifier:BookmarkHomeSectionIdentifierPromo]) {
-    return;
-  }
-
-  NSIndexPath* indexPath = [self.sharedState.tableViewModel
-      indexPathForItemType:BookmarkHomeItemTypePromo
-         sectionIdentifier:BookmarkHomeSectionIdentifierPromo];
-  BookmarkTableSigninPromoCell* signinPromoCell =
-      base::mac::ObjCCast<BookmarkTableSigninPromoCell>(
-          [self.sharedState.tableView cellForRowAtIndexPath:indexPath]);
-  if (!signinPromoCell) {
-    return;
-  }
-  // Should always reconfigure the cell size even if it has to be reloaded,
-  // to make sure it has the right size to compute the cell size.
-  [configurator configureSigninPromoView:signinPromoCell.signinPromoView];
-  if (identityChanged) {
-    // The section should be reload to update the cell height.
-    NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:indexPath.section];
-    [self.sharedState.tableView reloadSections:indexSet
-                              withRowAnimation:UITableViewRowAnimationNone];
-  }
-}
-
-- (void)addNewFolder {
-  [self.sharedState.editingFolderCell stopEdit];
-  if (!self.sharedState.tableViewDisplayedRootNode) {
-    return;
-  }
-  self.sharedState.addingNewFolder = YES;
-  base::string16 folderTitle = base::SysNSStringToUTF16(
-      l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_GROUP_DEFAULT_NAME));
-  self.sharedState.editingFolderNode =
-      self.sharedState.bookmarkModel->AddFolder(
-          self.sharedState.tableViewDisplayedRootNode,
-          self.sharedState.tableViewDisplayedRootNode->child_count(),
-          folderTitle);
-
-  BookmarkHomeNodeItem* nodeItem = [[BookmarkHomeNodeItem alloc]
-      initWithType:BookmarkHomeItemTypeBookmark
-      bookmarkNode:self.sharedState.editingFolderNode];
-  [self.sharedState.tableViewModel
-                      addItem:nodeItem
-      toSectionWithIdentifier:BookmarkHomeSectionIdentifierBookmarks];
-
-  // Insert the new folder cell at the end of the table.
-  NSIndexPath* newRowIndexPath =
-      [self.sharedState.tableViewModel indexPathForItem:nodeItem];
-  NSMutableArray* newRowIndexPaths =
-      [[NSMutableArray alloc] initWithObjects:newRowIndexPath, nil];
-  [self.sharedState.tableView beginUpdates];
-  [self.sharedState.tableView
-      insertRowsAtIndexPaths:newRowIndexPaths
-            withRowAnimation:UITableViewRowAnimationNone];
-  [self.sharedState.tableView endUpdates];
-
-  // Scroll to the end of the table
-  [self.sharedState.tableView
-      scrollToRowAtIndexPath:newRowIndexPath
-            atScrollPosition:UITableViewScrollPositionBottom
-                    animated:YES];
-}
-
-- (std::vector<const bookmarks::BookmarkNode*>)getEditNodesInVector {
-  // Create a vector of edit nodes in the same order as the nodes in folder.
-  std::vector<const bookmarks::BookmarkNode*> nodes;
-  int childCount = self.sharedState.tableViewDisplayedRootNode->child_count();
-  for (int i = 0; i < childCount; ++i) {
-    const BookmarkNode* node =
-        self.sharedState.tableViewDisplayedRootNode->GetChild(i);
-    if (self.sharedState.editNodes.find(node) !=
-        self.sharedState.editNodes.end()) {
-      nodes.push_back(node);
-    }
-  }
-  return nodes;
-}
-
-- (BOOL)allowsNewFolder {
-  // When the current root node has been removed remotely (becomes NULL),
-  // creating new folder is forbidden.
-  return self.sharedState.tableViewDisplayedRootNode != NULL;
-}
-
-- (CGFloat)contentPosition {
-  if (self.sharedState.tableViewDisplayedRootNode ==
-      self.sharedState.bookmarkModel->root_node()) {
-    return 0;
-  }
-  // Divided the scroll position by cell height so that it will stay correct in
-  // case the cell height is changed in future.
-  return self.sharedState.tableView.contentOffset.y /
-         [BookmarkHomeSharedState cellHeightPt];
-}
-
-- (void)setContentPosition:(CGFloat)position {
-  // The scroll position was divided by the cell height when stored.
-  [self.sharedState.tableView
-      setContentOffset:CGPointMake(
-                           0,
-                           position * [BookmarkHomeSharedState cellHeightPt])];
-}
-
-- (void)navigateAway {
-  [self.sharedState.editingFolderCell stopEdit];
-}
-
-#pragma mark - UIView
-
-- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
-  [super traitCollectionDidChange:previousTraitCollection];
-  // Stop edit of current bookmark folder name, if any.
-  [self.sharedState.editingFolderCell stopEdit];
-}
-
-// Row selection of the tableView will be cleared after reloadData.  This
-// function is used to restore the row selection.  It also updates editNodes in
-// case some selected nodes are removed.
-- (void)restoreRowSelection {
-  // Create a new editNodes set to check if some selected nodes are removed.
-  std::set<const bookmarks::BookmarkNode*> newEditNodes;
-
-  // Add selected nodes to editNodes only if they are not removed (still exist
-  // in the table).
-  NSArray<TableViewItem*>* items = [self.sharedState.tableViewModel
-      itemsInSectionWithIdentifier:BookmarkHomeSectionIdentifierBookmarks];
-  for (TableViewItem* item in items) {
-    BookmarkHomeNodeItem* nodeItem =
-        base::mac::ObjCCastStrict<BookmarkHomeNodeItem>(item);
-    const BookmarkNode* node = nodeItem.bookmarkNode;
-    if (self.sharedState.editNodes.find(node) !=
-        self.sharedState.editNodes.end()) {
-      newEditNodes.insert(node);
-      // Reselect the row of this node.
-      NSIndexPath* itemPath =
-          [self.sharedState.tableViewModel indexPathForItem:nodeItem];
-      [self.sharedState.tableView
-          selectRowAtIndexPath:itemPath
-                      animated:NO
-                scrollPosition:UITableViewScrollPositionNone];
-    }
-  }
-
-  // if editNodes is changed, update it and tell BookmarkTableViewDelegate.
-  if (self.sharedState.editNodes.size() != newEditNodes.size()) {
-    self.sharedState.editNodes = newEditNodes;
-    [self.delegate bookmarkTableView:self
-                   selectedEditNodes:self.sharedState.editNodes];
-  }
-}
-
-- (BOOL)shouldShowPromoCell {
-  return self.sharedState.promoVisible;
-}
-
-// Returns the bookmark node associated with |indexPath|.
-- (const BookmarkNode*)nodeAtIndexPath:(NSIndexPath*)indexPath {
-  TableViewItem* item =
-      [self.sharedState.tableViewModel itemAtIndexPath:indexPath];
-
-  if (item.type == BookmarkHomeItemTypeBookmark) {
-    BookmarkHomeNodeItem* nodeItem =
-        base::mac::ObjCCastStrict<BookmarkHomeNodeItem>(item);
-    return nodeItem.bookmarkNode;
-  }
-
-  NOTREACHED();
-  return nullptr;
-}
-
 // Shows loading spinner background view.
 - (void)showLoadingSpinnerBackground {
   if (!self.spinnerView) {
@@ -403,148 +138,4 @@
   self.sharedState.tableView.backgroundView = nil;
 }
 
-- (void)updateCellAtIndexPath:(NSIndexPath*)indexPath
-                    withImage:(UIImage*)image
-              backgroundColor:(UIColor*)backgroundColor
-                    textColor:(UIColor*)textColor
-                 fallbackText:(NSString*)fallbackText {
-  BookmarkTableCell* cell =
-      [self.sharedState.tableView cellForRowAtIndexPath:indexPath];
-  if (!cell) {
-    return;
-  }
-
-  if (image) {
-    [cell setImage:image];
-  } else {
-    [cell setPlaceholderText:fallbackText
-                   textColor:textColor
-             backgroundColor:backgroundColor];
-  }
-}
-
-- (void)updateCellAtIndexPath:(NSIndexPath*)indexPath
-          withLargeIconResult:(const favicon_base::LargeIconResult&)result
-                 fallbackText:(NSString*)fallbackText {
-  UIImage* favIcon = nil;
-  UIColor* backgroundColor = nil;
-  UIColor* textColor = nil;
-
-  if (result.bitmap.is_valid()) {
-    scoped_refptr<base::RefCountedMemory> data = result.bitmap.bitmap_data;
-    favIcon = [UIImage
-        imageWithData:[NSData dataWithBytes:data->front() length:data->size()]];
-    fallbackText = nil;
-    // Update the time when the icon was last requested - postpone thus the
-    // automatic eviction of the favicon from the favicon database.
-    IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState)
-        ->TouchIconFromGoogleServer(result.bitmap.icon_url);
-  } else if (result.fallback_icon_style) {
-    backgroundColor =
-        skia::UIColorFromSkColor(result.fallback_icon_style->background_color);
-    textColor =
-        skia::UIColorFromSkColor(result.fallback_icon_style->text_color);
-  }
-
-  [self updateCellAtIndexPath:indexPath
-                    withImage:favIcon
-              backgroundColor:backgroundColor
-                    textColor:textColor
-                 fallbackText:fallbackText];
-}
-
-// Cancels all async loads of favicons. Subclasses should call this method when
-// the bookmark model is going through significant changes, then manually call
-// loadFaviconAtIndexPath: for everything that needs to be loaded; or
-// just reload relevant cells.
-- (void)cancelAllFaviconLoads {
-  _faviconTaskTracker.TryCancelAll();
-}
-
-- (void)cancelLoadingFaviconAtIndexPath:(NSIndexPath*)indexPath {
-  _faviconTaskTracker.TryCancel(
-      _faviconLoadTasks[IntegerPair(indexPath.section, indexPath.item)]);
-}
-
-// Asynchronously loads favicon for given index path. The loads are cancelled
-// upon cell reuse automatically.  When the favicon is not found in cache, try
-// loading it from a Google server if |continueToGoogleServer| is YES,
-// otherwise, use the fall back icon style.
-- (void)loadFaviconAtIndexPath:(NSIndexPath*)indexPath
-        continueToGoogleServer:(BOOL)continueToGoogleServer {
-  const bookmarks::BookmarkNode* node = [self nodeAtIndexPath:indexPath];
-  if (node->is_folder()) {
-    return;
-  }
-
-  CGFloat scale = [UIScreen mainScreen].scale;
-  CGFloat desiredFaviconSizeInPixel =
-      scale * [BookmarkHomeSharedState desiredFaviconSizePt];
-  CGFloat minFaviconSizeInPixel =
-      scale * [BookmarkHomeSharedState minFaviconSizePt];
-
-  // Start loading a favicon.
-  __weak BookmarkTableView* weakSelf = self;
-  GURL blockURL(node->url());
-  NSString* fallbackText =
-      base::SysUTF16ToNSString(favicon::GetFallbackIconText(blockURL));
-  void (^faviconLoadedFromCacheBlock)(const favicon_base::LargeIconResult&) = ^(
-      const favicon_base::LargeIconResult& result) {
-    BookmarkTableView* strongSelf = weakSelf;
-    if (!strongSelf) {
-      return;
-    }
-    // TODO(crbug.com/697329) When fetching icon from server to replace existing
-    // cache is allowed, fetch icon from server here when cached icon is smaller
-    // than the desired size.
-    if (!result.bitmap.is_valid() && continueToGoogleServer &&
-        strongSelf.sharedState.faviconDownloadCount <
-            [BookmarkHomeSharedState maxDownloadFaviconCount]) {
-      void (^faviconLoadedFromServerBlock)(
-          favicon_base::GoogleFaviconServerRequestStatus status) =
-          ^(const favicon_base::GoogleFaviconServerRequestStatus status) {
-            if (status ==
-                favicon_base::GoogleFaviconServerRequestStatus::SUCCESS) {
-              BookmarkTableView* strongSelf = weakSelf;
-              // GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache
-              // is not cancellable.  So need to check if node has been changed
-              // before proceeding to favicon update.
-              if (!strongSelf ||
-                  [strongSelf nodeAtIndexPath:indexPath] != node) {
-                return;
-              }
-              // Favicon should be ready in cache now.  Fetch it again.
-              [strongSelf loadFaviconAtIndexPath:indexPath
-                          continueToGoogleServer:NO];
-            }
-          };  // faviconLoadedFromServerBlock
-
-      strongSelf.sharedState.faviconDownloadCount++;
-      IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState)
-          ->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
-              favicon::FaviconServerFetcherParams::CreateForMobile(
-                  node->url(), minFaviconSizeInPixel,
-                  desiredFaviconSizeInPixel),
-              /*may_page_url_be_private=*/true, kTrafficAnnotation,
-              base::BindBlockArc(faviconLoadedFromServerBlock));
-    }
-    [strongSelf updateCellAtIndexPath:indexPath
-                  withLargeIconResult:result
-                         fallbackText:fallbackText];
-  };  // faviconLoadedFromCacheBlock
-
-  base::CancelableTaskTracker::TaskId taskId =
-      IOSChromeLargeIconServiceFactory::GetForBrowserState(self.browserState)
-          ->GetLargeIconOrFallbackStyle(
-              node->url(), minFaviconSizeInPixel, desiredFaviconSizeInPixel,
-              base::BindBlockArc(faviconLoadedFromCacheBlock),
-              &_faviconTaskTracker);
-  _faviconLoadTasks[IntegerPair(indexPath.section, indexPath.item)] = taskId;
-}
-
-- (BOOL)isUrlOrFolder:(const BookmarkNode*)node {
-  return node->type() == BookmarkNode::URL ||
-         node->type() == BookmarkNode::FOLDER;
-}
-
 @end
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h b/ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h
new file mode 100644
index 0000000..4750ad6
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UI_CONSTANTS_H_
+#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UI_CONSTANTS_H_
+
+#import <Foundation/Foundation.h>
+
+// Accessibility identifier of the BookmarkEditVC toolbar delete button.
+extern NSString* const kBookmarkEditDeleteButtonIdentifier;
+// Accessibility identifier of the BookmarkFolderEditorVC toolbar delete button.
+extern NSString* const kBookmarkFolderEditorDeleteButtonIdentifier;
+
+#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UI_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.mm b/ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.mm
new file mode 100644
index 0000000..13453c41
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.mm
@@ -0,0 +1,14 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+NSString* const kBookmarkEditDeleteButtonIdentifier =
+    @"kBookmarkEditDeleteButtonIdentifier";
+NSString* const kBookmarkFolderEditorDeleteButtonIdentifier =
+    @"kBookmarkFolderEditorDeleteButtonIdentifier";
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index cb116ca..4e5796e 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -21,6 +21,7 @@
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_path_cache.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/legacy/toolbar_controller_constants.h"
@@ -215,7 +216,8 @@
   // Clear the bookmark via the UI.
   [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarLitLabel)]
       performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Delete_action")]
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kBookmarkEditDeleteButtonIdentifier)]
       performAction:grey_tap()];
 
   // Verify the bookmark is not in the BookmarkModel.
@@ -1654,7 +1656,9 @@
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Editor")]
       assertWithMatcher:grey_notNil()];
 
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Delete Folder")]
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(
+                                   kBookmarkFolderEditorDeleteButtonIdentifier)]
       performAction:grey_tap()];
 
   // Wait for Undo toast to go away from screen.
@@ -2068,7 +2072,9 @@
       performAction:grey_tap()];
 
   // Delete it.
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Delete Folder")]
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(
+                                   kBookmarkFolderEditorDeleteButtonIdentifier)]
       performAction:grey_tap()];
 
   // Wait until it's gone.
diff --git a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
index 4a7bb6c0..24ea2ba9 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
@@ -18,10 +18,6 @@
     "bookmark_table_signin_promo_cell.mm",
     "bookmark_text_field_item.h",
     "bookmark_text_field_item.mm",
-    "legacy_bookmark_parent_folder_item.h",
-    "legacy_bookmark_parent_folder_item.mm",
-    "legacy_bookmark_text_field_item.h",
-    "legacy_bookmark_text_field_item.mm",
   ]
 
   deps = [
@@ -31,7 +27,6 @@
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/authentication",
     "//ios/chrome/browser/ui/authentication:authentication_ui",
-    "//ios/chrome/browser/ui/collection_view/cells",
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/icons",
     "//ios/chrome/browser/ui/table_view:styler",
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
index 2911634..f148073 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
@@ -17,8 +17,8 @@
 
 @end
 
-// Cell class associated to BookmarkParentFolderItem.
-@interface BookmarkParentFolderCell : UITableViewCell
+// Legacy Cell class associated to BookmarkParentFolderItem.
+@interface LegacyBookmarkParentFolderCell : UITableViewCell
 
 // Label that displays the item's title.
 @property(nonatomic, readonly, strong) UILabel* parentFolderNameLabel;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
index da67b89..793f81b 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
@@ -24,7 +24,7 @@
   self = [super initWithType:type];
   if (self) {
     self.accessibilityIdentifier = @"Change Folder";
-    self.cellClass = [BookmarkParentFolderCell class];
+    self.cellClass = [LegacyBookmarkParentFolderCell class];
   }
   return self;
 }
@@ -34,19 +34,19 @@
 - (void)configureCell:(UITableViewCell*)tableCell
            withStyler:(ChromeTableViewStyler*)styler {
   [super configureCell:tableCell withStyler:styler];
-  BookmarkParentFolderCell* cell =
-      base::mac::ObjCCastStrict<BookmarkParentFolderCell>(tableCell);
+  LegacyBookmarkParentFolderCell* cell =
+      base::mac::ObjCCastStrict<LegacyBookmarkParentFolderCell>(tableCell);
   cell.parentFolderNameLabel.text = self.title;
 }
 
 @end
 
-@interface BookmarkParentFolderCell ()
+@interface LegacyBookmarkParentFolderCell ()
 @property(nonatomic, readwrite, strong) UILabel* parentFolderNameLabel;
 @property(nonatomic, strong) UILabel* decorationLabel;
 @end
 
-@implementation BookmarkParentFolderCell
+@implementation LegacyBookmarkParentFolderCell
 
 @synthesize parentFolderNameLabel = _parentFolderNameLabel;
 @synthesize decorationLabel = _decorationLabel;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm
index 55d823c..a34862f 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm
@@ -21,8 +21,8 @@
 TEST_F(BookmarkParentFolderItemTest, LabelGetsTitle) {
   BookmarkParentFolderItem* item =
       [[BookmarkParentFolderItem alloc] initWithType:0];
-  BookmarkParentFolderCell* cell =
-      [[BookmarkParentFolderCell alloc] initWithFrame:CGRectZero];
+  LegacyBookmarkParentFolderCell* cell =
+      [[LegacyBookmarkParentFolderCell alloc] initWithFrame:CGRectZero];
   ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
 
   item.title = @"Foo";
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
index 51fd641..2122d93 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
@@ -34,7 +34,7 @@
 
 @end
 
-@interface BookmarkTextFieldCell : UITableViewCell
+@interface LegacyBookmarkTextFieldCell : UITableViewCell
 
 // Text field to display the title or the URL of the bookmark node.
 @property(nonatomic, readonly, strong) UITextField<TextFieldStyling>* textField;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
index e7364e49..e7540e7 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
@@ -23,7 +23,7 @@
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
   if (self) {
-    self.cellClass = [BookmarkTextFieldCell class];
+    self.cellClass = [LegacyBookmarkTextFieldCell class];
   }
   return self;
 }
@@ -34,8 +34,8 @@
            withStyler:(ChromeTableViewStyler*)styler {
   [super configureCell:tableCell withStyler:styler];
 
-  BookmarkTextFieldCell* cell =
-      base::mac::ObjCCastStrict<BookmarkTextFieldCell>(tableCell);
+  LegacyBookmarkTextFieldCell* cell =
+      base::mac::ObjCCastStrict<LegacyBookmarkTextFieldCell>(tableCell);
   cell.textField.text = self.text;
   cell.textField.placeholder = self.placeholder;
   cell.textField.tag = self.type;
@@ -58,12 +58,12 @@
 
 @end
 
-@interface BookmarkTextFieldCell ()
+@interface LegacyBookmarkTextFieldCell ()
 @property(nonatomic, readwrite, strong)
     UITextField<TextFieldStyling>* textField;
 @end
 
-@implementation BookmarkTextFieldCell
+@implementation LegacyBookmarkTextFieldCell
 
 @synthesize textField = _textField;
 
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm
index eebf1ed1..a11a219 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm
@@ -20,8 +20,8 @@
 
 TEST_F(BookmarkTextFieldItemTest, DelegateGetsTextFieldEvents) {
   BookmarkTextFieldItem* item = [[BookmarkTextFieldItem alloc] initWithType:0];
-  BookmarkTextFieldCell* cell =
-      [[BookmarkTextFieldCell alloc] initWithFrame:CGRectZero];
+  LegacyBookmarkTextFieldCell* cell =
+      [[LegacyBookmarkTextFieldCell alloc] initWithFrame:CGRectZero];
   id mockDelegate =
       [OCMockObject mockForProtocol:@protocol(BookmarkTextFieldItemDelegate)];
   ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
@@ -36,8 +36,8 @@
 
 TEST_F(BookmarkTextFieldItemTest, TextFieldGetsText) {
   BookmarkTextFieldItem* item = [[BookmarkTextFieldItem alloc] initWithType:0];
-  BookmarkTextFieldCell* cell =
-      [[BookmarkTextFieldCell alloc] initWithFrame:CGRectZero];
+  LegacyBookmarkTextFieldCell* cell =
+      [[LegacyBookmarkTextFieldCell alloc] initWithFrame:CGRectZero];
   ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
 
   item.text = @"Foo";
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h
deleted file mode 100644
index 0d36c90..0000000
--- a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h
+++ /dev/null
@@ -1,29 +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 IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_PARENT_FOLDER_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_PARENT_FOLDER_ITEM_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
-
-// Item to display the name of the parent folder of a bookmark node.
-@interface LegacyBookmarkParentFolderItem : CollectionViewItem
-
-// The title of the bookmark folder it represents.
-@property(nonatomic, copy) NSString* title;
-
-@end
-
-// Cell class associated to LegacyBookmarkParentFolderItem.
-@interface LegacyBookmarkParentFolderCell : MDCCollectionViewCell
-
-// Label that displays the item's title.
-@property(nonatomic, readonly, strong) UILabel* parentFolderNameLabel;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_PARENT_FOLDER_ITEM_H_
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.mm
deleted file mode 100644
index 76e1f6c5..0000000
--- a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.mm
+++ /dev/null
@@ -1,124 +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.
-
-#import "ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h"
-
-#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
-#import "ios/chrome/browser/ui/icons/chrome_icon.h"
-#import "ios/chrome/browser/ui/uikit_ui_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface LegacyBookmarkParentFolderCell ()
-@property(nonatomic, readwrite, strong) UILabel* parentFolderNameLabel;
-@property(nonatomic, strong) UILabel* decorationLabel;
-@end
-
-@implementation LegacyBookmarkParentFolderItem
-
-@synthesize title = _title;
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.accessibilityIdentifier = @"Change Folder";
-    self.cellClass = [LegacyBookmarkParentFolderCell class];
-  }
-  return self;
-}
-
-#pragma mark CollectionViewItem
-
-- (void)configureCell:(LegacyBookmarkParentFolderCell*)cell {
-  [super configureCell:cell];
-  cell.parentFolderNameLabel.text = self.title;
-}
-
-@end
-
-@implementation LegacyBookmarkParentFolderCell
-
-@synthesize parentFolderNameLabel = _parentFolderNameLabel;
-@synthesize decorationLabel = _decorationLabel;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (!self)
-    return nil;
-
-  self.isAccessibilityElement = YES;
-  self.accessibilityTraits |= UIAccessibilityTraitButton;
-
-  const CGFloat kHorizontalPadding = 15;
-  const CGFloat kVerticalPadding = 8;
-  const CGFloat kParentFolderLabelTopPadding = 7;
-
-  _decorationLabel = [[UILabel alloc] init];
-  _decorationLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  _decorationLabel.text = l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_BUTTON);
-  _decorationLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
-  _decorationLabel.textColor = bookmark_utils_ios::lightTextColor();
-  [self.contentView addSubview:_decorationLabel];
-
-  _parentFolderNameLabel = [[UILabel alloc] init];
-  _parentFolderNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  _parentFolderNameLabel.font =
-      [[MDCTypography fontLoader] regularFontOfSize:16];
-  _parentFolderNameLabel.textColor =
-      [UIColor colorWithWhite:33.0 / 255.0 alpha:1.0];
-  _parentFolderNameLabel.textAlignment = NSTextAlignmentNatural;
-  [self.contentView addSubview:_parentFolderNameLabel];
-
-  UIImageView* navigationChevronImage = [[UIImageView alloc] init];
-  UIImage* image = TintImage([ChromeIcon chevronIcon], [UIColor grayColor]);
-  navigationChevronImage.image = image;
-  navigationChevronImage.translatesAutoresizingMaskIntoConstraints = NO;
-  [self.contentView addSubview:navigationChevronImage];
-
-  // Set up the constraints.
-  [NSLayoutConstraint activateConstraints:@[
-    [_decorationLabel.topAnchor constraintEqualToAnchor:self.topAnchor
-                                               constant:kVerticalPadding],
-    [_decorationLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
-                                                   constant:kHorizontalPadding],
-    [_parentFolderNameLabel.topAnchor
-        constraintEqualToAnchor:_decorationLabel.bottomAnchor
-                       constant:kParentFolderLabelTopPadding],
-    [_parentFolderNameLabel.leadingAnchor
-        constraintEqualToAnchor:_decorationLabel.leadingAnchor],
-    [navigationChevronImage.centerYAnchor
-        constraintEqualToAnchor:_parentFolderNameLabel.centerYAnchor],
-    [navigationChevronImage.leadingAnchor
-        constraintEqualToAnchor:_parentFolderNameLabel.trailingAnchor],
-    [navigationChevronImage.widthAnchor
-        constraintEqualToConstant:navigationChevronImage.image.size.width],
-    [navigationChevronImage.trailingAnchor
-        constraintEqualToAnchor:self.trailingAnchor
-                       constant:-kHorizontalPadding],
-  ]];
-
-  self.shouldHideSeparator = YES;
-  return self;
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  self.parentFolderNameLabel.text = nil;
-}
-
-- (NSString*)accessibilityLabel {
-  return self.parentFolderNameLabel.text;
-}
-
-- (NSString*)accessibilityHint {
-  return l10n_util::GetNSString(
-      IDS_IOS_BOOKMARK_EDIT_PARENT_FOLDER_BUTTON_HINT);
-}
-
-@end
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h
deleted file mode 100644
index b2fc511..0000000
--- a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h
+++ /dev/null
@@ -1,45 +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 IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_TEXT_FIELD_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_TEXT_FIELD_ITEM_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
-
-@class LegacyBookmarkTextFieldItem;
-@protocol TextFieldStyling;
-
-// Delegates the cell's text field's events.
-@protocol LegacyBookmarkTextFieldItemDelegate<UITextFieldDelegate>
-
-// Called when the |text| of the item was changed via the textfield. The item's
-// |text| is up-to-date when this is called.
-- (void)textDidChangeForItem:(LegacyBookmarkTextFieldItem*)item;
-
-@end
-
-@interface LegacyBookmarkTextFieldItem : CollectionViewItem
-
-// The text field content.
-@property(nonatomic, copy) NSString* text;
-
-// The text field placeholder.
-@property(nonatomic, copy) NSString* placeholder;
-
-// Receives the text field events.
-@property(nonatomic, weak) id<LegacyBookmarkTextFieldItemDelegate> delegate;
-
-@end
-
-@interface LegacyBookmarkTextFieldCell : MDCCollectionViewCell
-
-// Text field to display the title or the URL of the bookmark node.
-@property(nonatomic, readonly, strong) UITextField<TextFieldStyling>* textField;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_TEXT_FIELD_ITEM_H_
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.mm b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.mm
deleted file mode 100644
index b6acb9b..0000000
--- a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.mm
+++ /dev/null
@@ -1,103 +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.
-
-#import "ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h"
-
-#include "base/logging.h"
-#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
-#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#import "ios/public/provider/chrome/browser/ui/text_field_styling.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface LegacyBookmarkTextFieldCell ()
-@property(nonatomic, readwrite, strong)
-    UITextField<TextFieldStyling>* textField;
-@end
-
-@implementation LegacyBookmarkTextFieldItem
-
-@synthesize text = _text;
-@synthesize placeholder = _placeholder;
-@synthesize delegate = _delegate;
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [LegacyBookmarkTextFieldCell class];
-  }
-  return self;
-}
-
-#pragma mark CollectionViewItem
-
-- (void)configureCell:(LegacyBookmarkTextFieldCell*)cell {
-  [super configureCell:cell];
-  cell.textField.text = self.text;
-  cell.textField.placeholder = self.placeholder;
-  cell.textField.tag = self.type;
-  [cell.textField addTarget:self
-                     action:@selector(textFieldDidChange:)
-           forControlEvents:UIControlEventEditingChanged];
-  cell.textField.delegate = self.delegate;
-  cell.textField.accessibilityLabel = self.text;
-  cell.textField.accessibilityIdentifier =
-      [NSString stringWithFormat:@"%@_textField", self.accessibilityIdentifier];
-}
-
-#pragma mark UIControlEventEditingChanged
-
-- (void)textFieldDidChange:(UITextField*)textField {
-  DCHECK_EQ(textField.tag, self.type);
-  self.text = textField.text;
-  [self.delegate textDidChangeForItem:self];
-}
-
-@end
-
-@implementation LegacyBookmarkTextFieldCell
-
-@synthesize textField = _textField;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    _textField =
-        ios::GetChromeBrowserProvider()->CreateStyledTextField(CGRectZero);
-    _textField.translatesAutoresizingMaskIntoConstraints = NO;
-    _textField.textColor = bookmark_utils_ios::darkTextColor();
-    _textField.clearButtonMode = UITextFieldViewModeWhileEditing;
-    _textField.placeholderStyle =
-        TextFieldStylingPlaceholderFloatingPlaceholder;
-    [self.contentView addSubview:_textField];
-    const CGFloat kHorizontalPadding = 15;
-    const CGFloat kTopPadding = 8;
-    [NSLayoutConstraint activateConstraints:@[
-      [_textField.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
-                                               constant:kHorizontalPadding],
-      [_textField.topAnchor constraintEqualToAnchor:self.topAnchor
-                                           constant:kTopPadding],
-      [_textField.trailingAnchor constraintEqualToAnchor:self.trailingAnchor
-                                                constant:-kHorizontalPadding],
-    ]];
-
-    self.shouldHideSeparator = YES;
-  }
-  return self;
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  [self.textField resignFirstResponder];
-  [self.textField removeTarget:nil
-                        action:NULL
-              forControlEvents:UIControlEventAllEvents];
-  self.textField.delegate = nil;
-  self.textField.text = nil;
-  self.textField.textValidator = nil;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
index f3fb6ea5..43a18ab 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -129,12 +129,12 @@
 }
 
 void FullscreenWebStateObserver::SetIsLoading(bool loading) {
-  if (IsUIRefreshPhase1Enabled()) {
-    if (loading)
-      controller_->ResetModel();
-  } else {
-    loading_disabler_ =
-        loading ? std::make_unique<ScopedFullscreenDisabler>(controller_)
-                : nullptr;
-  }
+  if (IsUIRefreshPhase1Enabled())
+    return;
+
+  if (!!loading_disabler_.get() == loading)
+    return;
+  loading_disabler_ =
+      loading ? std::make_unique<ScopedFullscreenDisabler>(controller_)
+              : nullptr;
 }
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 5adfb43..e7fdd899 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -147,7 +147,7 @@
     "//ios/chrome/browser/find_in_page:unit_tests",
     "//ios/chrome/browser/geolocation:unit_tests",
     "//ios/chrome/browser/history:unit_tests",
-    "//ios/chrome/browser/itunes_links:unit_tests",
+    "//ios/chrome/browser/itunes_urls:unit_tests",
     "//ios/chrome/browser/language:unit_tests",
     "//ios/chrome/browser/metrics:unit_tests",
     "//ios/chrome/browser/metrics:unit_tests_internal",
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
index fff8665..85e0fea 100644
--- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -21,6 +21,7 @@
 #include "media/base/cdm_key_information.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
+#include "media/base/encryption_pattern.h"
 #include "media/cdm/api/content_decryption_module_ext.h"
 #include "media/cdm/json_web_key.h"
 #include "media/cdm/library_cdm/cdm_host_proxy.h"
@@ -95,23 +96,32 @@
   output_buffer->set_timestamp(
       base::TimeDelta::FromMicroseconds(input_buffer.timestamp));
 
-  // TODO(crbug.com/658026): Support other schemes.
-  if (input_buffer.encryption_scheme == cdm::EncryptionScheme::kCenc) {
-    DCHECK_GT(input_buffer.iv_size, 0u);
-    DCHECK_GT(input_buffer.key_id_size, 0u);
-    std::vector<media::SubsampleEntry> subsamples;
-    for (uint32_t i = 0; i < input_buffer.num_subsamples; ++i) {
-      subsamples.push_back(
-          media::SubsampleEntry(input_buffer.subsamples[i].clear_bytes,
-                                input_buffer.subsamples[i].cipher_bytes));
-    }
+  if (input_buffer.encryption_scheme == cdm::EncryptionScheme::kUnencrypted)
+    return output_buffer;
 
+  DCHECK_GT(input_buffer.iv_size, 0u);
+  DCHECK_GT(input_buffer.key_id_size, 0u);
+  std::vector<media::SubsampleEntry> subsamples;
+  for (uint32_t i = 0; i < input_buffer.num_subsamples; ++i) {
+    subsamples.push_back(
+        media::SubsampleEntry(input_buffer.subsamples[i].clear_bytes,
+                              input_buffer.subsamples[i].cipher_bytes));
+  }
+
+  const std::string key_id_string(
+      reinterpret_cast<const char*>(input_buffer.key_id),
+      input_buffer.key_id_size);
+  const std::string iv_string(reinterpret_cast<const char*>(input_buffer.iv),
+                              input_buffer.iv_size);
+  if (input_buffer.encryption_scheme == cdm::EncryptionScheme::kCenc) {
     output_buffer->set_decrypt_config(media::DecryptConfig::CreateCencConfig(
-        std::string(reinterpret_cast<const char*>(input_buffer.key_id),
-                    input_buffer.key_id_size),
-        std::string(reinterpret_cast<const char*>(input_buffer.iv),
-                    input_buffer.iv_size),
-        subsamples));
+        key_id_string, iv_string, subsamples));
+  } else {
+    DCHECK_EQ(input_buffer.encryption_scheme, cdm::EncryptionScheme::kCbcs);
+    output_buffer->set_decrypt_config(media::DecryptConfig::CreateCbcsConfig(
+        key_id_string, iv_string, subsamples,
+        media::EncryptionPattern(input_buffer.pattern.crypt_byte_block,
+                                 input_buffer.pattern.skip_byte_block)));
   }
 
   return output_buffer;
@@ -362,36 +372,6 @@
 
 namespace {
 
-bool IsSupportedConfigEncryptionScheme(cdm::EncryptionScheme scheme) {
-  // TODO(crbug.com/658026): Support other decryption schemes.
-  switch (scheme) {
-    case cdm::EncryptionScheme::kUnencrypted:
-    case cdm::EncryptionScheme::kCenc:
-      return true;
-    case cdm::EncryptionScheme::kCbcs:
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-bool IsSupportedBufferEncryptionScheme(cdm::EncryptionScheme scheme,
-                                       cdm::Pattern pattern) {
-  // TODO(crbug.com/658026): Support other decryption schemes.
-  switch (scheme) {
-    case cdm::EncryptionScheme::kUnencrypted:
-      return true;
-    case cdm::EncryptionScheme::kCenc:
-      return pattern.crypt_byte_block == 0 && pattern.skip_byte_block == 0;
-    case cdm::EncryptionScheme::kCbcs:
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
 cdm::InputBuffer_2 ToInputBuffer_2(cdm::InputBuffer_1 encrypted_buffer) {
   cdm::InputBuffer_2 buffer = {};
   buffer.data = encrypted_buffer.data;
@@ -707,11 +687,6 @@
   if (key_system_ == kExternalClearKeyDecryptOnlyKeySystem)
     return cdm::kInitializationError;
 
-  if (!IsSupportedConfigEncryptionScheme(
-          audio_decoder_config.encryption_scheme)) {
-    return cdm::kInitializationError;
-  }
-
 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
   if (!audio_decoder_)
     audio_decoder_.reset(
@@ -744,11 +719,6 @@
   if (key_system_ == kExternalClearKeyDecryptOnlyKeySystem)
     return cdm::kInitializationError;
 
-  if (!IsSupportedConfigEncryptionScheme(
-          video_decoder_config.encryption_scheme)) {
-    return cdm::kInitializationError;
-  }
-
   if (video_decoder_ && video_decoder_->is_initialized()) {
     DCHECK(!video_decoder_->is_initialized());
     return cdm::kInitializationError;
@@ -894,11 +864,6 @@
     scoped_refptr<DecoderBuffer>* decrypted_buffer) {
   DCHECK(decrypted_buffer);
 
-  if (!IsSupportedBufferEncryptionScheme(encrypted_buffer.encryption_scheme,
-                                         encrypted_buffer.pattern)) {
-    return cdm::kDecryptError;
-  }
-
   scoped_refptr<DecoderBuffer> buffer = CopyDecoderBufferFrom(encrypted_buffer);
 
   // EOS and unencrypted streams can be returned as-is.
diff --git a/mojo/public/cpp/bindings/interface_ptr_set.h b/mojo/public/cpp/bindings/interface_ptr_set.h
index 185cbff..17f90b1 100644
--- a/mojo/public/cpp/bindings/interface_ptr_set.h
+++ b/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -77,8 +77,10 @@
     if (it == ptrs_.end())
       return Ptr<Interface>();
     Ptr<Interface> ptr;
-    if (it->second)
+    if (it->second) {
       ptr = it->second->Take();
+      delete it->second.get();
+    }
     ptrs_.erase(it);
     return ptr;
   }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 14dc74c..5e59e77 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -157,7 +157,6 @@
     "cert/asn1_util.h",
     "cert/cert_database.cc",
     "cert/cert_database.h",
-    "cert/cert_database_stub.cc",
     "cert/cert_status_flags.cc",
     "cert/cert_status_flags.h",
     "cert/cert_status_flags_list.h",
@@ -513,11 +512,7 @@
       "base/winsock_util.h",
       "cert/caching_cert_verifier.cc",
       "cert/caching_cert_verifier.h",
-      "cert/cert_database_android.cc",
-      "cert/cert_database_ios.cc",
       "cert/cert_database_mac.cc",
-      "cert/cert_database_nss.cc",
-      "cert/cert_database_win.cc",
       "cert/cert_net_fetcher.cc",
       "cert/cert_net_fetcher.h",
       "cert/cert_verify_proc.cc",
@@ -1902,10 +1897,7 @@
     }
 
     if (!is_nacl) {
-      sources -= [
-        "base/network_interfaces_nacl.cc",
-        "cert/cert_database_stub.cc",
-      ]
+      sources -= [ "base/network_interfaces_nacl.cc" ]
     }
 
     # Use getifaddrs() on POSIX platforms, except Linux and Android.
@@ -1922,7 +1914,6 @@
 
     if (!use_nss_certs) {
       sources -= [
-        "cert/cert_database_nss.cc",
         "cert/internal/trust_store_nss.cc",
         "cert/internal/trust_store_nss.h",
         "cert/known_roots_nss.cc",
@@ -2045,7 +2036,6 @@
       sources += [
         "base/network_interfaces_fuchsia.cc",
         "base/platform_mime_util_fuchsia.cc",
-        "cert/cert_database_fuchsia.cc",
         "cert/test_root_certs_fuchsia.cc",
       ]
       deps += [ "//third_party/fuchsia-sdk:netstack" ]
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index 7553463..08326902 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "net/base/address_list.h"
 
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/sys_byteorder.h"
 #include "net/base/ip_address.h"
@@ -122,9 +123,9 @@
 
   // Construct a list of ip addresses.
   IPAddressList ip_list;
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (const auto& test : tests) {
     IPAddress ip_address;
-    ASSERT_TRUE(ip_address.AssignFromIPLiteral(tests[i].ip_address));
+    ASSERT_TRUE(ip_address.AssignFromIPLiteral(test.ip_address));
     ip_list.push_back(ip_address);
   }
 
@@ -132,7 +133,7 @@
                                                                kCanonicalName);
   std::string canonical_name;
   EXPECT_EQ(kCanonicalName, test_list.canonical_name());
-  EXPECT_EQ(arraysize(tests), test_list.size());
+  EXPECT_EQ(base::size(tests), test_list.size());
 }
 
 }  // namespace
diff --git a/net/base/chunked_upload_data_stream_unittest.cc b/net/base/chunked_upload_data_stream_unittest.cc
index 59d515e1..0b57658 100644
--- a/net/base/chunked_upload_data_stream_unittest.cc
+++ b/net/base/chunked_upload_data_stream_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <string>
 
+#include "base/stl_util.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -23,9 +24,9 @@
 
 namespace {
 
-const char kTestData[] = "0123456789";
-const size_t kTestDataSize = arraysize(kTestData) - 1;
-const size_t kTestBufferSize = 1 << 14;  // 16KB.
+constexpr char kTestData[] = "0123456789";
+constexpr size_t kTestDataSize = base::size(kTestData) - 1;
+constexpr size_t kTestBufferSize = 1 << 14;  // 16KB.
 
 }  // namespace
 
diff --git a/net/base/data_url.cc b/net/base/data_url.cc
index 1676fa6..878b1eb 100644
--- a/net/base/data_url.cc
+++ b/net/base/data_url.cc
@@ -52,9 +52,8 @@
     ++iter;
   }
 
-  static const char kBase64Tag[] = "base64";
-  static const char kCharsetTag[] = "charset=";
-  const size_t kCharsetTagLength = arraysize(kCharsetTag) - 1;
+  static constexpr base::StringPiece kBase64Tag("base64");
+  static constexpr base::StringPiece kCharsetTag("charset=");
 
   bool base64_encoded = false;
   for (; iter != meta_data.cend(); ++iter) {
@@ -63,7 +62,7 @@
     } else if (charset->empty() &&
                base::StartsWith(*iter, kCharsetTag,
                                 base::CompareCase::SENSITIVE)) {
-      *charset = std::string(iter->substr(kCharsetTagLength));
+      *charset = std::string(iter->substr(kCharsetTag.size()));
       // The grammar for charset is not specially defined in RFC2045 and
       // RFC2397. It just needs to be a token.
       if (!HttpUtil::IsToken(*charset))
diff --git a/net/base/data_url_unittest.cc b/net/base/data_url_unittest.cc
index 1b2d036c..2b3669a 100644
--- a/net/base/data_url_unittest.cc
+++ b/net/base/data_url_unittest.cc
@@ -233,16 +233,16 @@
     // TODO(darin): add more interesting tests
   };
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (const auto& test : tests) {
     std::string mime_type;
     std::string charset;
     std::string data;
-    bool ok = DataURL::Parse(GURL(tests[i].url), &mime_type, &charset, &data);
-    EXPECT_EQ(ok, tests[i].is_valid);
-    if (tests[i].is_valid) {
-      EXPECT_EQ(tests[i].mime_type, mime_type);
-      EXPECT_EQ(tests[i].charset, charset);
-      EXPECT_EQ(tests[i].data, data);
+    bool ok = DataURL::Parse(GURL(test.url), &mime_type, &charset, &data);
+    EXPECT_EQ(ok, test.is_valid);
+    if (test.is_valid) {
+      EXPECT_EQ(test.mime_type, mime_type);
+      EXPECT_EQ(test.charset, charset);
+      EXPECT_EQ(test.data, data);
     }
   }
 }
diff --git a/net/base/directory_listing_unittest.cc b/net/base/directory_listing_unittest.cc
index 4f888c0..2fcbb0e6 100644
--- a/net/base/directory_listing_unittest.cc
+++ b/net/base/directory_listing_unittest.cc
@@ -43,11 +43,11 @@
        ",0,10000,\"9.8 kB\",0,\"\");</script>\n"},
   };
 
-  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+  for (const auto& test_case : test_cases) {
     const std::string results = GetDirectoryListingEntry(
-        base::WideToUTF16(test_cases[i].name), test_cases[i].raw_bytes,
-        test_cases[i].is_dir, test_cases[i].filesize, test_cases[i].time);
-    EXPECT_EQ(test_cases[i].expected, results);
+        base::WideToUTF16(test_case.name), test_case.raw_bytes,
+        test_case.is_dir, test_case.filesize, test_case.time);
+    EXPECT_EQ(test_case.expected, results);
   }
 }
 
diff --git a/net/base/elements_upload_data_stream_unittest.cc b/net/base/elements_upload_data_stream_unittest.cc
index a967d213..92ff1c6 100644
--- a/net/base/elements_upload_data_stream_unittest.cc
+++ b/net/base/elements_upload_data_stream_unittest.cc
@@ -17,6 +17,8 @@
 #include "base/location.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
@@ -45,7 +47,7 @@
 namespace {
 
 const char kTestData[] = "0123456789";
-const size_t kTestDataSize = arraysize(kTestData) - 1;
+const size_t kTestDataSize = base::size(kTestData) - 1;
 const size_t kTestBufferSize = 1 << 14;  // 16KB.
 
 // Reads data from the upload data stream, and returns the data as string.
@@ -284,7 +286,7 @@
 
   // Run Init().
   ASSERT_THAT(stream->Init(CompletionCallback(), NetLogWithSource()), IsOk());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
   EXPECT_EQ(0U, stream->position());
   EXPECT_FALSE(stream->IsEOF());
 
@@ -322,7 +324,7 @@
   ASSERT_THAT(stream->Init(init_callback.callback(), NetLogWithSource()),
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(init_callback.WaitForResult(), IsOk());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
   EXPECT_EQ(0U, stream->position());
   EXPECT_FALSE(stream->IsEOF());
 
@@ -533,9 +535,8 @@
 
   // Consume the third and the fourth elements.
   TestCompletionCallback read_callback3;
-  ASSERT_EQ(
-      ERR_IO_PENDING,
-      stream->Read(buf.get(), kTestDataSize * 2, read_callback3.callback()));
+  ASSERT_EQ(ERR_IO_PENDING, stream->Read(buf.get(), kTestDataSize * 2,
+                                         read_callback3.callback()));
   EXPECT_EQ(static_cast<int>(kTestDataSize * 2),
             read_callback3.WaitForResult());
 }
@@ -606,7 +607,7 @@
               IsError(ERR_IO_PENDING));
   ASSERT_THAT(init_callback1.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read.
   EXPECT_EQ(expected_data, ReadFromUploadDataStream(stream.get()));
@@ -618,7 +619,7 @@
               IsError(ERR_IO_PENDING));
   ASSERT_THAT(init_callback2.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read again.
   EXPECT_EQ(expected_data, ReadFromUploadDataStream(stream.get()));
@@ -650,7 +651,7 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(test_callback.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read.
   EXPECT_EQ(expected_data, ReadFromUploadDataStream(stream.get()));
@@ -661,7 +662,7 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(test_callback.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read again.
   EXPECT_EQ(expected_data, ReadFromUploadDataStream(stream.get()));
@@ -694,11 +695,11 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(init_callback1.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read some.
   TestCompletionCallback read_callback1;
-  std::vector<char> buf(kTestDataSize + kTestDataSize/2);
+  std::vector<char> buf(kTestDataSize + kTestDataSize / 2);
   scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
   EXPECT_EQ(
       ERR_IO_PENDING,
@@ -713,11 +714,11 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read.
   TestCompletionCallback read_callback2;
-  std::vector<char> buf2(kTestDataSize*2);
+  std::vector<char> buf2(kTestDataSize * 2);
   scoped_refptr<IOBuffer> wrapped_buffer2 = new WrappedIOBuffer(&buf2[0]);
   EXPECT_EQ(ERR_IO_PENDING,
             stream->Read(
@@ -757,11 +758,11 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read.
   TestCompletionCallback read_callback2;
-  std::vector<char> buf2(kTestDataSize*2);
+  std::vector<char> buf2(kTestDataSize * 2);
   scoped_refptr<IOBuffer> wrapped_buffer2 = new WrappedIOBuffer(&buf2[0]);
   EXPECT_EQ(ERR_IO_PENDING,
             stream->Read(
@@ -800,11 +801,11 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(init_callback1.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Start reading.
   TestCompletionCallback read_callback1;
-  std::vector<char> buf(kTestDataSize*2);
+  std::vector<char> buf(kTestDataSize * 2);
   scoped_refptr<IOBuffer> wrapped_buffer = new WrappedIOBuffer(&buf[0]);
   EXPECT_EQ(
       ERR_IO_PENDING,
@@ -817,11 +818,11 @@
               IsError(ERR_IO_PENDING));
   EXPECT_THAT(init_callback2.WaitForResult(), IsOk());
   EXPECT_FALSE(stream->IsEOF());
-  EXPECT_EQ(kTestDataSize*2, stream->size());
+  EXPECT_EQ(kTestDataSize * 2, stream->size());
 
   // Read.
   TestCompletionCallback read_callback2;
-  std::vector<char> buf2(kTestDataSize*2);
+  std::vector<char> buf2(kTestDataSize * 2);
   scoped_refptr<IOBuffer> wrapped_buffer2 = new WrappedIOBuffer(&buf2[0]);
   EXPECT_EQ(ERR_IO_PENDING,
             stream->Read(
diff --git a/net/base/escape.cc b/net/base/escape.cc
index 7427fb63..35d37c7f 100644
--- a/net/base/escape.cc
+++ b/net/base/escape.cc
@@ -5,6 +5,7 @@
 #include "net/base/escape.h"
 
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "base/strings/utf_string_conversions.h"
@@ -143,7 +144,7 @@
     // reach max character length number of bytes, or hit an unescaped
     // character. No need to check length of escaped_text, as
     // UnescapeUnsignedByteAtIndex checks lengths.
-    while (num_bytes < arraysize(bytes) &&
+    while (num_bytes < base::size(bytes) &&
            UnescapeUnsignedByteAtIndex(escaped_text, index + num_bytes * 3,
                                        &bytes[num_bytes]) &&
            CBU8_IS_TRAIL(bytes[num_bytes])) {
@@ -323,9 +324,9 @@
 
 template <class str>
 void AppendEscapedCharForHTMLImpl(typename str::value_type c, str* output) {
-  static const struct {
+  static constexpr struct {
     char key;
-    const char* replacement;
+    base::StringPiece replacement;
   } kCharsToEscape[] = {
     { '<', "&lt;" },
     { '>', "&gt;" },
@@ -333,17 +334,14 @@
     { '"', "&quot;" },
     { '\'', "&#39;" },
   };
-  size_t k;
-  for (k = 0; k < arraysize(kCharsToEscape); ++k) {
-    if (c == kCharsToEscape[k].key) {
-      const char* p = kCharsToEscape[k].replacement;
-      while (*p)
-        output->push_back(*p++);
-      break;
+  for (const auto& char_to_escape : kCharsToEscape) {
+    if (c == char_to_escape.key) {
+      output->append(std::begin(char_to_escape.replacement),
+                     std::end(char_to_escape.replacement));
+      return;
     }
   }
-  if (k == arraysize(kCharsToEscape))
-    output->push_back(c);
+  output->push_back(c);
 }
 
 template <class str>
@@ -522,14 +520,14 @@
   if (input.find(base::ASCIIToUTF16("&")) == std::string::npos)
     return input.as_string();
 
-  base::string16 ampersand_chars[arraysize(kEscapeToChars)];
+  base::string16 ampersand_chars[base::size(kEscapeToChars)];
   base::string16 text = input.as_string();
   for (base::string16::iterator iter = text.begin();
        iter != text.end(); ++iter) {
     if (*iter == '&') {
       // Potential ampersand encode char.
       size_t index = iter - text.begin();
-      for (size_t i = 0; i < arraysize(kEscapeToChars); i++) {
+      for (size_t i = 0; i < base::size(kEscapeToChars); i++) {
         if (ampersand_chars[i].empty()) {
           ampersand_chars[i] =
               base::ASCIIToUTF16(kEscapeToChars[i].ampersand_code);
diff --git a/net/base/escape_unittest.cc b/net/base/escape_unittest.cc
index 6a33896..f901c27 100644
--- a/net/base/escape_unittest.cc
+++ b/net/base/escape_unittest.cc
@@ -56,9 +56,9 @@
     {"foo bar", "foo+bar"},
     {"foo++", "foo%2B%2B"}
   };
-  for (size_t i = 0; i < arraysize(escape_cases); ++i) {
-    EscapeCase value = escape_cases[i];
-    EXPECT_EQ(value.output, EscapeQueryParamValue(value.input, true));
+  for (const auto& escape_case : escape_cases) {
+    EXPECT_EQ(escape_case.output,
+              EscapeQueryParamValue(escape_case.input, true));
   }
 
   const EscapeCase escape_cases_no_plus[] = {
@@ -66,9 +66,9 @@
     {"foo bar", "foo%20bar"},
     {"foo++", "foo%2B%2B"}
   };
-  for (size_t i = 0; i < arraysize(escape_cases_no_plus); ++i) {
-    EscapeCase value = escape_cases_no_plus[i];
-    EXPECT_EQ(value.output, EscapeQueryParamValue(value.input, false));
+  for (const auto& escape_case : escape_cases_no_plus) {
+    EXPECT_EQ(escape_case.output,
+              EscapeQueryParamValue(escape_case.input, false));
   }
 
   // Test all the values in we're supposed to be escaping.
@@ -312,19 +312,19 @@
      L"%ED%ED"},  // Invalid UTF-8 -> kept unescaped.
   };
 
-  for (size_t i = 0; i < arraysize(unescape_cases); i++) {
-    std::string unescaped = UnescapeURLComponent(unescape_cases[i].input,
-                                                 UnescapeRule::NORMAL);
-    EXPECT_EQ(std::string(unescape_cases[i].url_unescaped), unescaped);
+  for (const auto& unescape_case : unescape_cases) {
+    std::string unescaped =
+        UnescapeURLComponent(unescape_case.input, UnescapeRule::NORMAL);
+    EXPECT_EQ(std::string(unescape_case.url_unescaped), unescaped);
 
-    unescaped = UnescapeURLComponent(unescape_cases[i].input,
+    unescaped = UnescapeURLComponent(unescape_case.input,
                                      UnescapeRule::REPLACE_PLUS_WITH_SPACE);
-    EXPECT_EQ(std::string(unescape_cases[i].query_unescaped), unescaped);
+    EXPECT_EQ(std::string(unescape_case.query_unescaped), unescaped);
 
     // TODO: Need to test unescape_spaces and unescape_percent.
     base::string16 decoded = UnescapeAndDecodeUTF8URLComponent(
-        unescape_cases[i].input, UnescapeRule::NORMAL);
-    EXPECT_EQ(base::WideToUTF16(unescape_cases[i].decoded), decoded);
+        unescape_case.input, UnescapeRule::NORMAL);
+    EXPECT_EQ(base::WideToUTF16(unescape_case.decoded), decoded);
   }
 }
 
@@ -371,15 +371,15 @@
       {"%ED%B0%80+%E5%A5%BD", 6, 6},  // not convertable to UTF-8
   };
 
-  for (size_t i = 0; i < arraysize(adjust_cases); i++) {
-    size_t offset = adjust_cases[i].input_offset;
+  for (const auto& adjust_case : adjust_cases) {
+    size_t offset = adjust_case.input_offset;
     base::OffsetAdjuster::Adjustments adjustments;
     UnescapeAndDecodeUTF8URLComponentWithAdjustments(
-        adjust_cases[i].input, UnescapeRule::NORMAL, &adjustments);
+        adjust_case.input, UnescapeRule::NORMAL, &adjustments);
     base::OffsetAdjuster::AdjustOffset(adjustments, &offset);
-    EXPECT_EQ(adjust_cases[i].output_offset, offset)
-        << "input=" << adjust_cases[i].input
-        << " offset=" << adjust_cases[i].input_offset;
+    EXPECT_EQ(adjust_case.output_offset, offset)
+        << "input=" << adjust_case.input
+        << " offset=" << adjust_case.input_offset;
   }
 }
 
@@ -434,9 +434,9 @@
     { "<hello>", "&lt;hello&gt;" },
     { "don\'t mess with me", "don&#39;t mess with me" },
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    std::string result = EscapeForHTML(std::string(tests[i].input));
-    EXPECT_EQ(std::string(tests[i].expected_output), result);
+  for (const auto& test : tests) {
+    std::string result = EscapeForHTML(std::string(test.input));
+    EXPECT_EQ(std::string(test.expected_output), result);
   }
 }
 
@@ -454,9 +454,9 @@
     { "&gt;", ">" },
     { "&amp; &", "& &" },
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    base::string16 result = UnescapeForHTML(base::ASCIIToUTF16(tests[i].input));
-    EXPECT_EQ(base::ASCIIToUTF16(tests[i].expected_output), result);
+  for (const auto& test : tests) {
+    base::string16 result = UnescapeForHTML(base::ASCIIToUTF16(test.input));
+    EXPECT_EQ(base::ASCIIToUTF16(test.expected_output), result);
   }
 }
 
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index e393965..98b1ac9 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop_current.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
@@ -41,8 +42,8 @@
 
 namespace {
 
-const char kTestData[] = "0123456789";
-const int kTestDataSize = arraysize(kTestData) - 1;
+constexpr char kTestData[] = "0123456789";
+constexpr int kTestDataSize = base::size(kTestData) - 1;
 
 // Creates an IOBufferWithSize that contains the kTestDataSize.
 IOBufferWithSize* CreateTestDataBuffer() {
diff --git a/net/base/filename_util.cc b/net/base/filename_util.cc
index 16341dc..2e3ae10d 100644
--- a/net/base/filename_util.cc
+++ b/net/base/filename_util.cc
@@ -170,12 +170,12 @@
   std::string filename_lower = base::ToLowerASCII(filename);
 #endif
 
-  for (size_t i = 0; i < arraysize(known_devices); ++i) {
+  for (const char* const device : known_devices) {
     // Exact match.
-    if (filename_lower == known_devices[i])
+    if (filename_lower == device)
       return true;
     // Starts with "DEVICE.".
-    if (base::StartsWith(filename_lower, std::string(known_devices[i]) + ".",
+    if (base::StartsWith(filename_lower, std::string(device) + ".",
                          base::CompareCase::SENSITIVE)) {
       return true;
     }
@@ -188,8 +188,8 @@
       "thumbs.db",
   };
 
-  for (size_t i = 0; i < arraysize(magic_names); ++i) {
-    if (filename_lower == magic_names[i])
+  for (const char* const magic_name : magic_names) {
+    if (filename_lower == magic_name)
       return true;
   }
 
diff --git a/net/base/filename_util_unittest.cc b/net/base/filename_util_unittest.cc
index f7a4c152..ec25e4c 100644
--- a/net/base/filename_util_unittest.cc
+++ b/net/base/filename_util_unittest.cc
@@ -128,49 +128,41 @@
 }  // namespace
 
 TEST(FilenameUtilTest, IsSafePortablePathComponent) {
-  for (size_t i = 0; i < arraysize(kSafePortableBasenames); ++i) {
-    EXPECT_TRUE(
-        IsSafePortablePathComponent(base::FilePath(kSafePortableBasenames[i])))
-        << kSafePortableBasenames[i];
+  for (auto* basename : kSafePortableBasenames) {
+    EXPECT_TRUE(IsSafePortablePathComponent(base::FilePath(basename)))
+        << basename;
   }
-  for (size_t i = 0; i < arraysize(kUnsafePortableBasenames); ++i) {
-    EXPECT_FALSE(IsSafePortablePathComponent(
-        base::FilePath(kUnsafePortableBasenames[i])))
-        << kUnsafePortableBasenames[i];
+  for (auto* basename : kUnsafePortableBasenames) {
+    EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(basename)))
+        << basename;
   }
-  for (size_t i = 0; i < arraysize(kSafePortableRelativePaths); ++i) {
-    EXPECT_FALSE(IsSafePortablePathComponent(
-        base::FilePath(kSafePortableRelativePaths[i])))
-        << kSafePortableRelativePaths[i];
+  for (auto* path : kSafePortableRelativePaths) {
+    EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(path))) << path;
   }
 }
 
 TEST(FilenameUtilTest, IsSafePortableRelativePath) {
   base::FilePath safe_dirname(FILE_PATH_LITERAL("a"));
-  for (size_t i = 0; i < arraysize(kSafePortableBasenames); ++i) {
+  for (auto* basename : kSafePortableBasenames) {
+    EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(basename)))
+        << basename;
+    EXPECT_TRUE(IsSafePortableRelativePath(
+        safe_dirname.Append(base::FilePath(basename))))
+        << basename;
+  }
+  for (auto* path : kSafePortableRelativePaths) {
+    EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(path))) << path;
     EXPECT_TRUE(
-        IsSafePortableRelativePath(base::FilePath(kSafePortableBasenames[i])))
-        << kSafePortableBasenames[i];
-    EXPECT_TRUE(IsSafePortableRelativePath(
-        safe_dirname.Append(base::FilePath(kSafePortableBasenames[i]))))
-        << kSafePortableBasenames[i];
+        IsSafePortableRelativePath(safe_dirname.Append(base::FilePath(path))))
+        << path;
   }
-  for (size_t i = 0; i < arraysize(kSafePortableRelativePaths); ++i) {
-    EXPECT_TRUE(IsSafePortableRelativePath(
-        base::FilePath(kSafePortableRelativePaths[i])))
-        << kSafePortableRelativePaths[i];
-    EXPECT_TRUE(IsSafePortableRelativePath(
-        safe_dirname.Append(base::FilePath(kSafePortableRelativePaths[i]))))
-        << kSafePortableRelativePaths[i];
-  }
-  for (size_t i = 0; i < arraysize(kUnsafePortableBasenames); ++i) {
-    EXPECT_FALSE(
-        IsSafePortableRelativePath(base::FilePath(kUnsafePortableBasenames[i])))
-        << kUnsafePortableBasenames[i];
-    if (!base::FilePath::StringType(kUnsafePortableBasenames[i]).empty()) {
+  for (auto* basename : kUnsafePortableBasenames) {
+    EXPECT_FALSE(IsSafePortableRelativePath(base::FilePath(basename)))
+        << basename;
+    if (!base::FilePath::StringType(basename).empty()) {
       EXPECT_FALSE(IsSafePortableRelativePath(
-          safe_dirname.Append(base::FilePath(kUnsafePortableBasenames[i]))))
-          << kUnsafePortableBasenames[i];
+          safe_dirname.Append(base::FilePath(basename))))
+          << basename;
     }
   }
 }
@@ -215,15 +207,14 @@
 
   // First, we'll test that we can round-trip all of the above cases of URLs
   base::FilePath output;
-  for (size_t i = 0; i < arraysize(round_trip_cases); i++) {
+  for (const auto& test_case : round_trip_cases) {
     // convert to the file URL
-    GURL file_url(
-        FilePathToFileURL(WStringAsFilePath(round_trip_cases[i].file)));
-    EXPECT_EQ(round_trip_cases[i].url, file_url.spec());
+    GURL file_url(FilePathToFileURL(WStringAsFilePath(test_case.file)));
+    EXPECT_EQ(test_case.url, file_url.spec());
 
     // Back to the filename.
     EXPECT_TRUE(FileURLToFilePath(file_url, &output));
-    EXPECT_EQ(round_trip_cases[i].file, FilePathAsWString(output));
+    EXPECT_EQ(test_case.file, FilePathAsWString(output));
   }
 
   // Test that various file: URLs get decoded into the correct file type
@@ -266,9 +257,9 @@
 //  {L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
 #endif
   };
-  for (size_t i = 0; i < arraysize(url_cases); i++) {
-    FileURLToFilePath(GURL(url_cases[i].url), &output);
-    EXPECT_EQ(url_cases[i].file, FilePathAsWString(output));
+  for (const auto& test_case : url_cases) {
+    FileURLToFilePath(GURL(test_case.url), &output);
+    EXPECT_EQ(test_case.file, FilePathAsWString(output));
   }
 
 // Unfortunately, UTF8ToWide discards invalid UTF8 input.
@@ -698,30 +689,28 @@
 #endif
   };
 
-  for (size_t i = 0; i < arraysize(selection_tests); ++i)
-    RunGenerateFileNameTestCase(&selection_tests[i]);
+  for (const auto& selection_test : selection_tests)
+    RunGenerateFileNameTestCase(&selection_test);
 
-  for (size_t i = 0; i < arraysize(generation_tests); ++i)
-    RunGenerateFileNameTestCase(&generation_tests[i]);
+  for (const auto& generation_test : generation_tests)
+    RunGenerateFileNameTestCase(&generation_test);
 
-  for (size_t i = 0; i < arraysize(generation_tests); ++i) {
-    GenerateFilenameCase test_case = generation_tests[i];
+  for (const auto& generation_test : generation_tests) {
+    GenerateFilenameCase test_case = generation_test;
     test_case.referrer_charset = "GBK";
     RunGenerateFileNameTestCase(&test_case);
   }
 }
 
 TEST(FilenameUtilTest, IsReservedNameOnWindows) {
-  for (size_t i = 0; i < arraysize(kSafePortableBasenames); ++i) {
-    EXPECT_FALSE(IsReservedNameOnWindows(
-        base::FilePath(kSafePortableBasenames[i]).value()))
-        << kSafePortableBasenames[i];
+  for (auto* basename : kSafePortableBasenames) {
+    EXPECT_FALSE(IsReservedNameOnWindows(base::FilePath(basename).value()))
+        << basename;
   }
 
-  for (size_t i = 0; i < arraysize(kUnsafePortableBasenamesForWin); ++i) {
-    EXPECT_TRUE(IsReservedNameOnWindows(
-        base::FilePath(kUnsafePortableBasenamesForWin[i]).value()))
-        << kUnsafePortableBasenamesForWin[i];
+  for (auto* basename : kUnsafePortableBasenamesForWin) {
+    EXPECT_TRUE(IsReservedNameOnWindows(base::FilePath(basename).value()))
+        << basename;
   }
 }
 
diff --git a/net/base/host_port_pair_unittest.cc b/net/base/host_port_pair_unittest.cc
index 72704a0..4300c2b 100644
--- a/net/base/host_port_pair_unittest.cc
+++ b/net/base/host_port_pair_unittest.cc
@@ -42,8 +42,8 @@
       "www.google.com:+1", "127.0.0.1:65536", "[2001:db8::42]:65536",
   };
 
-  for (size_t index = 0; index < arraysize(kBadStrings); ++index) {
-    HostPortPair foo = HostPortPair::FromString(kBadStrings[index]);
+  for (const auto* const test : kBadStrings) {
+    HostPortPair foo = HostPortPair::FromString(test);
     EXPECT_TRUE(foo.host().empty());
     EXPECT_EQ(0, foo.port());
   }
@@ -57,9 +57,9 @@
 }
 
 TEST(HostPortPairTest, ToString) {
-  for (size_t index = 0; index < arraysize(tests); ++index) {
-    HostPortPair foo(tests[index].host, tests[index].port);
-    EXPECT_EQ(tests[index].to_string, foo.ToString());
+  for (const auto& test : tests) {
+    HostPortPair foo(test.host, test.port);
+    EXPECT_EQ(test.to_string, foo.ToString());
   }
 
   // Test empty hostname.
@@ -67,9 +67,9 @@
 }
 
 TEST(HostPortPairTest, HostForURL) {
-  for (size_t index = 0; index < arraysize(tests); ++index) {
-    HostPortPair foo(tests[index].host, tests[index].port);
-    EXPECT_EQ(tests[index].host_for_url, foo.HostForURL());
+  for (const auto& test : tests) {
+    HostPortPair foo(test.host, test.port);
+    EXPECT_EQ(test.host_for_url, foo.HostForURL());
   }
 
   // Test hostname with null character.
diff --git a/net/base/ip_address.cc b/net/base/ip_address.cc
index b90b3b4..2daddc0 100644
--- a/net/base/ip_address.cc
+++ b/net/base/ip_address.cc
@@ -8,6 +8,7 @@
 #include <climits>
 
 #include "base/containers/stack_container.h"
+#include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
@@ -20,7 +21,8 @@
 
 // The prefix for IPv6 mapped IPv4 addresses.
 // https://tools.ietf.org/html/rfc4291#section-2.5.5.2
-const uint8_t kIPv4MappedPrefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF};
+constexpr uint8_t kIPv4MappedPrefix[] = {0, 0, 0, 0, 0,    0,
+                                         0, 0, 0, 0, 0xFF, 0xFF};
 
 // Note that this function assumes:
 // * |ip_address| is at least |prefix_length_in_bits| (bits) long;
@@ -359,7 +361,7 @@
 
   base::StackVector<uint8_t, 16> bytes;
   bytes->insert(bytes->end(),
-                address.bytes().begin() + arraysize(kIPv4MappedPrefix),
+                address.bytes().begin() + base::size(kIPv4MappedPrefix),
                 address.bytes().end());
   return IPAddress(bytes->data(), bytes->size());
 }
diff --git a/net/base/ip_address_unittest.cc b/net/base/ip_address_unittest.cc
index 177ab55..652416a 100644
--- a/net/base/ip_address_unittest.cc
+++ b/net/base/ip_address_unittest.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/format_macros.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,29 +34,29 @@
 
 TEST(IPAddressBytesTest, ConstructIPv4) {
   uint8_t data[] = {192, 168, 1, 1};
-  IPAddressBytes bytes(data, arraysize(data));
-  ASSERT_EQ(arraysize(data), bytes.size());
+  IPAddressBytes bytes(data, base::size(data));
+  ASSERT_EQ(base::size(data), bytes.size());
   size_t i = 0;
   for (uint8_t byte : bytes)
     EXPECT_EQ(data[i++], byte);
-  ASSERT_EQ(arraysize(data), i);
+  ASSERT_EQ(base::size(data), i);
 }
 
 TEST(IPAddressBytesTest, ConstructIPv6) {
   uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-  IPAddressBytes bytes(data, arraysize(data));
-  ASSERT_EQ(arraysize(data), bytes.size());
+  IPAddressBytes bytes(data, base::size(data));
+  ASSERT_EQ(base::size(data), bytes.size());
   size_t i = 0;
   for (uint8_t byte : bytes)
     EXPECT_EQ(data[i++], byte);
-  ASSERT_EQ(arraysize(data), i);
+  ASSERT_EQ(base::size(data), i);
 }
 
 TEST(IPAddressBytesTest, Assign) {
   uint8_t data[] = {192, 168, 1, 1};
   IPAddressBytes copy;
-  copy.Assign(data, arraysize(data));
-  EXPECT_EQ(IPAddressBytes(data, arraysize(data)), copy);
+  copy.Assign(data, base::size(data));
+  EXPECT_EQ(IPAddressBytes(data, base::size(data)), copy);
 }
 
 TEST(IPAddressTest, ConstructIPv4) {
@@ -521,20 +522,19 @@
       {"10.11.33.44", 16, "::ffff:0a0b:89", true},
       {"10.11.33.44", 16, "::ffff:10.12.33.44", false},
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s, %s", i,
-                                    tests[i].cidr_literal,
-                                    tests[i].ip_literal));
+  for (const auto& test : tests) {
+    SCOPED_TRACE(
+        base::StringPrintf("%s, %s", test.cidr_literal, test.ip_literal));
 
     IPAddress ip_address;
-    EXPECT_TRUE(ip_address.AssignFromIPLiteral(tests[i].ip_literal));
+    EXPECT_TRUE(ip_address.AssignFromIPLiteral(test.ip_literal));
 
     IPAddress ip_prefix;
-    EXPECT_TRUE(ip_prefix.AssignFromIPLiteral(tests[i].cidr_literal));
+    EXPECT_TRUE(ip_prefix.AssignFromIPLiteral(test.cidr_literal));
 
-    EXPECT_EQ(tests[i].expected_to_match,
+    EXPECT_EQ(test.expected_to_match,
               IPAddressMatchesPrefix(ip_address, ip_prefix,
-                                     tests[i].prefix_length_in_bits));
+                                     test.prefix_length_in_bits));
   }
 }
 
diff --git a/net/base/ip_endpoint_unittest.cc b/net/base/ip_endpoint_unittest.cc
index b3aa5b1..545f2e6 100644
--- a/net/base/ip_endpoint_unittest.cc
+++ b/net/base/ip_endpoint_unittest.cc
@@ -61,15 +61,13 @@
   { "::1", "[::1]", true },
   { "2001:db8:0::42", "[2001:db8::42]", true },
 };
-uint16_t test_count = static_cast<uint16_t>(arraysize(tests));
 
 class IPEndPointTest : public PlatformTest {
  public:
   void SetUp() override {
     // This is where we populate the TestData.
-    for (int index = 0; index < test_count; ++index) {
-      EXPECT_TRUE(
-          tests[index].ip_address.AssignFromIPLiteral(tests[index].host));
+    for (auto& test : tests) {
+      EXPECT_TRUE(test.ip_address.AssignFromIPLiteral(test.host));
     }
   }
 };
@@ -78,16 +76,17 @@
   IPEndPoint endpoint;
   EXPECT_EQ(0, endpoint.port());
 
-  for (uint16_t index = 0; index < test_count; ++index) {
-    IPEndPoint endpoint(tests[index].ip_address, 80);
+  for (const auto& test : tests) {
+    IPEndPoint endpoint(test.ip_address, 80);
     EXPECT_EQ(80, endpoint.port());
-    EXPECT_EQ(tests[index].ip_address, endpoint.address());
+    EXPECT_EQ(test.ip_address, endpoint.address());
   }
 }
 
 TEST_F(IPEndPointTest, Assignment) {
-  for (uint16_t index = 0; index < test_count; ++index) {
-    IPEndPoint src(tests[index].ip_address, index);
+  uint16_t port = 0;
+  for (const auto& test : tests) {
+    IPEndPoint src(test.ip_address, ++port);
     IPEndPoint dest = src;
 
     EXPECT_EQ(src.port(), dest.port());
@@ -96,8 +95,9 @@
 }
 
 TEST_F(IPEndPointTest, Copy) {
-  for (uint16_t index = 0; index < test_count; ++index) {
-    IPEndPoint src(tests[index].ip_address, index);
+  uint16_t port = 0;
+  for (const auto& test : tests) {
+    IPEndPoint src(test.ip_address, ++port);
     IPEndPoint dest(src);
 
     EXPECT_EQ(src.port(), dest.port());
@@ -106,16 +106,17 @@
 }
 
 TEST_F(IPEndPointTest, ToFromSockAddr) {
-  for (uint16_t index = 0; index < test_count; ++index) {
-    IPEndPoint ip_endpoint(tests[index].ip_address, index);
+  uint16_t port = 0;
+  for (const auto& test : tests) {
+    IPEndPoint ip_endpoint(test.ip_address, ++port);
 
     // Convert to a sockaddr.
     SockaddrStorage storage;
     EXPECT_TRUE(ip_endpoint.ToSockAddr(storage.addr, &storage.addr_len));
 
     // Basic verification.
-    socklen_t expected_size = tests[index].ipv6 ?
-        sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
+    socklen_t expected_size =
+        test.ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
     EXPECT_EQ(expected_size, storage.addr_len);
     EXPECT_EQ(ip_endpoint.port(), GetPortFromSockaddr(storage.addr,
                                                       storage.addr_len));
@@ -129,11 +130,12 @@
 }
 
 TEST_F(IPEndPointTest, ToSockAddrBufTooSmall) {
-  for (uint16_t index = 0; index < test_count; ++index) {
-    IPEndPoint ip_endpoint(tests[index].ip_address, index);
+  uint16_t port = 0;
+  for (const auto& test : tests) {
+    IPEndPoint ip_endpoint(test.ip_address, port);
 
     SockaddrStorage storage;
-    storage.addr_len = index;  // size is too small!
+    storage.addr_len = 3;  // size is too small!
     EXPECT_FALSE(ip_endpoint.ToSockAddr(storage.addr, &storage.addr_len));
   }
 }
@@ -148,8 +150,9 @@
 }
 
 TEST_F(IPEndPointTest, Equality) {
-  for (uint16_t index = 0; index < test_count; ++index) {
-    IPEndPoint src(tests[index].ip_address, index);
+  uint16_t port = 0;
+  for (const auto& test : tests) {
+    IPEndPoint src(test.ip_address, ++port);
     IPEndPoint dest(src);
     EXPECT_TRUE(src == dest);
   }
@@ -191,12 +194,12 @@
   IPEndPoint endpoint;
   EXPECT_EQ(0, endpoint.port());
 
-  for (uint16_t index = 0; index < test_count; ++index) {
-    uint16_t port = 100 + index;
-    IPEndPoint endpoint(tests[index].ip_address, port);
+  uint16_t port = 100;
+  for (const auto& test : tests) {
+    ++port;
+    IPEndPoint endpoint(test.ip_address, port);
     const std::string result = endpoint.ToString();
-    EXPECT_EQ(tests[index].host_normalized + ":" + base::UintToString(port),
-              result);
+    EXPECT_EQ(test.host_normalized + ":" + base::UintToString(port), result);
   }
 
   // ToString() shouldn't crash on invalid addresses.
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc
index 39d25ab6..3f60f22 100644
--- a/net/base/mime_sniffer.cc
+++ b/net/base/mime_sniffer.cc
@@ -88,7 +88,9 @@
 
 #include "net/base/mime_sniffer.h"
 
+#include "base/containers/span.h"
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "url/gurl.h"
 
@@ -348,11 +350,12 @@
   return false;
 }
 
-static bool CheckForMagicNumbers(const char* content, size_t size,
-                                 const MagicNumber* magic, size_t magic_len,
+static bool CheckForMagicNumbers(const char* content,
+                                 size_t size,
+                                 base::span<const MagicNumber> magic_numbers,
                                  std::string* result) {
-  for (size_t i = 0; i < magic_len; ++i) {
-    if (MatchMagicNumber(content, size, magic[i], result))
+  for (const MagicNumber& magic : magic_numbers) {
+    if (MatchMagicNumber(content, size, magic, result))
       return true;
   }
   return false;
@@ -390,8 +393,7 @@
       break;
   }
   // |pos| now points to first non-whitespace character (or at end).
-  return CheckForMagicNumbers(pos, end - pos, kSniffableTags,
-                              arraysize(kSniffableTags), result);
+  return CheckForMagicNumbers(pos, end - pos, kSniffableTags, result);
 }
 
 // Returns true and sets result if the content matches any of kMagicNumbers.
@@ -403,8 +405,7 @@
   *have_enough_content &= TruncateSize(kBytesRequiredForMagic, &size);
 
   // Check our big table of Magic Numbers
-  return CheckForMagicNumbers(content, size, kMagicNumbers,
-                              arraysize(kMagicNumbers), result);
+  return CheckForMagicNumbers(content, size, kMagicNumbers, result);
 }
 
 // Returns true and sets result if the content matches any of
@@ -420,22 +421,21 @@
   // Check our table of magic numbers for Office file types.
   std::string office_version;
   if (!CheckForMagicNumbers(content, size, kOfficeMagicNumbers,
-                            arraysize(kOfficeMagicNumbers), &office_version))
+                            &office_version))
     return false;
 
   OfficeDocType type = DOC_TYPE_NONE;
   base::StringPiece url_path = url.path_piece();
-  for (size_t i = 0; i < arraysize(kOfficeExtensionTypes); ++i) {
-    if (url_path.length() < kOfficeExtensionTypes[i].extension_len)
+  for (const auto& office_extension : kOfficeExtensionTypes) {
+    if (url_path.length() < office_extension.extension_len)
       continue;
 
-    base::StringPiece extension = url_path.substr(
-        url_path.length() - kOfficeExtensionTypes[i].extension_len);
+    base::StringPiece extension =
+        url_path.substr(url_path.length() - office_extension.extension_len);
     if (base::EqualsCaseInsensitiveASCII(
-            extension,
-            base::StringPiece(kOfficeExtensionTypes[i].extension,
-                              kOfficeExtensionTypes[i].extension_len))) {
-      type = kOfficeExtensionTypes[i].doc_type;
+            extension, base::StringPiece(office_extension.extension,
+                                         office_extension.extension_len))) {
+      type = office_extension.doc_type;
       break;
     }
   }
@@ -522,7 +522,7 @@
   // match one, the MIME type was invalid.  Set it instead to a safe value.
   std::string office_version;
   if (!CheckForMagicNumbers(content, size, kOfficeMagicNumbers,
-                            arraysize(kOfficeMagicNumbers), &office_version)) {
+                            &office_version)) {
     *result = "application/octet-stream";
   }
 
@@ -564,29 +564,25 @@
     if (!pos)
       return false;
 
-    static const char kXmlPrefix[] = "<?xml";
-    static const size_t kXmlPrefixLength = arraysize(kXmlPrefix) - 1;
-    static const char kDocTypePrefix[] = "<!DOCTYPE";
-    static const size_t kDocTypePrefixLength = arraysize(kDocTypePrefix) - 1;
+    static constexpr base::StringPiece kXmlPrefix("<?xml");
+    static constexpr base::StringPiece kDocTypePrefix("<!DOCTYPE");
 
-    if ((pos + kXmlPrefixLength <= end) &&
-        base::EqualsCaseInsensitiveASCII(
-            base::StringPiece(pos, kXmlPrefixLength),
-            base::StringPiece(kXmlPrefix, kXmlPrefixLength))) {
+    base::StringPiece current(pos, end - pos);
+    if (base::EqualsCaseInsensitiveASCII(current.substr(0, kXmlPrefix.size()),
+                                         kXmlPrefix)) {
       // Skip XML declarations.
       ++pos;
       continue;
-    } else if ((pos + kDocTypePrefixLength <= end) &&
-               base::EqualsCaseInsensitiveASCII(
-                   base::StringPiece(pos, kDocTypePrefixLength),
-                   base::StringPiece(kDocTypePrefix, kDocTypePrefixLength))) {
+    }
+
+    if (base::EqualsCaseInsensitiveASCII(
+            current.substr(0, kDocTypePrefix.size()), kDocTypePrefix)) {
       // Skip DOCTYPE declarations.
       ++pos;
       continue;
     }
 
-    if (CheckForMagicNumbers(pos, end - pos, kMagicXML, arraysize(kMagicXML),
-                             result))
+    if (CheckForMagicNumbers(pos, end - pos, kMagicXML, result))
       return true;
 
     // TODO(evanm): handle RSS 1.0, which is an RDF format and more difficult
@@ -628,8 +624,7 @@
 
   // First, we look for a BOM.
   std::string unused;
-  if (CheckForMagicNumbers(content, size, kByteOrderMark,
-                           arraysize(kByteOrderMark), &unused)) {
+  if (CheckForMagicNumbers(content, size, kByteOrderMark, &unused)) {
     // If there is BOM, we think the buffer is not binary.
     result->assign("text/plain");
     return false;
@@ -662,8 +657,8 @@
     // Firefox rejects a mime type if it is exactly */*
     "*/*",
   };
-  for (size_t i = 0; i < arraysize(kUnknownMimeTypes); ++i) {
-    if (mime_type == kUnknownMimeTypes[i])
+  for (const char* const unknown_mime_type : kUnknownMimeTypes) {
+    if (mime_type == unknown_mime_type)
       return true;
   }
   if (mime_type.find('/') == std::string::npos) {
@@ -695,8 +690,7 @@
     return false;
 
   *have_enough_content &= TruncateSize(kBytesRequiredForMagic, &size);
-  return CheckForMagicNumbers(content, size, kCRXMagicNumbers,
-                              arraysize(kCRXMagicNumbers), result);
+  return CheckForMagicNumbers(content, size, kCRXMagicNumbers, result);
 }
 
 bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) {
@@ -738,8 +732,8 @@
     "application/vnd.ms-word.document.12",
     "application/vnd.msword",
   };
-  for (size_t i = 0; i < arraysize(kSniffableTypes); ++i) {
-    if (mime_type == kSniffableTypes[i])
+  for (const char* const sniffable_type : kSniffableTypes) {
+    if (mime_type == sniffable_type)
       return true;
   }
   if (IsUnknownMimeType(mime_type)) {
@@ -847,12 +841,10 @@
                                 size_t size,
                                 std::string* result) {
   // First check the extra table.
-  if (CheckForMagicNumbers(content, size, kExtraMagicNumbers,
-                           arraysize(kExtraMagicNumbers), result))
+  if (CheckForMagicNumbers(content, size, kExtraMagicNumbers, result))
     return true;
   // Finally check the original table.
-  return CheckForMagicNumbers(content, size, kMagicNumbers,
-                              arraysize(kMagicNumbers), result);
+  return CheckForMagicNumbers(content, size, kMagicNumbers, result);
 }
 
 bool LooksLikeBinary(const char* content, size_t size) {
diff --git a/net/base/mime_sniffer_unittest.cc b/net/base/mime_sniffer_unittest.cc
index 1d3a869..5c200eb6 100644
--- a/net/base/mime_sniffer_unittest.cc
+++ b/net/base/mime_sniffer_unittest.cc
@@ -14,27 +14,14 @@
 using ::testing::Values;
 using ::net::SniffMimeType;  // It is shadowed by SniffMimeType(), below.
 
-struct SnifferTest {
-  const char* content;
-  size_t content_len;
-  std::string url;
-  std::string type_hint;
-  const char* mime_type;
-};
-
-static void TestArray(SnifferTest* tests, size_t count) {
-  std::string mime_type;
-
-  for (size_t i = 0; i < count; ++i) {
-    SniffMimeType(tests[i].content, tests[i].content_len, GURL(tests[i].url),
-                  tests[i].type_hint, ForceSniffFileUrlsForHtml::kDisabled,
-                  &mime_type);
-    EXPECT_EQ(tests[i].mime_type, mime_type);
-  }
+// Turn |str|, a constant string with one or more embedded NULs, along with
+// a NUL terminator, into an std::string() containing just that data.
+// Turn |str|, a string with one or more embedded NULs, into an std::string()
+template <size_t N>
+std::string MakeConstantString(const char (&str)[N]) {
+  return std::string(str, N - 1);
 }
 
-// TODO(evanm): convert other tests to use SniffMimeType instead of TestArray,
-// so the error messages produced by test failures are more useful.
 static std::string SniffMimeType(const std::string& content,
                                  const std::string& url,
                                  const std::string& mime_type_hint) {
@@ -66,184 +53,169 @@
 }
 
 TEST(MimeSnifferTest, BasicSniffingTest) {
-  SnifferTest tests[] = {
-    { "<!DOCTYPE html PUBLIC", sizeof("<!DOCTYPE html PUBLIC")-1,
-      "http://www.example.com/",
-      "", "text/html" },
-    { "<HtMl><Body></body></htMl>", sizeof("<HtMl><Body></body></htMl>")-1,
-      "http://www.example.com/foo.gif",
-      "application/octet-stream", "application/octet-stream" },
-    { "GIF89a\x1F\x83\x94", sizeof("GIF89a\xAF\x83\x94")-1,
-      "http://www.example.com/foo",
-      "text/plain", "image/gif" },
-    { "Gif87a\x1F\x83\x94", sizeof("Gif87a\xAF\x83\x94")-1,
-      "http://www.example.com/foo?param=tt.gif",
-      "", "application/octet-stream" },
-    { "%!PS-Adobe-3.0", sizeof("%!PS-Adobe-3.0")-1,
-      "http://www.example.com/foo",
-      "text/plain", "text/plain" },
-    { "\x89" "PNG\x0D\x0A\x1A\x0A", sizeof("\x89" "PNG\x0D\x0A\x1A\x0A")-1,
-      "http://www.example.com/foo",
-      "application/octet-stream", "application/octet-stream" },
-    { "\xFF\xD8\xFF\x23\x49\xAF", sizeof("\xFF\xD8\xFF\x23\x49\xAF")-1,
-      "http://www.example.com/foo",
-      "", "image/jpeg" },
-  };
-
-  TestArray(tests, arraysize(tests));
+  EXPECT_EQ("text/html",
+            SniffMimeType(MakeConstantString("<!DOCTYPE html PUBLIC"),
+                          "http://www.example.com/", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("<HtMl><Body></body></htMl>"),
+                          "http://www.example.com/foo.gif",
+                          "application/octet-stream"));
+  EXPECT_EQ("image/gif",
+            SniffMimeType(MakeConstantString("GIF89a\x1F\x83\x94"),
+                          "http://www.example.com/foo", "text/plain"));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Gif87a\x1F\x83\x94"),
+                          "http://www.example.com/foo?param=tt.gif", ""));
+  EXPECT_EQ("text/plain",
+            SniffMimeType(MakeConstantString("%!PS-Adobe-3.0"),
+                          "http://www.example.com/foo", "text/plain"));
+  EXPECT_EQ(
+      "application/octet-stream",
+      SniffMimeType(MakeConstantString("\x89"
+                                       "PNG\x0D\x0A\x1A\x0A"),
+                    "http://www.example.com/foo", "application/octet-stream"));
+  EXPECT_EQ("image/jpeg",
+            SniffMimeType(MakeConstantString("\xFF\xD8\xFF\x23\x49\xAF"),
+                          "http://www.example.com/foo", ""));
 }
 
 TEST(MimeSnifferTest, ChromeExtensionsTest) {
-  SnifferTest tests[] = {
-      // schemes
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.crx", "", "application/x-chrome-extension"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "https://www.example.com/foo.crx", "", "application/x-chrome-extension"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "ftp://www.example.com/foo.crx", "", "application/x-chrome-extension"},
+  // schemes
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.crx", ""));
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "https://www.example.com/foo.crx", ""));
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "ftp://www.example.com/foo.crx", ""));
 
-      // some other mimetypes that should get converted
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.crx", "text/plain",
-       "application/x-chrome-extension"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.crx", "application/octet-stream",
-       "application/x-chrome-extension"},
+  // some other mimetypes that should get converted
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.crx", "text/plain"));
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.crx",
+                          "application/octet-stream"));
 
-      // success edge cases
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.crx?query=string", "",
-       "application/x-chrome-extension"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo..crx", "", "application/x-chrome-extension"},
-      {"Cr24\x03\x00\x00\x00", sizeof("Cr24\x03\x00\x00\x00") - 1,
-       "http://www.example.com/foo..crx", "", "application/x-chrome-extension"},
+  // success edge cases
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.crx?query=string", ""));
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo..crx", ""));
+  EXPECT_EQ("application/x-chrome-extension",
+            SniffMimeType(MakeConstantString("Cr24\x03\x00\x00\x00"),
+                          "http://www.example.com/foo..crx", ""));
 
-      // wrong file extension
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.bin", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.bin?monkey", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "invalid-url", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foocrx", "", "application/octet-stream"},
-      {"Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.crx.blech", "", "application/octet-stream"},
+  // wrong file extension
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.bin", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.bin?monkey", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "invalid-url", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foocrx", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.crx.blech", ""));
 
-      // wrong magic
-      {"Cr24\x02\x00\x00\x01", sizeof("Cr24\x02\x00\x00\x01") - 1,
-       "http://www.example.com/foo.crx?monkey", "", "application/octet-stream"},
-      {"PADDING_Cr24\x02\x00\x00\x00",
-       sizeof("PADDING_Cr24\x02\x00\x00\x00") - 1,
-       "http://www.example.com/foo.crx?monkey", "", "application/octet-stream"},
-  };
-
-  TestArray(tests, arraysize(tests));
+  // wrong magic
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x01"),
+                          "http://www.example.com/foo.crx?monkey", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("PADDING_Cr24\x02\x00\x00\x00"),
+                          "http://www.example.com/foo.crx?monkey", ""));
 }
 
 TEST(MimeSnifferTest, MozillaCompatibleTest) {
-  SnifferTest tests[] = {
-    { " \n <hTmL>\n <hea", sizeof(" \n <hTmL>\n <hea")-1,
-      "http://www.example.com/",
-      "", "text/html" },
-    { " \n <hTmL>\n <hea", sizeof(" \n <hTmL>\n <hea")-1,
-      "http://www.example.com/",
-      "text/plain", "text/plain" },
-    { "BMjlakdsfk", sizeof("BMjlakdsfk")-1,
-      "http://www.example.com/foo",
-      "", "image/bmp" },
-    { "\x00\x00\x30\x00", sizeof("\x00\x00\x30\x00")-1,
-      "http://www.example.com/favicon.ico",
-      "", "application/octet-stream" },
-    { "#!/bin/sh\nls /\n", sizeof("#!/bin/sh\nls /\n")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-    { "From: Fred\nTo: Bob\n\nHi\n.\n",
-      sizeof("From: Fred\nTo: Bob\n\nHi\n.\n")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-    { "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
-      sizeof("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")-1,
-      "http://www.example.com/foo",
-      "", "text/xml" },
-    { "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
-      sizeof("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")-1,
-      "http://www.example.com/foo",
-      "application/octet-stream", "application/octet-stream" },
-  };
-
-  TestArray(tests, arraysize(tests));
+  EXPECT_EQ("text/html", SniffMimeType(MakeConstantString(" \n <hTmL>\n <hea"),
+                                       "http://www.example.com/", ""));
+  EXPECT_EQ("text/plain",
+            SniffMimeType(MakeConstantString(" \n <hTmL>\n <hea"),
+                          "http://www.example.com/", "text/plain"));
+  EXPECT_EQ("image/bmp", SniffMimeType(MakeConstantString("BMjlakdsfk"),
+                                       "http://www.example.com/foo", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("\x00\x00\x30\x00"),
+                          "http://www.example.com/favicon.ico", ""));
+  EXPECT_EQ("text/plain", SniffMimeType(MakeConstantString("#!/bin/sh\nls /\n"),
+                                        "http://www.example.com/foo", ""));
+  EXPECT_EQ("text/plain",
+            SniffMimeType(MakeConstantString("From: Fred\nTo: Bob\n\nHi\n.\n"),
+                          "http://www.example.com/foo", ""));
+  EXPECT_EQ("text/xml",
+            SniffMimeType(MakeConstantString(
+                              "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"),
+                          "http://www.example.com/foo", ""));
+  EXPECT_EQ(
+      "application/octet-stream",
+      SniffMimeType(
+          MakeConstantString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"),
+          "http://www.example.com/foo", "application/octet-stream"));
 }
 
 TEST(MimeSnifferTest, DontAllowPrivilegeEscalationTest) {
-  SnifferTest tests[] = {
-    { "GIF87a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("GIF87a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo",
-      "", "image/gif" },
-    { "GIF87a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("GIF87a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo?q=ttt.html",
-      "", "image/gif" },
-    { "GIF87a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("GIF87a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo#ttt.html",
-      "", "image/gif" },
-    { "a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-    { "a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo?q=ttt.html",
-      "", "text/plain" },
-    { "a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo#ttt.html",
-      "", "text/plain" },
-    { "a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n",
-      sizeof("a\n<html>\n<body>"
-        "<script>alert('haxorzed');\n</script>"
-        "</body></html>\n")-1,
-      "http://www.example.com/foo.html",
-      "", "text/plain" },
-  };
-
-  TestArray(tests, arraysize(tests));
+  EXPECT_EQ(
+      "image/gif",
+      SniffMimeType(MakeConstantString("GIF87a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo", ""));
+  EXPECT_EQ(
+      "image/gif",
+      SniffMimeType(MakeConstantString("GIF87a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo?q=ttt.html", ""));
+  EXPECT_EQ(
+      "image/gif",
+      SniffMimeType(MakeConstantString("GIF87a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo#ttt.html", ""));
+  EXPECT_EQ(
+      "text/plain",
+      SniffMimeType(MakeConstantString("a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo", ""));
+  EXPECT_EQ(
+      "text/plain",
+      SniffMimeType(MakeConstantString("a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo?q=ttt.html", ""));
+  EXPECT_EQ(
+      "text/plain",
+      SniffMimeType(MakeConstantString("a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo#ttt.html", ""));
+  EXPECT_EQ(
+      "text/plain",
+      SniffMimeType(MakeConstantString("a\n<html>\n<body>"
+                                       "<script>alert('haxorzed');\n</script>"
+                                       "</body></html>\n"),
+                    "http://www.example.com/foo.html", ""));
 }
 
 TEST(MimeSnifferTest, SniffFilesAsHtml) {
@@ -261,66 +233,61 @@
 }
 
 TEST(MimeSnifferTest, UnicodeTest) {
-  SnifferTest tests[] = {
-    { "\xEF\xBB\xBF" "Hi there", sizeof("\xEF\xBB\xBF" "Hi there")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-    { "\xEF\xBB\xBF\xED\x7A\xAD\x7A\x0D\x79",
-      sizeof("\xEF\xBB\xBF\xED\x7A\xAD\x7A\x0D\x79")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-    { "\xFE\xFF\xD0\xA5\xD0\xBE\xD0\xBB\xD1\x83\xD0\xB9",
-      sizeof("\xFE\xFF\xD0\xA5\xD0\xBE\xD0\xBB\xD1\x83\xD0\xB9")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-    { "\xFE\xFF\x00\x41\x00\x20\xD8\x00\xDC\x00\xD8\x00\xDC\x01",
-      sizeof("\xFE\xFF\x00\x41\x00\x20\xD8\x00\xDC\x00\xD8\x00\xDC\x01")-1,
-      "http://www.example.com/foo",
-      "", "text/plain" },
-  };
-
-  TestArray(tests, arraysize(tests));
+  EXPECT_EQ("text/plain", SniffMimeType(MakeConstantString("\xEF\xBB\xBF"
+                                                           "Hi there"),
+                                        "http://www.example.com/foo", ""));
+  EXPECT_EQ(
+      "text/plain",
+      SniffMimeType(MakeConstantString("\xEF\xBB\xBF\xED\x7A\xAD\x7A\x0D\x79"),
+                    "http://www.example.com/foo", ""));
+  EXPECT_EQ(
+      "text/plain",
+      SniffMimeType(MakeConstantString(
+                        "\xFE\xFF\xD0\xA5\xD0\xBE\xD0\xBB\xD1\x83\xD0\xB9"),
+                    "http://www.example.com/foo", ""));
+  EXPECT_EQ("text/plain",
+            SniffMimeType(
+                MakeConstantString(
+                    "\xFE\xFF\x00\x41\x00\x20\xD8\x00\xDC\x00\xD8\x00\xDC\x01"),
+                "http://www.example.com/foo", ""));
 }
 
 TEST(MimeSnifferTest, FlashTest) {
-  SnifferTest tests[] = {
-    { "CWSdd\x00\xB3", sizeof("CWSdd\x00\xB3")-1,
-      "http://www.example.com/foo",
-      "", "application/octet-stream" },
-    { "FLVjdkl*(#)0sdj\x00", sizeof("FLVjdkl*(#)0sdj\x00")-1,
-      "http://www.example.com/foo?q=ttt.swf",
-      "", "application/octet-stream" },
-    { "FWS3$9\r\b\x00", sizeof("FWS3$9\r\b\x00")-1,
-      "http://www.example.com/foo#ttt.swf",
-      "", "application/octet-stream" },
-    { "FLVjdkl*(#)0sdj", sizeof("FLVjdkl*(#)0sdj")-1,
-      "http://www.example.com/foo.swf",
-      "", "text/plain" },
-    { "FLVjdkl*(#)0s\x01dj", sizeof("FLVjdkl*(#)0s\x01dj")-1,
-      "http://www.example.com/foo/bar.swf",
-      "", "application/octet-stream" },
-    { "FWS3$9\r\b\x1A", sizeof("FWS3$9\r\b\x1A")-1,
-      "http://www.example.com/foo.swf?clickTAG=http://www.adnetwork.com/bar",
-      "", "application/octet-stream" },
-    { "FWS3$9\r\x1C\b", sizeof("FWS3$9\r\x1C\b")-1,
-      "http://www.example.com/foo.swf?clickTAG=http://www.adnetwork.com/bar",
-      "text/plain", "application/octet-stream" },
-  };
-
-  TestArray(tests, arraysize(tests));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("CWSdd\x00\xB3"),
+                          "http://www.example.com/foo", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("FLVjdkl*(#)0sdj\x00"),
+                          "http://www.example.com/foo?q=ttt.swf", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("FWS3$9\r\b\x00"),
+                          "http://www.example.com/foo#ttt.swf", ""));
+  EXPECT_EQ("text/plain", SniffMimeType(MakeConstantString("FLVjdkl*(#)0sdj"),
+                                        "http://www.example.com/foo.swf", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("FLVjdkl*(#)0s\x01dj"),
+                          "http://www.example.com/foo/bar.swf", ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("FWS3$9\r\b\x1A"),
+                          "http://www.example.com/foo.swf?clickTAG=http://"
+                          "www.adnetwork.com/bar",
+                          ""));
+  EXPECT_EQ("application/octet-stream",
+            SniffMimeType(MakeConstantString("FWS3$9\r\x1C\b"),
+                          "http://www.example.com/foo.swf?clickTAG=http://"
+                          "www.adnetwork.com/bar",
+                          "text/plain"));
 }
 
 TEST(MimeSnifferTest, XMLTest) {
   // An easy feed to identify.
   EXPECT_EQ("application/atom+xml",
-            SniffMimeType("<?xml?><feed", std::string(), "text/xml"));
+            SniffMimeType("<?xml?><feed", "", "text/xml"));
   // Don't sniff out of plain text.
-  EXPECT_EQ("text/plain",
-            SniffMimeType("<?xml?><feed", std::string(), "text/plain"));
+  EXPECT_EQ("text/plain", SniffMimeType("<?xml?><feed", "", "text/plain"));
   // Simple RSS.
   EXPECT_EQ("application/rss+xml",
-            SniffMimeType(
-                "<?xml version='1.0'?>\r\n<rss", std::string(), "text/xml"));
+            SniffMimeType("<?xml version='1.0'?>\r\n<rss", "", "text/xml"));
 
   // The top of CNN's RSS feed, which we'd like to recognize as RSS.
   static const char kCNNRSS[] =
@@ -332,39 +299,33 @@
       "<rss xmlns:feedburner=\"http://rssnamespace.org/feedburner/ext/1.0\" "
       "version=\"2.0\">";
   // CNN's RSS
-  EXPECT_EQ("application/rss+xml",
-            SniffMimeType(kCNNRSS, std::string(), "text/xml"));
-  EXPECT_EQ("text/plain", SniffMimeType(kCNNRSS, std::string(), "text/plain"));
+  EXPECT_EQ("application/rss+xml", SniffMimeType(kCNNRSS, "", "text/xml"));
+  EXPECT_EQ("text/plain", SniffMimeType(kCNNRSS, "", "text/plain"));
 
   // Don't sniff random XML as something different.
-  EXPECT_EQ("text/xml",
-            SniffMimeType("<?xml?><notafeed", std::string(), "text/xml"));
+  EXPECT_EQ("text/xml", SniffMimeType("<?xml?><notafeed", "", "text/xml"));
   // Don't sniff random plain-text as something different.
-  EXPECT_EQ("text/plain",
-            SniffMimeType("<?xml?><notafeed", std::string(), "text/plain"));
+  EXPECT_EQ("text/plain", SniffMimeType("<?xml?><notafeed", "", "text/plain"));
 
   // We never upgrade to application/xhtml+xml.
   EXPECT_EQ("text/xml",
-            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">",
-                          std::string(), "text/xml"));
+            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
+                          "text/xml"));
   EXPECT_EQ("application/xml",
-            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">",
-                          std::string(), "application/xml"));
+            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
+                          "application/xml"));
   EXPECT_EQ("text/plain",
-            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">",
-                          std::string(),
+            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
                           "text/plain"));
   EXPECT_EQ("application/rss+xml",
-            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">",
-                          std::string(),
+            SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
                           "application/rss+xml"));
-  EXPECT_EQ("text/xml",
-            SniffMimeType("<html><head>", std::string(), "text/xml"));
+  EXPECT_EQ("text/xml", SniffMimeType("<html><head>", "", "text/xml"));
   EXPECT_EQ("text/xml",
             SniffMimeType("<foo><rss "
                           "xmlns:feedburner=\"http://rssnamespace.org/"
                           "feedburner/ext/1.0\" version=\"2.0\">",
-                          std::string(), "text/xml"));
+                          "", "text/xml"));
 }
 
 // Test content which is >= 1024 bytes, and includes no open angle bracket.
@@ -400,54 +361,55 @@
 }
 
 TEST(MimeSnifferTest, OfficeTest) {
-  SnifferTest tests[] = {
     // Check for URLs incorrectly reported as Microsoft Office files.
-    { "Hi there",
-      sizeof("Hi there")-1,
-      "http://www.example.com/foo.doc",
-      "application/msword", "application/octet-stream" },
-    { "Hi there",
-      sizeof("Hi there")-1,
-      "http://www.example.com/foo.xls",
-      "application/vnd.ms-excel", "application/octet-stream" },
-    { "Hi there",
-      sizeof("Hi there")-1,
-      "http://www.example.com/foo.ppt",
-      "application/vnd.ms-powerpoint", "application/octet-stream" },
+    EXPECT_EQ(
+        "application/octet-stream",
+        SniffMimeType(MakeConstantString("Hi there"),
+                      "http://www.example.com/foo.doc", "application/msword"));
+    EXPECT_EQ("application/octet-stream",
+              SniffMimeType(MakeConstantString("Hi there"),
+                            "http://www.example.com/foo.xls",
+                            "application/vnd.ms-excel"));
+    EXPECT_EQ("application/octet-stream",
+              SniffMimeType(MakeConstantString("Hi there"),
+                            "http://www.example.com/foo.ppt",
+                            "application/vnd.ms-powerpoint"));
     // Check for Microsoft Office files incorrectly reported as text.
-    { "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" "Hi there",
-      sizeof("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" "Hi there")-1,
-      "http://www.example.com/foo.doc",
-      "text/plain", "application/msword" },
-    { "PK\x03\x04" "Hi there",
-      sizeof("PK\x03\x04" "Hi there")-1,
-      "http://www.example.com/foo.doc",
-      "text/plain",
-      "application/vnd.openxmlformats-officedocument."
-      "wordprocessingml.document" },
-    { "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" "Hi there",
-      sizeof("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" "Hi there")-1,
-      "http://www.example.com/foo.xls",
-      "text/plain", "application/vnd.ms-excel" },
-    { "PK\x03\x04" "Hi there",
-      sizeof("PK\x03\x04" "Hi there")-1,
-      "http://www.example.com/foo.xls",
-      "text/plain",
-      "application/vnd.openxmlformats-officedocument."
-      "spreadsheetml.sheet" },
-    { "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" "Hi there",
-      sizeof("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" "Hi there")-1,
-      "http://www.example.com/foo.ppt",
-      "text/plain", "application/vnd.ms-powerpoint" },
-    { "PK\x03\x04" "Hi there",
-      sizeof("PK\x03\x04" "Hi there")-1,
-      "http://www.example.com/foo.ppt",
-      "text/plain",
-      "application/vnd.openxmlformats-officedocument."
-      "presentationml.presentation" },
-  };
+    EXPECT_EQ(
+        "application/msword",
+        SniffMimeType(MakeConstantString("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
+                                         "Hi there"),
+                      "http://www.example.com/foo.doc", "text/plain"));
+    EXPECT_EQ(
+        "application/vnd.openxmlformats-officedocument."
+        "wordprocessingml.document",
+        SniffMimeType(MakeConstantString(
 
-  TestArray(tests, arraysize(tests));
+                          "PK\x03\x04"
+                          "Hi there"),
+                      "http://www.example.com/foo.doc", "text/plain"));
+    EXPECT_EQ(
+        "application/vnd.ms-excel",
+        SniffMimeType(MakeConstantString("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
+                                         "Hi there"),
+                      "http://www.example.com/foo.xls", "text/plain"));
+    EXPECT_EQ(
+        "application/vnd.openxmlformats-officedocument."
+        "spreadsheetml.sheet",
+        SniffMimeType(MakeConstantString("PK\x03\x04"
+                                         "Hi there"),
+                      "http://www.example.com/foo.xls", "text/plain"));
+    EXPECT_EQ(
+        "application/vnd.ms-powerpoint",
+        SniffMimeType(MakeConstantString("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
+                                         "Hi there"),
+                      "http://www.example.com/foo.ppt", "text/plain"));
+    EXPECT_EQ(
+        "application/vnd.openxmlformats-officedocument."
+        "presentationml.presentation",
+        SniffMimeType(MakeConstantString("PK\x03\x04"
+                                         "Hi there"),
+                      "http://www.example.com/foo.ppt", "text/plain"));
 }
 
 // TODO(thestig) Add more tests for other AV formats. Add another test case for
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index 59cf91d..568c10e3 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -9,6 +9,7 @@
 #include <unordered_set>
 
 #include "base/base64.h"
+#include "base/containers/span.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/rand_util.h"
@@ -368,16 +369,9 @@
 }
 
 // See http://www.iana.org/assignments/media-types/media-types.xhtml
-static const char* const legal_top_level_types[] = {
-  "application",
-  "audio",
-  "example",
-  "image",
-  "message",
-  "model",
-  "multipart",
-  "text",
-  "video",
+static const char* const kLegalTopLevelTypes[] = {
+    "application", "audio",     "example", "image", "message",
+    "model",       "multipart", "text",    "video",
 };
 
 bool MimeUtil::ParseMimeTypeWithoutParameter(
@@ -400,8 +394,8 @@
 
 bool MimeUtil::IsValidTopLevelMimeType(const std::string& type_string) const {
   std::string lower_type = base::ToLowerASCII(type_string);
-  for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) {
-    if (lower_type.compare(legal_top_level_types[i]) == 0)
+  for (const char* const legal_type : kLegalTopLevelTypes) {
+    if (lower_type.compare(legal_type) == 0)
       return true;
   }
 
@@ -519,15 +513,13 @@
 
 struct StandardType {
   const char* const leading_mime_type;
-  const char* const* standard_types;
-  size_t standard_types_len;
+  base::span<const char* const> standard_types;
 };
 static const StandardType kStandardTypes[] = {
-  { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) },
-  { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) },
-  { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) },
-  { NULL, NULL, 0 }
-};
+    {"image/", kStandardImageTypes},
+    {"audio/", kStandardAudioTypes},
+    {"video/", kStandardVideoTypes},
+    {nullptr, base::span<const char* const>()}};
 
 // GetExtensionsFromHardCodedMappings() adds file extensions (without a leading
 // dot) to the set |extensions|, for all MIME types matching |mime_type|.
@@ -539,9 +531,8 @@
 //
 //  * If |prefix_match = true| then |mime_type| is treated as the prefix for a
 //    (case-insensitive) string. For instance "Text/" would match "text/plain".
-template <size_t N>
 void GetExtensionsFromHardCodedMappings(
-    const MimeInfo (&mappings)[N],
+    base::span<const MimeInfo> mappings,
     const std::string& mime_type,
     bool prefix_match,
     std::unordered_set<base::FilePath::StringType>* extensions) {
@@ -561,12 +552,11 @@
 }
 
 void GetExtensionsHelper(
-    const char* const* standard_types,
-    size_t standard_types_len,
+    base::span<const char* const> standard_types,
     const std::string& leading_mime_type,
     std::unordered_set<base::FilePath::StringType>* extensions) {
-  for (size_t i = 0; i < standard_types_len; ++i) {
-    g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i],
+  for (auto* standard_type : standard_types) {
+    g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_type,
                                                        extensions);
   }
 
@@ -599,8 +589,8 @@
 // following characters are legal for boundaries:  '()+_,-./:=?
 // However the following characters, though legal, cause some sites
 // to fail: (),./:=+
-const char kMimeBoundaryCharacters[] =
-    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+constexpr base::StringPiece kMimeBoundaryCharacters(
+    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
 
 // Size of mime multipart boundary.
 const size_t kMimeBoundarySize = 69;
@@ -621,16 +611,16 @@
 
     // Find the matching StandardType from within kStandardTypes, or fall
     // through to the last (default) StandardType.
-    const StandardType* type = NULL;
-    for (size_t i = 0; i < arraysize(kStandardTypes); ++i) {
-      type = &(kStandardTypes[i]);
+    const StandardType* type = nullptr;
+    for (const StandardType& standard_type : kStandardTypes) {
+      type = &standard_type;
       if (type->leading_mime_type &&
-          leading_mime_type == type->leading_mime_type)
+          leading_mime_type == type->leading_mime_type) {
         break;
+      }
     }
     DCHECK(type);
     GetExtensionsHelper(type->standard_types,
-                        type->standard_types_len,
                         leading_mime_type,
                         &unique_extensions);
   } else {
@@ -671,10 +661,8 @@
   result.reserve(kMimeBoundarySize);
   result.append("----MultipartBoundary--");
   while (result.size() < (kMimeBoundarySize - 4)) {
-    // Subtract 2 from the array size to 1) exclude '\0', and 2) turn the size
-    // into the last index.
-    const int last_char_index = sizeof(kMimeBoundaryCharacters) - 2;
-    char c = kMimeBoundaryCharacters[base::RandInt(0, last_char_index)];
+    char c = kMimeBoundaryCharacters[base::RandInt(
+        0, kMimeBoundaryCharacters.size() - 1)];
     result.push_back(c);
   }
   result.append("----");
diff --git a/net/base/mime_util_unittest.cc b/net/base/mime_util_unittest.cc
index 473920b..f160583 100644
--- a/net/base/mime_util_unittest.cc
+++ b/net/base/mime_util_unittest.cc
@@ -47,11 +47,11 @@
   std::string mime_type;
   bool rv;
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    rv = GetMimeTypeFromExtension(tests[i].extension, &mime_type);
-    EXPECT_EQ(tests[i].valid, rv);
+  for (const auto& test : tests) {
+    rv = GetMimeTypeFromExtension(test.extension, &mime_type);
+    EXPECT_EQ(test.valid, rv);
     if (rv)
-      EXPECT_EQ(tests[i].mime_type, mime_type);
+      EXPECT_EQ(test.mime_type, mime_type);
   }
 }
 
@@ -73,12 +73,11 @@
   std::string mime_type;
   bool rv;
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    rv = GetMimeTypeFromFile(base::FilePath(tests[i].file_path),
-                                  &mime_type);
-    EXPECT_EQ(tests[i].valid, rv);
+  for (const auto& test : tests) {
+    rv = GetMimeTypeFromFile(base::FilePath(test.file_path), &mime_type);
+    EXPECT_EQ(test.valid, rv);
     if (rv)
-      EXPECT_EQ(tests[i].mime_type, mime_type);
+      EXPECT_EQ(test.mime_type, mime_type);
   }
 }
 
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc
index 573ec3a..37f34ec1 100644
--- a/net/base/network_change_notifier.cc
+++ b/net/base/network_change_notifier.cc
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
@@ -709,7 +710,7 @@
     "CONNECTION_NONE",
     "CONNECTION_BLUETOOTH"
   };
-  static_assert(arraysize(kConnectionTypeNames) ==
+  static_assert(base::size(kConnectionTypeNames) ==
                     NetworkChangeNotifier::CONNECTION_LAST + 1,
                 "ConnectionType name count should match");
   if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) {
diff --git a/net/base/network_interfaces_fuchsia.cc b/net/base/network_interfaces_fuchsia.cc
index f535143..947cd83 100644
--- a/net/base/network_interfaces_fuchsia.cc
+++ b/net/base/network_interfaces_fuchsia.cc
@@ -11,7 +11,7 @@
 
 namespace net {
 
-IPAddress NetAddressToIPAddress(const fuchsia::netstack::NetAddress& addr) {
+IPAddress NetAddressToIPAddress(const netstack::NetAddress& addr) {
   if (addr.ipv4) {
     return IPAddress(addr.ipv4->addr.data(), addr.ipv4->addr.count());
   }
@@ -22,25 +22,25 @@
 }
 
 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
-  fuchsia::netstack::NetstackSyncPtr netstack =
+  netstack::NetstackSyncPtr netstack =
       base::fuchsia::ComponentContext::GetDefault()
-          ->ConnectToServiceSync<fuchsia::netstack::Netstack>();
+          ->ConnectToServiceSync<netstack::Netstack>();
 
-  fidl::VectorPtr<fuchsia::netstack::NetInterface> interfaces;
+  fidl::VectorPtr<netstack::NetInterface> interfaces;
   if (!netstack->GetInterfaces(&interfaces))
     return false;
 
   for (auto& interface : interfaces.get()) {
     // Check if the interface is up.
-    if (!(interface.flags & fuchsia::netstack::NetInterfaceFlagUp))
+    if (!(interface.flags & netstack::NetInterfaceFlagUp))
       continue;
 
     // Skip loopback.
-    if (interface.features & fuchsia::netstack::interfaceFeatureLoopback)
+    if (interface.features & netstack::interfaceFeatureLoopback)
       continue;
 
     NetworkChangeNotifier::ConnectionType connection_type =
-        (interface.features & fuchsia::netstack::interfaceFeatureWlan)
+        (interface.features & netstack::interfaceFeatureWlan)
             ? NetworkChangeNotifier::CONNECTION_WIFI
             : NetworkChangeNotifier::CONNECTION_UNKNOWN;
 
diff --git a/net/base/network_interfaces_linux_unittest.cc b/net/base/network_interfaces_linux_unittest.cc
index 85a7367..fe1984b2 100644
--- a/net/base/network_interfaces_linux_unittest.cc
+++ b/net/base/network_interfaces_linux_unittest.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <unordered_set>
 
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "net/base/address_tracker_linux.h"
@@ -30,18 +31,17 @@
                                           0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
                                           0xfe, 0xe5, 0x00, 0xc3};
 
-char* CopyInterfaceName(const char* ifname, int ifname_size, char* output) {
-  EXPECT_LT(ifname_size, IF_NAMESIZE);
-  memcpy(output, ifname, ifname_size);
-  return output;
-}
-
 char* GetInterfaceName(int interface_index, char* ifname) {
-  return CopyInterfaceName(kIfnameEm1, arraysize(kIfnameEm1), ifname);
+  static_assert(base::size(kIfnameEm1) < IF_NAMESIZE, "Invalid interface name");
+  memcpy(ifname, kIfnameEm1, base::size(kIfnameEm1));
+  return ifname;
 }
 
 char* GetInterfaceNameVM(int interface_index, char* ifname) {
-  return CopyInterfaceName(kIfnameVmnet, arraysize(kIfnameVmnet), ifname);
+  static_assert(base::size(kIfnameVmnet) < IF_NAMESIZE,
+                "Invalid interface name");
+  memcpy(ifname, kIfnameVmnet, base::size(kIfnameVmnet));
+  return ifname;
 }
 
 TEST(NetworkInterfacesTest, NetworkListTrimmingLinux) {
diff --git a/net/base/network_interfaces_win.cc b/net/base/network_interfaces_win.cc
index d4cc641..2a81aeba 100644
--- a/net/base/network_interfaces_win.cc
+++ b/net/base/network_interfaces_win.cc
@@ -9,6 +9,7 @@
 
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
+#include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
@@ -105,7 +106,7 @@
   // Use an absolute path to load the DLL to avoid DLL preloading attacks.
   static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll";
   wchar_t path[MAX_PATH] = {0};
-  ExpandEnvironmentStrings(kDLL, path, arraysize(path));
+  ExpandEnvironmentStrings(kDLL, path, base::size(path));
   module = ::LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
   if (!module)
     return;
diff --git a/net/base/port_util_unittest.cc b/net/base/port_util_unittest.cc
index 6bd163f..fac64e6d 100644
--- a/net/base/port_util_unittest.cc
+++ b/net/base/port_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -14,12 +15,12 @@
   std::string invalid[] = {"1,2,a", "'1','2'", "1, 2, 3", "1 0,11,12"};
   std::string valid[] = {"", "1", "1,2", "1,2,3", "10,11,12,13"};
 
-  for (size_t i = 0; i < arraysize(invalid); ++i) {
+  for (size_t i = 0; i < base::size(invalid); ++i) {
     SetExplicitlyAllowedPorts(invalid[i]);
     EXPECT_EQ(0, static_cast<int>(GetCountOfExplicitlyAllowedPorts()));
   }
 
-  for (size_t i = 0; i < arraysize(valid); ++i) {
+  for (size_t i = 0; i < base::size(valid); ++i) {
     SetExplicitlyAllowedPorts(valid[i]);
     EXPECT_EQ(i, GetCountOfExplicitlyAllowedPorts());
   }
diff --git a/net/base/priority_queue_unittest.cc b/net/base/priority_queue_unittest.cc
index 3e68acfb..435c08a 100644
--- a/net/base/priority_queue_unittest.cc
+++ b/net/base/priority_queue_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <cstddef>
 
+#include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -13,13 +14,13 @@
 namespace {
 
 typedef PriorityQueue<int>::Priority Priority;
-const Priority kPriorities[] = { 2, 1, 2, 0, 4, 3, 1, 4, 0 };
-const Priority kNumPriorities = 5;  // max(kPriorities) + 1
-const size_t kNumElements = arraysize(kPriorities);
-const int kFirstMinOrder[kNumElements] = { 3, 8, 1, 6, 0, 2, 5, 4, 7 };
-const int kLastMaxOrderErase[kNumElements] = { 7, 4, 5, 2, 0, 6, 1, 8, 3 };
-const int kFirstMaxOrder[kNumElements] = { 4, 7, 5, 0, 2, 1, 6, 3, 8 };
-const int kLastMinOrder[kNumElements] = { 8, 3, 6, 1, 2, 0, 5, 7, 4 };
+constexpr Priority kPriorities[] = {2, 1, 2, 0, 4, 3, 1, 4, 0};
+constexpr Priority kNumPriorities = 5;  // max(kPriorities) + 1
+constexpr size_t kNumElements = base::size(kPriorities);
+constexpr int kFirstMinOrder[kNumElements] = {3, 8, 1, 6, 0, 2, 5, 4, 7};
+constexpr int kLastMaxOrderErase[kNumElements] = {7, 4, 5, 2, 0, 6, 1, 8, 3};
+constexpr int kFirstMaxOrder[kNumElements] = {4, 7, 5, 0, 2, 1, 6, 3, 8};
+constexpr int kLastMinOrder[kNumElements] = {8, 3, 6, 1, 2, 0, 5, 7, 4};
 
 class PriorityQueueTest : public testing::Test {
  protected:
@@ -124,8 +125,8 @@
 
   const int expected_order[] = { 8, 1, 6, 0, 5, 4, 7 };
 
-  for (size_t i = 0; i < arraysize(expected_order); ++i) {
-    EXPECT_EQ(expected_order[i], queue_.FirstMin().value());
+  for (const auto& value : expected_order) {
+    EXPECT_EQ(value, queue_.FirstMin().value());
     queue_.Erase(queue_.FirstMin());
   }
   CheckEmpty();
@@ -139,8 +140,8 @@
 
   const int expected_order[] = { 10, 3, 8, 12, 11, 1, 6, 9, 0, 2, 5, 4, 7 };
 
-  for (size_t i = 0; i < arraysize(expected_order); ++i) {
-    EXPECT_EQ(expected_order[i], queue_.FirstMin().value());
+  for (const auto& value : expected_order) {
+    EXPECT_EQ(value, queue_.FirstMin().value());
     queue_.Erase(queue_.FirstMin());
   }
   CheckEmpty();
diff --git a/net/base/upload_bytes_element_reader_unittest.cc b/net/base/upload_bytes_element_reader_unittest.cc
index 2b6298ea..c4a43385 100644
--- a/net/base/upload_bytes_element_reader_unittest.cc
+++ b/net/base/upload_bytes_element_reader_unittest.cc
@@ -21,8 +21,7 @@
 class UploadBytesElementReaderTest : public PlatformTest {
  protected:
   void SetUp() override {
-    const char kData[] = "123abc";
-    bytes_.assign(kData, kData + arraysize(kData));
+    bytes_.assign({'1', '2', '3', 'a', 'b', 'c'});
     reader_.reset(new UploadBytesElementReader(&bytes_[0], bytes_.size()));
     ASSERT_THAT(reader_->Init(CompletionOnceCallback()), IsOk());
     EXPECT_EQ(bytes_.size(), reader_->GetContentLength());
diff --git a/net/base/upload_file_element_reader_unittest.cc b/net/base/upload_file_element_reader_unittest.cc
index 213c46b..eec7b3fe 100644
--- a/net/base/upload_file_element_reader_unittest.cc
+++ b/net/base/upload_file_element_reader_unittest.cc
@@ -38,8 +38,8 @@
  protected:
   void SetUp() override {
     // Some tests (*.ReadPartially) rely on bytes_.size() being even.
-    const char kData[] = "123456789abcdefghi";
-    bytes_.assign(kData, kData + arraysize(kData) - 1);
+    bytes_.assign({'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',
+                   'd', 'e', 'f', 'g', 'h', 'i'});
 
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
diff --git a/net/base/url_util_unittest.cc b/net/base/url_util_unittest.cc
index 67acfd23..bd8125fd 100644
--- a/net/base/url_util_unittest.cc
+++ b/net/base/url_util_unittest.cc
@@ -211,16 +211,15 @@
     {"[]", false, "", -1},
   };
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (const auto& test : tests) {
     std::string host;
     int port;
-    bool ok = ParseHostAndPort(tests[i].input, &host, &port);
+    bool ok = ParseHostAndPort(test.input, &host, &port);
+    EXPECT_EQ(test.success, ok);
 
-    EXPECT_EQ(tests[i].success, ok);
-
-    if (tests[i].success) {
-      EXPECT_EQ(tests[i].expected_host, host);
-      EXPECT_EQ(tests[i].expected_port, port);
+    if (test.success) {
+      EXPECT_EQ(test.expected_host, host);
+      EXPECT_EQ(test.expected_port, port);
     }
   }
 }
@@ -236,9 +235,9 @@
     { GURL("http://[1::2]/x"), "[1::2]:80"},
     { GURL("http://[::a]:33/x"), "[::a]:33"},
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    std::string host_and_port = GetHostAndPort(tests[i].url);
-    EXPECT_EQ(std::string(tests[i].expected_host_and_port), host_and_port);
+  for (const auto& test : tests) {
+    std::string host_and_port = GetHostAndPort(test.url);
+    EXPECT_EQ(std::string(test.expected_host_and_port), host_and_port);
   }
 }
 
@@ -254,9 +253,9 @@
     { GURL("http://[1::2]/x"), "[1::2]"},
     { GURL("http://[::a]:33/x"), "[::a]:33"},
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    std::string host_and_port = GetHostAndOptionalPort(tests[i].url);
-    EXPECT_EQ(std::string(tests[i].expected_host_and_port), host_and_port);
+  for (const auto& test : tests) {
+    std::string host_and_port = GetHostAndOptionalPort(test.url);
+    EXPECT_EQ(std::string(test.expected_host_and_port), host_and_port);
   }
 }
 
@@ -302,9 +301,9 @@
       {"1.2.3.4.5.", true},
   };
 
-  for (size_t i = 0; i < arraysize(compliant_host_cases); ++i) {
-    EXPECT_EQ(compliant_host_cases[i].expected_output,
-              IsCanonicalizedHostCompliant(compliant_host_cases[i].host));
+  for (const auto& compliant_host : compliant_host_cases) {
+    EXPECT_EQ(compliant_host.expected_output,
+              IsCanonicalizedHostCompliant(compliant_host.host));
   }
 }
 
@@ -471,11 +470,10 @@
       "foobar://user:pass@google.com:80/sup?yo",
     },
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
-                                    tests[i].input_url));
-    GURL input_url(GURL(tests[i].input_url));
-    GURL expected_url(GURL(tests[i].expected_simplified_url));
+  for (const auto& test : tests) {
+    SCOPED_TRACE(test.input_url);
+    GURL input_url(GURL(test.input_url));
+    GURL expected_url(GURL(test.expected_simplified_url));
     EXPECT_EQ(expected_url, SimplifyUrlForRequest(input_url));
   }
 }
@@ -522,16 +520,15 @@
       "p&ssword",
     },
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
-    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
-                                    tests[i].input_url));
-    GURL url(tests[i].input_url);
+  for (const auto& test : tests) {
+    SCOPED_TRACE(test.input_url);
+    GURL url(test.input_url);
 
     base::string16 username, password;
     GetIdentityFromURL(url, &username, &password);
 
-    EXPECT_EQ(ASCIIToUTF16(tests[i].expected_username), username);
-    EXPECT_EQ(ASCIIToUTF16(tests[i].expected_password), password);
+    EXPECT_EQ(ASCIIToUTF16(test.expected_username), username);
+    EXPECT_EQ(ASCIIToUTF16(test.expected_password), password);
   }
 }
 
@@ -580,9 +577,8 @@
       {GURL("http://oggole.com"), false},
   };
 
-  for (size_t i = 0; i < arraysize(google_host_cases); ++i) {
-    EXPECT_EQ(google_host_cases[i].expected_output,
-              HasGoogleHost(google_host_cases[i].url));
+  for (const auto& host : google_host_cases) {
+    EXPECT_EQ(host.expected_output, HasGoogleHost(host.url));
   }
 }
 
diff --git a/net/cert/cert_database.cc b/net/cert/cert_database.cc
index 51f0005..b20ec55 100644
--- a/net/cert/cert_database.cc
+++ b/net/cert/cert_database.cc
@@ -29,4 +29,13 @@
   observer_list_->Notify(FROM_HERE, &Observer::OnCertDBChanged);
 }
 
+CertDatabase::CertDatabase()
+    : observer_list_(new base::ObserverListThreadSafe<Observer>) {}
+
+CertDatabase::~CertDatabase() {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  ReleaseNotifier();
+#endif
+}
+
 }  // namespace net
diff --git a/net/cert/cert_database.h b/net/cert/cert_database.h
index b44b78ce..32b74a3 100644
--- a/net/cert/cert_database.h
+++ b/net/cert/cert_database.h
@@ -9,8 +9,8 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "build/build_config.h"
 #include "net/base/net_export.h"
-#include "net/cert/x509_certificate.h"
 
 namespace base {
 template <typename T> struct DefaultSingletonTraits;
@@ -21,12 +21,14 @@
 
 namespace net {
 
-// This class provides cross-platform functions to verify and add user
-// certificates, and to observe changes to the underlying certificate stores.
-
-// TODO(gauravsh): This class could be augmented with methods
-// for all operations that manipulate the underlying system
-// certificate store.
+// This class allows callers to observe changes to the underlying certificate
+// stores.
+//
+// TODO(davidben): This class is really just a giant global ObserverList. It
+// does not do anything with the platform certificate and, in principle, //net's
+// dependency on the platform is abstracted behind the CertVerifier and
+// ClientCertStore interfaces. Ideally these signals would originate out of
+// those interfaces' platform implementations.
 
 class NET_EXPORT CertDatabase {
  public:
@@ -71,21 +73,9 @@
   void SetMessageLoopForKeychainEvents();
 #endif
 
-#if defined(OS_ANDROID)
-  // On Android, the system key store may be replaced with a device-specific
-  // KeyStore used for storing client certificates. When the Java side replaces
-  // the KeyStore used for client certificates, notifies the observers as if a
-  // new client certificate was added.
-  void OnAndroidKeyStoreChanged();
-
-  // On Android, the system database is used. When the system notifies the
-  // application that the certificates changed, the observers must be notified.
-  void OnAndroidKeyChainChanged();
-#endif
-
   // Synthetically injects notifications to all observers. In general, this
   // should only be called by the creator of the CertDatabase. Used to inject
-  // notifcations from other DB interfaces.
+  // notifications from other DB interfaces.
   void NotifyObserversCertDBChanged();
 
  private:
@@ -97,9 +87,11 @@
   const scoped_refptr<base::ObserverListThreadSafe<Observer>> observer_list_;
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
+  void ReleaseNotifier();
+
   class Notifier;
   friend class Notifier;
-  std::unique_ptr<Notifier> notifier_;
+  Notifier* notifier_ = nullptr;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(CertDatabase);
diff --git a/net/cert/cert_database_android.cc b/net/cert/cert_database_android.cc
deleted file mode 100644
index 5631f7cf..0000000
--- a/net/cert/cert_database_android.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cert/cert_database.h"
-
-#include "base/logging.h"
-#include "base/observer_list_threadsafe.h"
-#include "net/base/net_errors.h"
-
-namespace net {
-
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {
-}
-
-CertDatabase::~CertDatabase() {}
-
-void CertDatabase::OnAndroidKeyStoreChanged() {
-  NotifyObserversCertDBChanged();
-}
-
-void CertDatabase::OnAndroidKeyChainChanged() {
-  observer_list_->Notify(FROM_HERE, &Observer::OnCertDBChanged);
-}
-
-}  // namespace net
diff --git a/net/cert/cert_database_fuchsia.cc b/net/cert/cert_database_fuchsia.cc
deleted file mode 100644
index e9f884e..0000000
--- a/net/cert/cert_database_fuchsia.cc
+++ /dev/null
@@ -1,16 +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 "net/cert/cert_database.h"
-
-#include "base/observer_list_threadsafe.h"
-
-namespace net {
-
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {}
-
-CertDatabase::~CertDatabase() {}
-
-}  // namespace net
diff --git a/net/cert/cert_database_ios.cc b/net/cert/cert_database_ios.cc
deleted file mode 100644
index c426ee9..0000000
--- a/net/cert/cert_database_ios.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cert/cert_database.h"
-
-#include "base/logging.h"
-#include "base/observer_list_threadsafe.h"
-#include "net/base/net_errors.h"
-
-namespace net {
-
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {
-}
-
-CertDatabase::~CertDatabase() {}
-
-}  // namespace net
diff --git a/net/cert/cert_database_mac.cc b/net/cert/cert_database_mac.cc
index 0cfd4154d..12dce73ac 100644
--- a/net/cert/cert_database_mac.cc
+++ b/net/cert/cert_database_mac.cc
@@ -116,21 +116,16 @@
 }
 
 void CertDatabase::SetMessageLoopForKeychainEvents() {
-  // Shutdown will take care to delete the notifier on the right thread.
-  if (notifier_.get())
-    notifier_.release()->Shutdown();
-
-  notifier_.reset(new Notifier(this, base::MessageLoopCurrentForUI::Get()));
+  ReleaseNotifier();
+  notifier_ = new Notifier(this, base::MessageLoopCurrentForUI::Get());
 }
 
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {
-}
-
-CertDatabase::~CertDatabase() {
+void CertDatabase::ReleaseNotifier() {
   // Shutdown will take care to delete the notifier on the right thread.
-  if (notifier_.get())
-    notifier_.release()->Shutdown();
+  if (notifier_) {
+    notifier_->Shutdown();
+    notifier_ = nullptr;
+  }
 }
 
 }  // namespace net
diff --git a/net/cert/cert_database_nss.cc b/net/cert/cert_database_nss.cc
deleted file mode 100644
index 832f901..0000000
--- a/net/cert/cert_database_nss.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cert/cert_database.h"
-
-#include "base/observer_list_threadsafe.h"
-
-namespace net {
-
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {
-}
-
-CertDatabase::~CertDatabase() = default;
-
-}  // namespace net
diff --git a/net/cert/cert_database_stub.cc b/net/cert/cert_database_stub.cc
deleted file mode 100644
index 63589b60..0000000
--- a/net/cert/cert_database_stub.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cert/cert_database.h"
-
-#include "base/observer_list_threadsafe.h"
-
-namespace net {
-
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {}
-
-CertDatabase::~CertDatabase() {}
-
-}  // namespace net
diff --git a/net/cert/cert_database_win.cc b/net/cert/cert_database_win.cc
deleted file mode 100644
index 32c9168..0000000
--- a/net/cert/cert_database_win.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/cert/cert_database.h"
-
-#include "base/observer_list_threadsafe.h"
-
-namespace net {
-
-CertDatabase::CertDatabase()
-    : observer_list_(new base::ObserverListThreadSafe<Observer>) {
-}
-
-CertDatabase::~CertDatabase() {}
-
-}  // namespace net
diff --git a/net/cert/x509_util_android.cc b/net/cert/x509_util_android.cc
index 8ee18742..2ef23d21e 100644
--- a/net/cert/x509_util_android.cc
+++ b/net/cert/x509_util_android.cc
@@ -11,7 +11,7 @@
 
 void JNI_X509Util_NotifyKeyChainChanged(JNIEnv* env,
                                         const JavaParamRef<jclass>& clazz) {
-  CertDatabase::GetInstance()->OnAndroidKeyChainChanged();
+  CertDatabase::GetInstance()->NotifyObserversCertDBChanged();
 }
 
 }  // namespace net
diff --git a/net/docs/bug-triage-suggested-workflow.md b/net/docs/bug-triage-suggested-workflow.md
index dcde25f..c955025 100644
--- a/net/docs/bug-triage-suggested-workflow.md
+++ b/net/docs/bug-triage-suggested-workflow.md
@@ -29,24 +29,6 @@
 
 * If non-network causes also seem possible, attach those components as well.
 
-## Investigate UMA notifications
-
-For each alert that fires, determine if it's a real alert and file a bug if so.
-
-* Don't file if the alert is coincident with a major volume change.  The volume
-  at a particular date can be determined by hovering the mouse over the
-  appropriate location on the alert line.
-
-* Don't file if the alert is on a graph with very low volume (< ~200 data
-  points); it's probably noise, and we probably don't care even if it isn't.
-
-* Don't file if the graph is really noisy (but eyeball it to decide if there is
-  an underlying important shift under the noise).
-
-* Don't file if the alert is in the "Known Ignorable" list:
-    * SimpleCache on Windows
-    * DiskCache on Android.
-
 ## Investigating component=Internals>Network bugs
 
 * Note that you may want to investigate Needs-Feedback bugs first, as
diff --git a/net/docs/bug-triage.md b/net/docs/bug-triage.md
index eb349ad..d9b04143d 100644
--- a/net/docs/bug-triage.md
+++ b/net/docs/bug-triage.md
@@ -8,7 +8,6 @@
 
 ### Required, in rough order of priority:
 * Identify new network bugs on the tracker.
-* Investigate UMA notifications.
 * Investigate recent Internals>Network issues with no subcomponent.
 * Follow up on Needs-Feedback issues for all network components.
 * Identify and file bugs for significant new crashers.
@@ -33,8 +32,8 @@
 * Identify new network bugs on the bug tracker, looking at [this issue tracker
   query](https://bugs.chromium.org/p/chromium/issues/list?q=status%3Aunconfirmed&sort=-id&num=1000).
 
-  * All Unconfirmed issues filed during your triage rotation should be scanned,
-    and, for suspected network bugs, a network component assigned and a
+  * All Unconfirmed issues filed during your triage rotation should be scanned
+    for suspected network bugs, a network component assigned and a
     chrome://net-export/ log requested.  Suggested text: "Please collect and
     attach a chrome://net-export log. Instructions can be found here:
     https://sites.google.com/a/chromium.org/dev/for-testers/providing-network-details".
@@ -45,24 +44,6 @@
     3:00 pm EST of the last day of the previous triager's rotation until the
     same time on the last day of their rotation.
 
-* Investigate UMA notifications.
-
-    * UMA notifications ("chirps") are alerts based on UMA histograms that are
-      sent to   chrome-network-debugging@google.com.  Triagers should subscribe
-      to this list.  When an alert fires, the triager should determine if the
-      alert looks to be real and file a bug with the appropriate label if so.
-      Note that if no label more specific than Internals&gt;Network is
-      appropriate, the responsibility remains with the triager to continue
-      investigating the bug, as above.
-
-    * The triager is responsible for looking at any notification previous
-      triagers did not, so when an issue is investigated, the person who did
-      so should respond to chrome-network-debugging@google.com with a short
-      email, describing their conclusions.  Future triagers can then use the
-      fact an alert was responded to as an indicator of which of them need
-      to be followed up on.  Alerts fired before the beginning of the
-      previous triager's rotation may be ignored.
-
 * Investigate [Unconfirmed / Untriaged Internals>Network issues that don't belong to a more specific network component](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3DInternals%3ENetwork+status%3AUnconfirmed,Untriaged+-label:Needs-Feedback&sort=-modified),
   prioritizing the most recent issues, ones with the most responsive reporters,
   and major crashers.  This will generally take up the majority of your time as
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index 5c446dd..9cd0edf 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -223,7 +223,6 @@
     // We reach this case when the user cancels a 407 proxy auth prompt.
     // See http://crbug.com/8473.
     DCHECK_EQ(407, response_.headers->response_code());
-    LogBlockedTunnelResponse();
 
     return ERR_TUNNEL_CONNECTION_FAILED;
   }
@@ -301,12 +300,6 @@
   return OK;
 }
 
-void HttpProxyClientSocket::LogBlockedTunnelResponse() const {
-  ProxyClientSocket::LogBlockedTunnelResponse(
-      response_.headers->response_code(),
-      is_https_proxy_);
-}
-
 void HttpProxyClientSocket::DoCallback(int result) {
   DCHECK_NE(ERR_IO_PENDING, result);
   DCHECK(!user_callback_.is_null());
@@ -470,10 +463,8 @@
       // sanitize the response.  This still allows a rogue HTTPS proxy to
       // redirect an HTTPS site load to a similar-looking site, but no longer
       // allows it to impersonate the site the user requested.
-      if (!is_https_proxy_ || !SanitizeProxyRedirect(&response_)) {
-        LogBlockedTunnelResponse();
+      if (!is_https_proxy_ || !SanitizeProxyRedirect(&response_))
         return ERR_TUNNEL_CONNECTION_FAILED;
-      }
 
       redirect_has_load_timing_info_ = transport_->GetLoadTimingInfo(
           http_stream_parser_->IsConnectionReused(),
@@ -487,10 +478,8 @@
       // authentication code is smart enough to avoid being tricked by an
       // active network attacker.
       // The next state is intentionally not set as it should be STATE_NONE;
-      if (!SanitizeProxyAuth(&response_)) {
-        LogBlockedTunnelResponse();
+      if (!SanitizeProxyAuth(&response_))
         return ERR_TUNNEL_CONNECTION_FAILED;
-      }
       return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
 
     default:
@@ -500,7 +489,6 @@
       // 501 response bodies that contain a useful error message.  For
       // example, Squid uses a 404 response to report the DNS error: "The
       // domain name does not exist."
-      LogBlockedTunnelResponse();
       return ERR_TUNNEL_CONNECTION_FAILED;
   }
 }
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index 15bd9a5..c744158 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -114,8 +114,6 @@
   int PrepareForAuthRestart();
   int DidDrainBodyForAuthRestart();
 
-  void LogBlockedTunnelResponse() const;
-
   void DoCallback(int result);
   void OnIOComplete(int result);
 
diff --git a/net/http/proxy_client_socket.cc b/net/http/proxy_client_socket.cc
index 1cfa0c3..fe23978 100644
--- a/net/http/proxy_client_socket.cc
+++ b/net/http/proxy_client_socket.cc
@@ -57,22 +57,6 @@
 }
 
 // static
-void ProxyClientSocket::LogBlockedTunnelResponse(int http_status_code,
-                                                 bool is_https_proxy) {
-  if (is_https_proxy) {
-    UMA_HISTOGRAM_CUSTOM_ENUMERATION(
-        "Net.BlockedTunnelResponse.HttpsProxy",
-        HttpUtil::MapStatusCodeForHistogram(http_status_code),
-        HttpUtil::GetStatusCodesForHistogram());
-  } else {
-    UMA_HISTOGRAM_CUSTOM_ENUMERATION(
-        "Net.BlockedTunnelResponse.HttpProxy",
-        HttpUtil::MapStatusCodeForHistogram(http_status_code),
-        HttpUtil::GetStatusCodesForHistogram());
-  }
-}
-
-// static
 bool ProxyClientSocket::SanitizeProxyAuth(HttpResponseInfo* response) {
   DCHECK(response && response->headers.get());
 
diff --git a/net/http/proxy_client_socket.h b/net/http/proxy_client_socket.h
index 7979f77..046ea6c7 100644
--- a/net/http/proxy_client_socket.h
+++ b/net/http/proxy_client_socket.h
@@ -74,10 +74,6 @@
                                       HttpResponseInfo* response,
                                       const NetLogWithSource& net_log);
 
-  // Logs (to the log and in a histogram) a blocked CONNECT response.
-  static void LogBlockedTunnelResponse(int http_response_code,
-                                       bool is_https_proxy);
-
   // When a proxy authentication response is received during tunnel
   // construction, this method should be called to strip everything
   // but the auth header from the redirect response.  If it returns
diff --git a/net/quic/chromium/quic_proxy_client_socket.cc b/net/quic/chromium/quic_proxy_client_socket.cc
index 703c919..baa81021 100644
--- a/net/quic/chromium/quic_proxy_client_socket.cc
+++ b/net/quic/chromium/quic_proxy_client_socket.cc
@@ -270,12 +270,6 @@
                        : ERR_SOCKET_NOT_CONNECTED;
 }
 
-void QuicProxyClientSocket::LogBlockedTunnelResponse() const {
-  ProxyClientSocket::LogBlockedTunnelResponse(
-      response_.headers->response_code(),
-      /* is_https_proxy = */ true);
-}
-
 void QuicProxyClientSocket::OnIOComplete(int result) {
   DCHECK_NE(STATE_DISCONNECTED, next_state_);
   int rv = DoLoop(result);
@@ -419,10 +413,8 @@
     case 302:  // Found / Moved Temporarily
       // Try to return a sanitized response so we can follow auth redirects.
       // If we can't, fail the tunnel connection.
-      if (!SanitizeProxyRedirect(&response_)) {
-        LogBlockedTunnelResponse();
+      if (!SanitizeProxyRedirect(&response_))
         return ERR_TUNNEL_CONNECTION_FAILED;
-      }
       redirect_has_load_timing_info_ =
           GetLoadTimingInfo(&redirect_load_timing_info_);
       next_state_ = STATE_DISCONNECTED;
@@ -430,16 +422,13 @@
 
     case 407:  // Proxy Authentication Required
       next_state_ = STATE_CONNECT_COMPLETE;
-      if (!SanitizeProxyAuth(&response_)) {
-        LogBlockedTunnelResponse();
+      if (!SanitizeProxyAuth(&response_))
         return ERR_TUNNEL_CONNECTION_FAILED;
-      }
       return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
 
     default:
       // Ignore response to avoid letting the proxy impersonate the target
       // server.  (See http://crbug.com/137891.)
-      LogBlockedTunnelResponse();
       return ERR_TUNNEL_CONNECTION_FAILED;
   }
 }
diff --git a/net/quic/chromium/quic_proxy_client_socket.h b/net/quic/chromium/quic_proxy_client_socket.h
index 6c98e7c..903527d 100644
--- a/net/quic/chromium/quic_proxy_client_socket.h
+++ b/net/quic/chromium/quic_proxy_client_socket.h
@@ -91,8 +91,6 @@
     STATE_CONNECT_COMPLETE
   };
 
-  void LogBlockedTunnelResponse() const;
-
   void OnIOComplete(int result);  // Callback used during connecting
   void OnReadComplete(int rv);
   void OnWriteComplete(int rv);
diff --git a/net/spdy/chromium/header_coalescer.cc b/net/spdy/chromium/header_coalescer.cc
index d2f80f7..2b0206a2 100644
--- a/net/spdy/chromium/header_coalescer.cc
+++ b/net/spdy/chromium/header_coalescer.cc
@@ -5,6 +5,7 @@
 #include "net/spdy/chromium/header_coalescer.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
diff --git a/net/spdy/chromium/header_coalescer_test.cc b/net/spdy/chromium/header_coalescer_test.cc
index 14bf757..c8c1534e 100644
--- a/net/spdy/chromium/header_coalescer_test.cc
+++ b/net/spdy/chromium/header_coalescer_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/spdy/chromium/header_coalescer.h"
 
+#include <string>
 #include <vector>
 
 #include "net/log/test_net_log.h"
diff --git a/net/spdy/chromium/http2_push_promise_index.cc b/net/spdy/chromium/http2_push_promise_index.cc
index f0f280c..b8ed939 100644
--- a/net/spdy/chromium/http2_push_promise_index.cc
+++ b/net/spdy/chromium/http2_push_promise_index.cc
@@ -3,11 +3,12 @@
 // found in the LICENSE file.
 
 #include "net/spdy/chromium/http2_push_promise_index.h"
-#include "base/trace_event/memory_usage_estimator.h"
 
 #include <algorithm>
 #include <utility>
 
+#include "base/trace_event/memory_usage_estimator.h"
+
 namespace net {
 
 Http2PushPromiseIndex::Http2PushPromiseIndex() = default;
diff --git a/net/spdy/chromium/http2_push_promise_index_test.cc b/net/spdy/chromium/http2_push_promise_index_test.cc
index 39d9d83..3f5706fa 100644
--- a/net/spdy/chromium/http2_push_promise_index_test.cc
+++ b/net/spdy/chromium/http2_push_promise_index_test.cc
@@ -28,7 +28,7 @@
 class TestDelegate : public Http2PushPromiseIndex::Delegate {
  public:
   TestDelegate() = delete;
-  TestDelegate(const SpdySessionKey& key) : key_(key) {}
+  explicit TestDelegate(const SpdySessionKey& key) : key_(key) {}
   ~TestDelegate() override {}
 
   bool ValidatePushedStream(SpdyStreamId stream_id,
@@ -417,7 +417,7 @@
   // (which then must be |entry2|).
   std::tie(std::ignore, success) = entries.insert(entry2);
   EXPECT_FALSE(success);
-};
+}
 
 TEST(Http2PushPromiseIndexCompareByUrlTest, LookupByURL) {
   const GURL url1("https://example.com:1");
@@ -463,7 +463,7 @@
   EXPECT_TRUE(
       entries.lower_bound(Http2PushPromiseIndexPeer::UnclaimedPushedStream{
           url2, nullptr, kNoPushedStreamFound}) == entries.find(entry2));
-};
+}
 
 }  // namespace test
 }  // namespace net
diff --git a/net/spdy/chromium/multiplexed_http_stream.cc b/net/spdy/chromium/multiplexed_http_stream.cc
index 028b263..f25fa9a 100644
--- a/net/spdy/chromium/multiplexed_http_stream.cc
+++ b/net/spdy/chromium/multiplexed_http_stream.cc
@@ -4,6 +4,8 @@
 
 #include "net/spdy/chromium/multiplexed_http_stream.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "net/http/http_raw_request_headers.h"
 #include "net/third_party/spdy/core/spdy_header_block.h"
diff --git a/net/spdy/chromium/spdy_log_util.cc b/net/spdy/chromium/spdy_log_util.cc
index b1d20b7..2ba44f301 100644
--- a/net/spdy/chromium/spdy_log_util.cc
+++ b/net/spdy/chromium/spdy_log_util.cc
@@ -4,6 +4,8 @@
 
 #include "net/spdy/chromium/spdy_log_util.h"
 
+#include <utility>
+
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "net/http/http_log_util.h"
diff --git a/net/spdy/chromium/spdy_proxy_client_socket.cc b/net/spdy/chromium/spdy_proxy_client_socket.cc
index 6a6dcce..a7cbd58 100644
--- a/net/spdy/chromium/spdy_proxy_client_socket.cc
+++ b/net/spdy/chromium/spdy_proxy_client_socket.cc
@@ -268,12 +268,6 @@
   return spdy_stream_->GetLocalAddress(address);
 }
 
-void SpdyProxyClientSocket::LogBlockedTunnelResponse() const {
-  ProxyClientSocket::LogBlockedTunnelResponse(
-      response_.headers->response_code(),
-      /* is_https_proxy = */ true);
-}
-
 void SpdyProxyClientSocket::RunCallback(CompletionOnceCallback callback,
                                         int result) const {
   std::move(callback).Run(result);
@@ -406,10 +400,8 @@
     case 302:  // Found / Moved Temporarily
       // Try to return a sanitized response so we can follow auth redirects.
       // If we can't, fail the tunnel connection.
-      if (!SanitizeProxyRedirect(&response_)) {
-        LogBlockedTunnelResponse();
+      if (!SanitizeProxyRedirect(&response_))
         return ERR_TUNNEL_CONNECTION_FAILED;
-      }
 
       redirect_has_load_timing_info_ =
           spdy_stream_->GetLoadTimingInfo(&redirect_load_timing_info_);
@@ -420,16 +412,13 @@
 
     case 407:  // Proxy Authentication Required
       next_state_ = STATE_OPEN;
-      if (!SanitizeProxyAuth(&response_)) {
-        LogBlockedTunnelResponse();
+      if (!SanitizeProxyAuth(&response_))
         return ERR_TUNNEL_CONNECTION_FAILED;
-      }
       return HandleProxyAuthChallenge(auth_.get(), &response_, net_log_);
 
     default:
       // Ignore response to avoid letting the proxy impersonate the target
       // server.  (See http://crbug.com/137891.)
-      LogBlockedTunnelResponse();
       return ERR_TUNNEL_CONNECTION_FAILED;
   }
 }
diff --git a/net/spdy/chromium/spdy_proxy_client_socket.h b/net/spdy/chromium/spdy_proxy_client_socket.h
index 2ade4b9a..e05f652 100644
--- a/net/spdy/chromium/spdy_proxy_client_socket.h
+++ b/net/spdy/chromium/spdy_proxy_client_socket.h
@@ -116,8 +116,6 @@
     STATE_CLOSED
   };
 
-  void LogBlockedTunnelResponse() const;
-
   // Calls |callback.Run(result)|. Used to run a callback posted to the
   // message loop.
   void RunCallback(CompletionOnceCallback callback, int result) const;
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index 267da7c..9bf6a8e 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <limits>
 #include <map>
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -1449,21 +1450,21 @@
   // 206 Partial Content and 416 Requested Range Not Satisfiable are range
   // responses.
   if (status_it->second == "206" || status_it->second == "416") {
-    SpdyHeaderBlock::const_iterator client_request_range_it =
-        stream_it->second->request_headers().find("range");
-    if (client_request_range_it == stream_it->second->request_headers().end()) {
+    std::string client_request_range;
+    if (!request_info.extra_headers.GetHeader(HttpRequestHeaders::kRange,
+                                              &client_request_range)) {
       // Client initiated request is not a range request.
       // TODO(https://crbug.com/831536): Add histogram.
       return false;
     }
-    std::string pushed_request_range;
-    if (!request_info.extra_headers.GetHeader(HttpRequestHeaders::kRange,
-                                              &pushed_request_range)) {
+    SpdyHeaderBlock::const_iterator pushed_request_range_it =
+        stream_it->second->request_headers().find("range");
+    if (pushed_request_range_it == stream_it->second->request_headers().end()) {
       // Pushed request is not a range request.
       // TODO(https://crbug.com/831536): Add histogram.
       return false;
     }
-    if (client_request_range_it->second != pushed_request_range) {
+    if (client_request_range != pushed_request_range_it->second) {
       // Client and pushed request ranges do not match.
       // TODO(https://crbug.com/831536): Add histogram.
       return false;
diff --git a/net/spdy/chromium/spdy_session_unittest.cc b/net/spdy/chromium/spdy_session_unittest.cc
index 96b77c3..e138343 100644
--- a/net/spdy/chromium/spdy_session_unittest.cc
+++ b/net/spdy/chromium/spdy_session_unittest.cc
@@ -5,6 +5,7 @@
 #include "net/spdy/chromium/spdy_session.h"
 
 #include <algorithm>
+#include <string>
 #include <utility>
 
 #include "base/base64.h"
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index be500ae..ec20831 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -34,6 +34,8 @@
     "debug_recording.h",
     "delay_buffer.cc",
     "delay_buffer.h",
+    "device_notifier.cc",
+    "device_notifier.h",
     "group_coordinator.cc",
     "group_coordinator.h",
     "group_member.h",
@@ -81,12 +83,14 @@
   sources = [
     "debug_recording_unittest.cc",
     "delay_buffer_unittest.cc",
+    "device_notifier_unittest.cc",
     "group_coordinator_unittest.cc",
     "input_stream_unittest.cc",
     "local_muter_unittest.cc",
     "loopback_stream_unittest.cc",
     "output_controller_unittest.cc",
     "output_stream_unittest.cc",
+    "public/cpp/input_ipc_unittest.cc",
     "snooper_node_unittest.cc",
     "stream_factory_unittest.cc",
     "sync_reader_unittest.cc",
diff --git a/services/audio/device_notifier.cc b/services/audio/device_notifier.cc
new file mode 100644
index 0000000..4f07f11
--- /dev/null
+++ b/services/audio/device_notifier.cc
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/device_notifier.h"
+
+#include <utility>
+
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+
+namespace audio {
+
+DeviceNotifier::DeviceNotifier()
+    : task_runner_(base::SequencedTaskRunnerHandle::Get()),
+      weak_factory_(this) {}
+
+DeviceNotifier::~DeviceNotifier() {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this);
+}
+
+void DeviceNotifier::Bind(
+    mojom::DeviceNotifierRequest request,
+    std::unique_ptr<service_manager::ServiceContextRef> context_ref) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  bindings_.AddBinding(this, std::move(request), std::move(context_ref));
+  base::SystemMonitor::Get()->AddDevicesChangedObserver(this);
+}
+
+void DeviceNotifier::RegisterListener(mojom::DeviceListenerPtr listener) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  int listener_id = next_listener_id_++;
+  listener.set_connection_error_handler(
+      base::BindRepeating(&DeviceNotifier::RemoveListener,
+                          weak_factory_.GetWeakPtr(), listener_id));
+  listeners_[listener_id] = std::move(listener);
+}
+
+void DeviceNotifier::OnDevicesChanged(
+    base::SystemMonitor::DeviceType device_type) {
+  if (device_type != base::SystemMonitor::DEVTYPE_AUDIO)
+    return;
+
+  task_runner_->PostTask(FROM_HERE,
+                         base::BindRepeating(&DeviceNotifier::UpdateListeners,
+                                             weak_factory_.GetWeakPtr()));
+}
+
+void DeviceNotifier::UpdateListeners() {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  for (const auto& listener : listeners_)
+    listener.second->DevicesChanged();
+}
+
+void DeviceNotifier::RemoveListener(int listener_id) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  listeners_.erase(listener_id);
+}
+
+}  // namespace audio
diff --git a/services/audio/device_notifier.h b/services/audio/device_notifier.h
new file mode 100644
index 0000000..e61aaac
--- /dev/null
+++ b/services/audio/device_notifier.h
@@ -0,0 +1,59 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_AUDIO_DEVICE_NOTIFIER_H_
+#define SERVICES_AUDIO_DEVICE_NOTIFIER_H_
+
+#include <memory>
+
+#include "base/containers/flat_map.h"
+#include "base/system_monitor/system_monitor.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/audio/public/mojom/device_notifications.mojom.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace service_manager {
+class ServiceContextRef;
+}
+
+namespace audio {
+
+// This class publishes notifications about changes in the audio devices
+// to registered listeners.
+class DeviceNotifier final : public base::SystemMonitor::DevicesChangedObserver,
+                             public mojom::DeviceNotifier {
+ public:
+  DeviceNotifier();
+  ~DeviceNotifier() final;
+
+  void Bind(mojom::DeviceNotifierRequest request,
+            std::unique_ptr<service_manager::ServiceContextRef> context_ref);
+
+  // mojom::DeviceNotifier implementation.
+  void RegisterListener(mojom::DeviceListenerPtr listener) final;
+
+  // base::SystemMonitor::DevicesChangedObserver implementation;
+  void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) final;
+
+ private:
+  void UpdateListeners();
+  void RemoveListener(int listener_id);
+
+  int next_listener_id_ = 0;
+  base::flat_map<int, mojom::DeviceListenerPtr> listeners_;
+  mojo::BindingSet<mojom::DeviceNotifier,
+                   std::unique_ptr<service_manager::ServiceContextRef>>
+      bindings_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  base::WeakPtrFactory<DeviceNotifier> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceNotifier);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_DEVICE_NOTIFIER_H_
diff --git a/services/audio/device_notifier_unittest.cc b/services/audio/device_notifier_unittest.cc
new file mode 100644
index 0000000..bedb7ae
--- /dev/null
+++ b/services/audio/device_notifier_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/device_notifier.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/system_monitor/system_monitor.h"
+#include "base/test/scoped_task_environment.h"
+#include "services/audio/public/mojom/device_notifications.mojom.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace audio {
+
+namespace {
+
+class MockDeviceListener : public mojom::DeviceListener {
+ public:
+  explicit MockDeviceListener(audio::mojom::DeviceListenerRequest request)
+      : binding_(this, std::move(request)) {}
+  MOCK_METHOD0(DevicesChanged, void());
+
+ private:
+  mojo::Binding<audio::mojom::DeviceListener> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockDeviceListener);
+};
+
+}  // namespace
+
+class DeviceNotifierTest : public ::testing::Test {
+ public:
+  DeviceNotifierTest()
+      : system_monitor_(std::make_unique<base::SystemMonitor>()),
+        service_ref_factory_(
+            base::BindRepeating(&DeviceNotifierTest::OnNoServiceRefs,
+                                base::Unretained(this))) {}
+
+ protected:
+  MOCK_METHOD0(OnNoServiceRefs, void());
+
+  void CreateDeviceNotifier() {
+    device_notifier_ = std::make_unique<DeviceNotifier>();
+    device_notifier_->Bind(mojo::MakeRequest(&device_notifier_ptr_),
+                           service_ref_factory_.CreateRef());
+    EXPECT_FALSE(service_ref_factory_.HasNoRefs());
+  }
+
+  void DestroyDeviceNotifier() {
+    device_notifier_ptr_.reset();
+    scoped_task_environment_.RunUntilIdle();
+    EXPECT_TRUE(service_ref_factory_.HasNoRefs());
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  mojom::DeviceNotifierPtr device_notifier_ptr_;
+
+ private:
+  std::unique_ptr<base::SystemMonitor> system_monitor_;
+  std::unique_ptr<DeviceNotifier> device_notifier_;
+  service_manager::ServiceContextRefFactory service_ref_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceNotifierTest);
+};
+
+TEST_F(DeviceNotifierTest, DeviceNotifierNotifies) {
+  EXPECT_CALL(*this, OnNoServiceRefs());
+  CreateDeviceNotifier();
+
+  mojom::DeviceListenerPtr device_listener_ptr;
+  MockDeviceListener listener(mojo::MakeRequest(&device_listener_ptr));
+
+  // Simulate audio-device event, but no callback should be invoked before the
+  // listener is registered.
+  EXPECT_CALL(listener, DevicesChanged()).Times(0);
+  base::SystemMonitor::Get()->ProcessDevicesChanged(
+      base::SystemMonitor::DEVTYPE_AUDIO);
+  scoped_task_environment_.RunUntilIdle();
+
+  // Register the listener and simulate an audio-device event.
+  device_notifier_ptr_->RegisterListener(std::move(device_listener_ptr));
+  EXPECT_CALL(listener, DevicesChanged());
+  base::SystemMonitor::Get()->ProcessDevicesChanged(
+      base::SystemMonitor::DEVTYPE_AUDIO);
+  scoped_task_environment_.RunUntilIdle();
+
+  // Simulate a video-device event, which should be ignored.
+  EXPECT_CALL(listener, DevicesChanged()).Times(0);
+  base::SystemMonitor::Get()->ProcessDevicesChanged(
+      base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
+  scoped_task_environment_.RunUntilIdle();
+
+  DestroyDeviceNotifier();
+}
+
+}  // namespace audio
diff --git a/services/audio/manifest.json b/services/audio/manifest.json
index 4f6637e2..beb981b 100644
--- a/services/audio/manifest.json
+++ b/services/audio/manifest.json
@@ -7,7 +7,8 @@
       "provides": {
         "info": [ "audio::mojom::SystemInfo" ],
         "debug_recording": [ "audio::mojom::DebugRecording" ],
-        "stream_factory": [ "audio::mojom::StreamFactory" ]
+        "stream_factory": [ "audio::mojom::StreamFactory" ],
+        "device_notifier": [ "audio::mojom::DeviceNotifier" ]
       },
       "requires": {
         "service_manager": [ "service_manager:all_users" ]
diff --git a/services/audio/public/cpp/BUILD.gn b/services/audio/public/cpp/BUILD.gn
index ea40a26..dd06c3e 100644
--- a/services/audio/public/cpp/BUILD.gn
+++ b/services/audio/public/cpp/BUILD.gn
@@ -12,6 +12,10 @@
     "debug_recording_session.h",
     "debug_recording_session_factory.cc",
     "debug_recording_session_factory.h",
+    "device_factory.cc",
+    "device_factory.h",
+    "input_ipc.cc",
+    "input_ipc.h",
   ]
 
   public_deps = [
diff --git a/services/audio/public/cpp/device_factory.cc b/services/audio/public/cpp/device_factory.cc
new file mode 100644
index 0000000..e92fb2f
--- /dev/null
+++ b/services/audio/public/cpp/device_factory.cc
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/public/cpp/device_factory.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "services/audio/public/cpp/input_ipc.h"
+
+namespace audio {
+
+scoped_refptr<media::AudioCapturerSource> CreateInputDevice(
+    std::unique_ptr<service_manager::Connector> connector,
+    const std::string& device_id,
+    media::mojom::AudioLogPtr log) {
+  std::unique_ptr<media::AudioInputIPC> ipc = std::make_unique<InputIPC>(
+      std::move(connector), device_id, std::move(log));
+
+  return base::MakeRefCounted<media::AudioInputDevice>(std::move(ipc));
+}
+
+scoped_refptr<media::AudioCapturerSource> CreateInputDevice(
+    std::unique_ptr<service_manager::Connector> connector,
+    const std::string& device_id) {
+  std::unique_ptr<media::AudioInputIPC> ipc =
+      std::make_unique<InputIPC>(std::move(connector), device_id, nullptr);
+
+  return base::MakeRefCounted<media::AudioInputDevice>(std::move(ipc));
+}
+
+}  // namespace audio
diff --git a/services/audio/public/cpp/device_factory.h b/services/audio/public/cpp/device_factory.h
new file mode 100644
index 0000000..a1b2d12
--- /dev/null
+++ b/services/audio/public/cpp/device_factory.h
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_AUDIO_PUBLIC_CPP_DEVICE_FACTORY_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_DEVICE_FACTORY_H_
+
+#include "media/audio/audio_input_device.h"
+
+#include "services/audio/public/mojom/stream_factory.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace audio {
+
+scoped_refptr<media::AudioCapturerSource> CreateInputDevice(
+    std::unique_ptr<service_manager::Connector> connector,
+    const std::string& device_id);
+
+scoped_refptr<media::AudioCapturerSource> CreateInputDevice(
+    std::unique_ptr<service_manager::Connector> connector,
+    const std::string& device_id,
+    media::mojom::AudioLogPtr);
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_PUBLIC_CPP_DEVICE_FACTORY_H_
diff --git a/services/audio/public/cpp/fake_stream_factory.h b/services/audio/public/cpp/fake_stream_factory.h
index 38d06e5c..811881d 100644
--- a/services/audio/public/cpp/fake_stream_factory.h
+++ b/services/audio/public/cpp/fake_stream_factory.h
@@ -24,6 +24,8 @@
     return ptr;
   }
 
+  void CloseBinding() { binding_.Close(); }
+
   void CreateInputStream(media::mojom::AudioInputStreamRequest stream_request,
                          media::mojom::AudioInputStreamClientPtr client,
                          media::mojom::AudioInputStreamObserverPtr observer,
diff --git a/services/audio/public/cpp/input_ipc.cc b/services/audio/public/cpp/input_ipc.cc
new file mode 100644
index 0000000..fda6852
--- /dev/null
+++ b/services/audio/public/cpp/input_ipc.cc
@@ -0,0 +1,123 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/public/cpp/input_ipc.h"
+
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/audio/public/mojom/constants.mojom.h"
+
+namespace audio {
+
+InputIPC::InputIPC(std::unique_ptr<service_manager::Connector> connector,
+                   const std::string& device_id,
+                   media::mojom::AudioLogPtr log)
+    : stream_(),
+      stream_client_binding_(this),
+      device_id_(std::move(device_id)),
+      stream_factory_(),
+      stream_factory_info_(),
+      log_(std::move(log)),
+      weak_factory_(this) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+  DCHECK(connector);
+
+  connector->BindInterface(audio::mojom::kServiceName,
+                           mojo::MakeRequest(&stream_factory_info_));
+}
+
+InputIPC::~InputIPC() = default;
+
+void InputIPC::CreateStream(media::AudioInputIPCDelegate* delegate,
+                            const media::AudioParameters& params,
+                            bool automatic_gain_control,
+                            uint32_t total_segments) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(delegate);
+  DCHECK(!delegate_);
+
+  delegate_ = delegate;
+
+  if (!stream_factory_.is_bound())
+    stream_factory_.Bind(std::move(stream_factory_info_));
+
+  media::mojom::AudioInputStreamRequest stream_request =
+      mojo::MakeRequest(&stream_);
+
+  media::mojom::AudioInputStreamClientPtr client;
+  stream_client_binding_.Bind(mojo::MakeRequest(&client));
+
+  // Unretained is safe because we own the binding.
+  stream_client_binding_.set_connection_error_handler(
+      base::BindOnce(&InputIPC::OnError, base::Unretained(this)));
+
+  // For now we don't care about key presses, so we pass a invalid buffer.
+  mojo::ScopedSharedBufferHandle invalid_key_press_count_buffer;
+
+  stream_factory_->CreateInputStream(
+      std::move(stream_request), std::move(client), nullptr,
+      log_ ? std::move(log_) : nullptr, device_id_, params, total_segments,
+      automatic_gain_control, std::move(invalid_key_press_count_buffer),
+      base::BindOnce(&InputIPC::StreamCreated, weak_factory_.GetWeakPtr()));
+}
+
+void InputIPC::StreamCreated(media::mojom::AudioDataPipePtr data_pipe,
+                             bool initially_muted) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(delegate_);
+
+  if (data_pipe.is_null()) {
+    OnError();
+    return;
+  }
+
+  base::PlatformFile socket_handle;
+  auto result =
+      mojo::UnwrapPlatformFile(std::move(data_pipe->socket), &socket_handle);
+  DCHECK_EQ(result, MOJO_RESULT_OK);
+  base::SharedMemoryHandle memory_handle;
+  mojo::UnwrappedSharedMemoryHandleProtection protection;
+  result = mojo::UnwrapSharedMemoryHandle(std::move(data_pipe->shared_memory),
+                                          &memory_handle, nullptr, &protection);
+  DCHECK_EQ(result, MOJO_RESULT_OK);
+  DCHECK_EQ(protection, mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
+
+  delegate_->OnStreamCreated(memory_handle, socket_handle, initially_muted);
+}
+
+void InputIPC::RecordStream() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(stream_.is_bound());
+  stream_->Record();
+}
+
+void InputIPC::SetVolume(double volume) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(stream_.is_bound());
+  stream_->SetVolume(volume);
+}
+
+void InputIPC::CloseStream() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  delegate_ = nullptr;
+  if (stream_client_binding_.is_bound())
+    stream_client_binding_.Close();
+  stream_.reset();
+}
+
+void InputIPC::OnError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(delegate_);
+  delegate_->OnError();
+}
+
+void InputIPC::OnMutedStateChanged(bool is_muted) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(delegate_);
+  delegate_->OnMuted(is_muted);
+}
+
+}  // namespace audio
diff --git a/services/audio/public/cpp/input_ipc.h b/services/audio/public/cpp/input_ipc.h
new file mode 100644
index 0000000..06fb0370
--- /dev/null
+++ b/services/audio/public/cpp/input_ipc.h
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_AUDIO_PUBLIC_CPP_INPUT_IPC_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_INPUT_IPC_H_
+
+#include <string>
+
+#include "base/callback_helpers.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/time/time.h"
+#include "media/audio/audio_input_ipc.h"
+#include "media/mojo/interfaces/audio_input_stream.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/audio/public/mojom/stream_factory.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace audio {
+
+// InputIPC is a client-side class for handling creation,
+// initialization and control of an input stream. May only be used on a single
+// thread.
+class InputIPC : public media::AudioInputIPC,
+                 public media::mojom::AudioInputStreamClient {
+ public:
+  explicit InputIPC(std::unique_ptr<service_manager::Connector> connector,
+                    const std::string& device_id,
+                    media::mojom::AudioLogPtr log);
+  ~InputIPC() override;
+
+  // AudioInputIPC implementation
+  void CreateStream(media::AudioInputIPCDelegate* delegate,
+                    const media::AudioParameters& params,
+                    bool automatic_gain_control,
+                    uint32_t total_segments) override;
+  void RecordStream() override;
+  void SetVolume(double volume) override;
+  void CloseStream() override;
+
+ private:
+  // AudioInputStreamClient implementation.
+  void OnError() override;
+  void OnMutedStateChanged(bool is_muted) override;
+
+  void StreamCreated(media::mojom::AudioDataPipePtr data_pipe, bool is_muted);
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  media::mojom::AudioInputStreamPtr stream_;
+  mojo::Binding<AudioInputStreamClient> stream_client_binding_;
+  media::AudioInputIPCDelegate* delegate_ = nullptr;
+
+  const std::string& device_id_;
+
+  // stream_factory_info_ is bound in the constructor, and later used to
+  // bind stream_factory_. This is done because the constructor may be called
+  // from a different thread than the other functions.
+  audio::mojom::StreamFactoryPtr stream_factory_;
+  audio::mojom::StreamFactoryPtrInfo stream_factory_info_;
+
+  media::mojom::AudioLogPtr log_;
+
+  base::WeakPtrFactory<InputIPC> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(InputIPC);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_PUBLIC_CPP_INPUT_IPC_H_
diff --git a/services/audio/public/cpp/input_ipc_unittest.cc b/services/audio/public/cpp/input_ipc_unittest.cc
new file mode 100644
index 0000000..9137b1b
--- /dev/null
+++ b/services/audio/public/cpp/input_ipc_unittest.cc
@@ -0,0 +1,247 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/audio/public/cpp/input_ipc.h"
+
+#include "base/test/scoped_task_environment.h"
+#include "media/mojo/interfaces/audio_data_pipe.mojom.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/audio/public/cpp/device_factory.h"
+#include "services/audio/public/mojom/constants.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::StrictMock;
+
+namespace audio {
+
+namespace {
+
+const std::string& kDeviceId = "1234";
+const size_t kShMemSize = 456;
+const double kNewVolume = 0.271828;
+
+class MockStream : public media::mojom::AudioInputStream {
+ public:
+  MOCK_METHOD0(Record, void());
+  MOCK_METHOD1(SetVolume, void(double));
+};
+
+class FakeStreamFactory : public audio::mojom::StreamFactory {
+ public:
+  FakeStreamFactory() : binding_(this), stream_(), stream_binding_(&stream_) {}
+  ~FakeStreamFactory() override = default;
+  void CreateInputStream(media::mojom::AudioInputStreamRequest stream_request,
+                         media::mojom::AudioInputStreamClientPtr client,
+                         media::mojom::AudioInputStreamObserverPtr observer,
+                         media::mojom::AudioLogPtr log,
+                         const std::string& device_id,
+                         const media::AudioParameters& params,
+                         uint32_t shared_memory_count,
+                         bool enable_agc,
+                         mojo::ScopedSharedBufferHandle key_press_count_buffer,
+                         CreateInputStreamCallback created_callback) {
+    if (should_fail_) {
+      std::move(created_callback).Run(nullptr, initially_muted_);
+      return;
+    }
+
+    // Keep the client alive to avoid binding errors.
+    client_ = std::move(client);
+
+    if (stream_binding_.is_bound())
+      stream_binding_.Unbind();
+
+    stream_binding_.Bind(std::move(stream_request));
+
+    base::SyncSocket socket1, socket2;
+    base::SyncSocket::CreatePair(&socket1, &socket2);
+    auto h = mojo::SharedBufferHandle::Create(kShMemSize);
+    std::move(created_callback)
+        .Run({base::in_place,
+              h->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
+              mojo::WrapPlatformFile(socket1.Release())},
+             initially_muted_);
+  }
+
+  MOCK_METHOD7(CreateOutputStream,
+               void(media::mojom::AudioOutputStreamRequest stream_request,
+                    media::mojom::AudioOutputStreamObserverAssociatedPtrInfo
+                        observer_info,
+                    media::mojom::AudioLogPtr log,
+                    const std::string& output_device_id,
+                    const media::AudioParameters& params,
+                    const base::UnguessableToken& group_id,
+                    CreateOutputStreamCallback created_callback));
+
+  MOCK_METHOD2(BindMuter,
+               void(mojom::LocalMuterAssociatedRequest request,
+                    const base::UnguessableToken& group_id));
+
+  void Bind(mojo::ScopedMessagePipeHandle handle) {
+    binding_.Bind(audio::mojom::StreamFactoryRequest(std::move(handle)));
+  }
+
+  mojo::Binding<audio::mojom::StreamFactory> binding_;
+  StrictMock<MockStream> stream_;
+  media::mojom::AudioInputStreamClientPtr client_;
+  mojo::Binding<media::mojom::AudioInputStream> stream_binding_;
+  bool initially_muted_ = true;
+  bool should_fail_ = false;
+};
+
+class MockDelegate : public media::AudioInputIPCDelegate {
+ public:
+  MockDelegate() {}
+  ~MockDelegate() override {}
+
+  void OnStreamCreated(base::SharedMemoryHandle mem_handle,
+                       base::SyncSocket::Handle socket_handle,
+                       bool initially_muted) override {
+    base::SharedMemory sh_mem(
+        mem_handle, /*read_only*/ true);  // Releases the shared memory handle.
+    base::SyncSocket socket(socket_handle);  // Releases the socket descriptor.
+    GotOnStreamCreated(initially_muted);
+  }
+
+  MOCK_METHOD1(GotOnStreamCreated, void(bool initially_muted));
+  MOCK_METHOD0(OnError, void());
+  MOCK_METHOD1(OnMuted, void(bool));
+  MOCK_METHOD0(OnIPCClosed, void());
+};
+
+class InputIPCTest : public ::testing::Test {
+ public:
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+  std::unique_ptr<audio::InputIPC> ipc;
+  const media::AudioParameters audioParameters =
+      media::AudioParameters(media::AudioParameters::AUDIO_PCM_LINEAR,
+                             media::CHANNEL_LAYOUT_STEREO,
+                             16000,
+                             1600);
+
+ protected:
+  InputIPCTest()
+      : scoped_task_environment(
+            base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT,
+            base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
+  std::unique_ptr<StrictMock<FakeStreamFactory>> factory_;
+
+  void SetUp() override {
+    service_manager::mojom::ConnectorRequest request;
+    std::unique_ptr<service_manager::Connector> connector =
+        service_manager::Connector::Create(&request);
+
+    factory_ = std::make_unique<StrictMock<FakeStreamFactory>>();
+    {
+      service_manager::Connector::TestApi test_api(connector.get());
+
+      test_api.OverrideBinderForTesting(
+          service_manager::Identity(audio::mojom::kServiceName),
+          audio::mojom::StreamFactory::Name_,
+          base::BindRepeating(&FakeStreamFactory::Bind,
+                              base::Unretained(factory_.get())));
+    }
+    ipc = std::make_unique<InputIPC>(std::move(connector), kDeviceId, nullptr);
+  }
+};
+
+}  // namespace
+
+TEST_F(InputIPCTest, CreateStreamPropagates) {
+  StrictMock<MockDelegate> delegate;
+  EXPECT_CALL(delegate, GotOnStreamCreated(_));
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+}
+
+TEST_F(InputIPCTest, CreateStreamPropagatesInitiallyMuted) {
+  StrictMock<MockDelegate> delegate;
+
+  factory_->initially_muted_ = true;
+  EXPECT_CALL(delegate, GotOnStreamCreated(true));
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+  ipc->CloseStream();
+  scoped_task_environment.RunUntilIdle();
+
+  factory_->initially_muted_ = false;
+  EXPECT_CALL(delegate, GotOnStreamCreated(false));
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+  ipc->CloseStream();
+  scoped_task_environment.RunUntilIdle();
+}
+
+TEST_F(InputIPCTest, MutedStateChangesPropagates) {
+  StrictMock<MockDelegate> delegate;
+
+  EXPECT_CALL(delegate, GotOnStreamCreated(_));
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+
+  EXPECT_CALL(delegate, OnMuted(true));
+  factory_->client_->OnMutedStateChanged(true);
+  scoped_task_environment.RunUntilIdle();
+
+  EXPECT_CALL(delegate, OnMuted(false));
+  factory_->client_->OnMutedStateChanged(false);
+  scoped_task_environment.RunUntilIdle();
+}
+
+TEST_F(InputIPCTest, Record_Records) {
+  StrictMock<MockDelegate> delegate;
+  EXPECT_CALL(delegate, GotOnStreamCreated(_));
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+
+  EXPECT_CALL(factory_->stream_, Record());
+  ipc->RecordStream();
+  scoped_task_environment.RunUntilIdle();
+}
+
+TEST_F(InputIPCTest, IsReusable) {
+  for (int i = 0; i < 5; i++) {
+    StrictMock<MockDelegate> delegate;
+    EXPECT_CALL(delegate, GotOnStreamCreated(_));
+    ipc->CreateStream(&delegate, audioParameters, false, 0);
+    scoped_task_environment.RunUntilIdle();
+
+    ipc->CloseStream();
+    scoped_task_environment.RunUntilIdle();
+
+    testing::Mock::VerifyAndClearExpectations(&delegate);
+  }
+}
+
+TEST_F(InputIPCTest, SetVolume_SetsVolume) {
+  StrictMock<MockDelegate> delegate;
+  EXPECT_CALL(delegate, GotOnStreamCreated(_));
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+
+  EXPECT_CALL(factory_->stream_, SetVolume(kNewVolume));
+  ipc->SetVolume(kNewVolume);
+  scoped_task_environment.RunUntilIdle();
+}
+
+TEST_F(InputIPCTest, FailedStreamCreationNullCallback) {
+  StrictMock<MockDelegate> delegate;
+  EXPECT_CALL(delegate, OnError()).Times(2);
+  factory_->should_fail_ = true;
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+}
+
+TEST_F(InputIPCTest, FailedStreamCreationDestuctedFactory) {
+  StrictMock<MockDelegate> delegate;
+  EXPECT_CALL(delegate, OnError());
+  factory_ = nullptr;
+  ipc->CreateStream(&delegate, audioParameters, false, 0);
+  scoped_task_environment.RunUntilIdle();
+}
+
+}  // namespace audio
diff --git a/services/audio/public/mojom/BUILD.gn b/services/audio/public/mojom/BUILD.gn
index 2929963..29f89d2 100644
--- a/services/audio/public/mojom/BUILD.gn
+++ b/services/audio/public/mojom/BUILD.gn
@@ -8,6 +8,7 @@
   sources = [
     "audio_device_description.mojom",
     "debug_recording.mojom",
+    "device_notifications.mojom",
     "stream_factory.mojom",
     "system_info.mojom",
   ]
diff --git a/services/audio/public/mojom/device_notifications.mojom b/services/audio/public/mojom/device_notifications.mojom
new file mode 100644
index 0000000..f3d5c75
--- /dev/null
+++ b/services/audio/public/mojom/device_notifications.mojom
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module audio.mojom;
+
+// This interface is implemented by clients of the audio service (e.g., the
+// browser process) to register listeners of audio-device events.
+interface DeviceListener {
+  DevicesChanged();
+};
+
+// This interface is exposed by the audio service to allow trusted clients
+// (e.g., the browser process) to subscribe to device-change events.
+interface DeviceNotifier {
+  // Registers a listener. Closing the pipe removes the subscription.
+  RegisterListener(DeviceListener listener);
+};
diff --git a/services/audio/service.cc b/services/audio/service.cc
index 9684cc0..b00498e 100644
--- a/services/audio/service.cc
+++ b/services/audio/service.cc
@@ -9,9 +9,11 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
+#include "base/system_monitor/system_monitor.h"
 #include "build/build_config.h"
 #include "media/audio/audio_manager.h"
 #include "services/audio/debug_recording.h"
+#include "services/audio/device_notifier.h"
 #include "services/audio/system_info.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_context_ref.h"
@@ -19,9 +21,11 @@
 namespace audio {
 
 Service::Service(std::unique_ptr<AudioManagerAccessor> audio_manager_accessor,
-                 base::TimeDelta quit_timeout)
+                 base::TimeDelta quit_timeout,
+                 bool device_notifications_enabled)
     : quit_timeout_(quit_timeout),
-      audio_manager_accessor_(std::move(audio_manager_accessor)) {
+      audio_manager_accessor_(std::move(audio_manager_accessor)),
+      device_notifications_enabled_(device_notifications_enabled) {
   DCHECK(audio_manager_accessor_);
 }
 
@@ -41,6 +45,10 @@
       &Service::BindDebugRecordingRequest, base::Unretained(this)));
   registry_.AddInterface<mojom::StreamFactory>(base::BindRepeating(
       &Service::BindStreamFactoryRequest, base::Unretained(this)));
+  if (device_notifications_enabled_) {
+    registry_.AddInterface<mojom::DeviceNotifier>(base::BindRepeating(
+        &Service::BindDeviceNotifierRequest, base::Unretained(this)));
+  }
 }
 
 void Service::OnBindInterface(
@@ -100,6 +108,19 @@
   stream_factory_->Bind(std::move(request), ref_factory_->CreateRef());
 }
 
+void Service::BindDeviceNotifierRequest(mojom::DeviceNotifierRequest request) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(ref_factory_);
+  DCHECK(device_notifications_enabled_);
+  if (!system_monitor_) {
+    CHECK(!base::SystemMonitor::Get());
+    system_monitor_ = std::make_unique<base::SystemMonitor>();
+  }
+  if (!device_notifier_)
+    device_notifier_ = std::make_unique<DeviceNotifier>();
+  device_notifier_->Bind(std::move(request), ref_factory_->CreateRef());
+}
+
 void Service::MaybeRequestQuitDelayed() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (quit_timeout_ <= base::TimeDelta())
diff --git a/services/audio/service.h b/services/audio/service.h
index 9fdc3abb..9c52862 100644
--- a/services/audio/service.h
+++ b/services/audio/service.h
@@ -14,12 +14,17 @@
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
 #include "services/audio/public/mojom/debug_recording.mojom.h"
+#include "services/audio/public/mojom/device_notifications.mojom.h"
 #include "services/audio/public/mojom/stream_factory.mojom.h"
 #include "services/audio/public/mojom/system_info.mojom.h"
 #include "services/audio/stream_factory.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 
+namespace base {
+class SystemMonitor;
+}
+
 namespace media {
 class AudioManager;
 }  // namespace media
@@ -30,6 +35,7 @@
 
 namespace audio {
 class DebugRecording;
+class DeviceNotifier;
 class SystemInfo;
 
 class Service : public service_manager::Service {
@@ -50,9 +56,12 @@
 
   // Service will attempt to quit if there are no connections to it within
   // |quit_timeout| interval. If |quit_timeout| is base::TimeDelta() the
-  // service never quits.
+  // service never quits. If |device_notifications_enabled| is true, the service
+  // will make available a DeviceNotifier object that allows clients to
+  // subscribe to notifications about device changes.
   Service(std::unique_ptr<AudioManagerAccessor> audio_manager_accessor,
-          base::TimeDelta quit_timeout);
+          base::TimeDelta quit_timeout,
+          bool device_notifications_enabled);
   ~Service() final;
 
   // service_manager::Service implementation.
@@ -68,6 +77,7 @@
   void BindSystemInfoRequest(mojom::SystemInfoRequest request);
   void BindDebugRecordingRequest(mojom::DebugRecordingRequest request);
   void BindStreamFactoryRequest(mojom::StreamFactoryRequest request);
+  void BindDeviceNotifierRequest(mojom::DeviceNotifierRequest request);
 
   void MaybeRequestQuitDelayed();
   void MaybeRequestQuit();
@@ -83,9 +93,12 @@
   std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
 
   std::unique_ptr<AudioManagerAccessor> audio_manager_accessor_;
+  const bool device_notifications_enabled_;
+  std::unique_ptr<base::SystemMonitor> system_monitor_;
   std::unique_ptr<SystemInfo> system_info_;
   std::unique_ptr<DebugRecording> debug_recording_;
   base::Optional<StreamFactory> stream_factory_;
+  std::unique_ptr<DeviceNotifier> device_notifier_;
 
   service_manager::BinderRegistry registry_;
 
diff --git a/services/audio/service_factory.cc b/services/audio/service_factory.cc
index 6c0475ef..91da2eda 100644
--- a/services/audio/service_factory.cc
+++ b/services/audio/service_factory.cc
@@ -4,6 +4,8 @@
 
 #include "services/audio/service_factory.h"
 
+#include <string>
+
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
@@ -40,14 +42,15 @@
     media::AudioManager* audio_manager) {
   return std::make_unique<Service>(
       std::make_unique<InProcessAudioManagerAccessor>(audio_manager),
-      base::TimeDelta() /* do not quit if all clients disconnected */);
+      base::TimeDelta() /* do not quit if all clients disconnected */,
+      false /* enable_device_notifications */);
 }
 
 std::unique_ptr<service_manager::Service> CreateStandaloneService() {
   return std::make_unique<Service>(
       std::make_unique<audio::OwningAudioManagerAccessor>(
           base::BindOnce(&media::AudioManager::Create)),
-      GetQuitTimeout());
+      GetQuitTimeout(), true /* enable_device_notifications */);
 }
 
 }  // namespace audio
diff --git a/services/audio/test/in_process_service_test.cc b/services/audio/test/in_process_service_test.cc
index 6bcf4e8e..27e0bf7 100644
--- a/services/audio/test/in_process_service_test.cc
+++ b/services/audio/test/in_process_service_test.cc
@@ -45,7 +45,7 @@
       service_context_ = std::make_unique<service_manager::ServiceContext>(
           std::make_unique<audio::Service>(
               std::make_unique<InProcessAudioManagerAccessor>(audio_manager_),
-              service_quit_timeout_),
+              service_quit_timeout_, false /* device_notifications_enabled */),
           std::move(request));
       service_context_->SetQuitClosure(base::BindRepeating(
           &AudioThreadContext::QuitOnAudioThread, base::Unretained(this)));
@@ -66,7 +66,7 @@
     virtual ~AudioThreadContext() {
       if (service_context_)
         service_context_->QuitNow();
-    };
+    }
 
     media::AudioManager* const audio_manager_;
     const base::TimeDelta service_quit_timeout_;
diff --git a/services/audio/test/service_lifetime_connector_test.cc b/services/audio/test/service_lifetime_connector_test.cc
index 6c08a68..2f67607 100644
--- a/services/audio/test/service_lifetime_connector_test.cc
+++ b/services/audio/test/service_lifetime_connector_test.cc
@@ -36,7 +36,7 @@
             false /*not using a separate audio thread*/));
     std::unique_ptr<Service> service_impl = std::make_unique<Service>(
         std::make_unique<InProcessAudioManagerAccessor>(audio_manager_.get()),
-        kQuitTimeout);
+        kQuitTimeout, false /* device_notifications_enabled */);
     service_ = service_impl.get();
     service_->SetQuitClosureForTesting(quit_request_.Get());
     connector_factory_ =
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 8545d73..fc40b1c 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -554,6 +554,11 @@
             net_log));
   }
 
+  if (network_context_params->transport_security_persister_path) {
+    builder->set_transport_security_persister_path(
+        *network_context_params->transport_security_persister_path);
+  }
+
   builder->set_data_enabled(network_context_params->enable_data_url_support);
 #if !BUILDFLAG(DISABLE_FILE_SUPPORT)
   builder->set_file_enabled(network_context_params->enable_file_url_support);
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index e85bbc5..b461e1e 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -646,6 +646,61 @@
                    ->GetSupportsSpdy(kSchemeHostPort));
 }
 
+// Test that TransportSecurity state is persisted (or not) as expected.
+TEST_F(NetworkContextTest, TransportSecurityStatePersisted) {
+  const char kDomain[] = "foo.test";
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath transport_security_persister_path = temp_dir.GetPath();
+  base::FilePath transport_security_persister_file_path =
+      transport_security_persister_path.AppendASCII("TransportSecurity");
+  EXPECT_FALSE(base::PathExists(transport_security_persister_file_path));
+
+  for (bool on_disk : {false, true}) {
+    // Create a NetworkContext.
+    mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+    if (on_disk) {
+      context_params->transport_security_persister_path =
+          transport_security_persister_path;
+    }
+    std::unique_ptr<NetworkContext> network_context =
+        CreateContextWithParams(std::move(context_params));
+
+    // Add an STS entry.
+    net::TransportSecurityState::STSState sts_state;
+    net::TransportSecurityState* state =
+        network_context->url_request_context()->transport_security_state();
+    EXPECT_FALSE(state->GetDynamicSTSState(kDomain, &sts_state));
+    state->AddHSTS(kDomain,
+                   base::Time::Now() + base::TimeDelta::FromSecondsD(1000),
+                   false /* include subdomains */);
+    EXPECT_TRUE(state->GetDynamicSTSState(kDomain, &sts_state));
+    ASSERT_EQ(kDomain, sts_state.domain);
+
+    // Destroy the network context, and wait for all tasks to write state to
+    // disk to finish running.
+    network_context.reset();
+    scoped_task_environment_.RunUntilIdle();
+    EXPECT_EQ(on_disk,
+              base::PathExists(transport_security_persister_file_path));
+
+    // Create a new NetworkContext,with the same parameters, and check if the
+    // added STS entry still exists.
+    context_params = CreateContextParams();
+    if (on_disk) {
+      context_params->transport_security_persister_path =
+          transport_security_persister_path;
+    }
+    network_context = CreateContextWithParams(std::move(context_params));
+    // Wait for the entry to load.
+    scoped_task_environment_.RunUntilIdle();
+    state = network_context->url_request_context()->transport_security_state();
+    ASSERT_EQ(on_disk, state->GetDynamicSTSState(kDomain, &sts_state));
+    if (on_disk)
+      EXPECT_EQ(kDomain, sts_state.domain);
+  }
+}
+
 // Validates that clearing the HTTP cache when no cache exists does complete.
 TEST_F(NetworkContextTest, ClearHttpCacheWithNoCache) {
   mojom::NetworkContextParamsPtr context_params = CreateContextParams();
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index f151fdf0..d2c9d36cd4 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -80,6 +80,11 @@
   // logic. If null, an in-memory cache will be used instead.
   mojo_base.mojom.FilePath? http_server_properties_path;
 
+  // The directory in which to store cached transport security properties (like
+  // HSTS). The file itself will be called "TransportSecurity". If null, or the
+  // file can't be opened, an in-memory store will be used instead.
+  mojo_base.mojom.FilePath? transport_security_persister_path;
+
   // Enabled protocols. Note that these apply to all fetches, including those
   // used to fetch PAC scripts.
 
diff --git a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
index 3f0507b..312df8f 100644
--- a/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
@@ -404,8 +404,7 @@
     return nullptr;
 
   raster_interface_ = std::make_unique<gpu::raster::RasterImplementationGLES>(
-      gles2_impl_.get(), gles2_impl_.get(), command_buffer_.get(),
-      ContextCapabilities());
+      gles2_impl_.get(), command_buffer_.get(), ContextCapabilities());
   return raster_interface_.get();
 }
 
diff --git a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
index f5d8b2c..18823c2 100644
--- a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
@@ -92,16 +92,10 @@
   request->SetScaleRatio(scale_from, scale_to);
 
   if (!data.ReadSource(&request->source_) || !data.ReadArea(&request->area_) ||
-      !data.ReadResultSelection(&request->result_selection_) ||
-      !data.ReadMailbox(&request->mailbox_) ||
-      !data.ReadSyncToken(&request->sync_token_)) {
+      !data.ReadResultSelection(&request->result_selection_)) {
     return false;
   }
 
-  // Mailbox and SyncToken always come together.
-  if (!request->mailbox_ != !request->sync_token_)
-    return false;
-
   *out_p = std::move(request);
 
   return true;
diff --git a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
index 20a4dfc..a95baeb 100644
--- a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
+++ b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
@@ -46,16 +46,6 @@
     return request->result_selection_;
   }
 
-  static const base::Optional<gpu::Mailbox>& mailbox(
-      const std::unique_ptr<viz::CopyOutputRequest>& request) {
-    return request->mailbox_;
-  }
-
-  static const base::Optional<gpu::SyncToken>& sync_token(
-      const std::unique_ptr<viz::CopyOutputRequest>& request) {
-    return request->sync_token_;
-  }
-
   static viz::mojom::CopyOutputResultSenderPtr result_sender(
       const std::unique_ptr<viz::CopyOutputRequest>& request);
 
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 70d09bc..c7456d6 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -327,7 +327,6 @@
             quit_closure.Run();
           },
           run_loop_for_result.QuitClosure(), result_rect)));
-  input->SetMailbox(mailbox, sync_token);
   EXPECT_FALSE(input->is_scaled());
   std::unique_ptr<CopyOutputRequest> output;
   SerializeAndDeserialize<mojom::CopyOutputRequest>(input, &output);
@@ -336,8 +335,6 @@
   EXPECT_FALSE(output->is_scaled());
   EXPECT_FALSE(output->has_source());
   EXPECT_FALSE(output->has_area());
-  EXPECT_TRUE(output->has_mailbox());
-  EXPECT_EQ(mailbox, output->mailbox());
 
   base::RunLoop run_loop_for_release;
   output->SendResult(std::make_unique<CopyOutputTextureResult>(
diff --git a/services/viz/public/interfaces/compositing/copy_output_request.mojom b/services/viz/public/interfaces/compositing/copy_output_request.mojom
index 220c2e4..045f7529 100644
--- a/services/viz/public/interfaces/compositing/copy_output_request.mojom
+++ b/services/viz/public/interfaces/compositing/copy_output_request.mojom
@@ -22,12 +22,6 @@
   gfx.mojom.Rect? area;
   gfx.mojom.Rect? result_selection;
 
-  // DEPRECATED: To be removed once tab capture is moved into VIZ.
-  // http://crbug.com/754872
-  // If mailbox is present, then sync_token must also be.
-  gpu.mojom.Mailbox? mailbox;
-  gpu.mojom.SyncToken? sync_token;
-
   CopyOutputResultSender result_sender;
 };
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 799691c..b27afee 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -403,6 +403,99 @@
   "chromeos-amd64-generic-rel": {
     "additional_compile_targets": [
       "chromiumos_preflight"
+    ],
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "google_apis_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "url_unittests"
+      }
     ]
   },
   "chromeos-daisy-rel": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 66337b5..1658e5d 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -8085,7 +8085,7 @@
             }
           ]
         },
-        "test": "cacheinvalidation_unittests"
+        "test": "base_unittests"
       },
       {
         "swarming": {
@@ -8098,73 +8098,7 @@
             }
           ]
         },
-        "test": "capture_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-CrOS-VM"
-            }
-          ],
-          "shards": 2
-        },
-        "test": "crypto_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-CrOS-VM"
-            }
-          ]
-        },
-        "test": "google_apis_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-CrOS-VM"
-            }
-          ]
-        },
-        "test": "midi_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-CrOS-VM"
-            }
-          ]
-        },
-        "test": "sql_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-CrOS-VM"
-            }
-          ]
-        },
-        "test": "url_unittests"
+        "test": "net_unittests"
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/filters/viz.browser_tests.filter b/testing/buildbot/filters/viz.browser_tests.filter
index 0f03cd5..f333d0c9 100644
--- a/testing/buildbot/filters/viz.browser_tests.filter
+++ b/testing/buildbot/filters/viz.browser_tests.filter
@@ -26,6 +26,7 @@
 #### Compositor Frame Observation Timeouts
 # WaitForChildFrameSurfaceReady crashes crbug.com/787945
 -PDFExtensionHitTestTest.ContextMenuCoordinates*
+-PDFExtensionHitTestTest.MouseLeave*
 -SitePerProcessDevToolsSanityTest.InputDispatchEventsToOOPIF
 -WebViewTest.InterstitialPageFocusedWidget
 -WebViewTest.ReloadAfterCrash
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 75ab68df..0112d7f 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -362,17 +362,18 @@
   'chromeos_gtests': {
     'cacheinvalidation_unittests': {},
     'capture_unittests': {},
-    'crypto_unittests': {
-       'swarming': {
-         'shards': 2,
-       },
-    },
+    'crypto_unittests': {},
     'midi_unittests': {},
     'google_apis_unittests': {},
     'sql_unittests': {},
     'url_unittests': {},
   },
 
+  'chromeos_gtests_experimental': {
+    'base_unittests': {},
+    'net_unittests': {},
+  },
+
   'chromeos_isolated_scripts': {
     'telemetry_perf_unittests': {
       'args': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 34e3722e..5663bcb 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -586,6 +586,18 @@
         'additional_compile_targets': [
           'chromiumos_preflight',
         ],
+        'test_suites': {
+          'gtest_tests': 'chromeos_gtests',
+        },
+        'swarming': {
+          'dimension_sets': [
+            {
+              'kvm': '1',
+              'os': 'Ubuntu-14.04',
+              'pool': 'Chrome-CrOS-VM',
+            },
+          ],
+        },
       },
       'chromeos-daisy-rel': {
         'additional_compile_targets': [
@@ -1430,7 +1442,7 @@
           'chromiumos_preflight',
         ],
         'test_suites': {
-          'gtest_tests': 'chromeos_gtests',
+          'gtest_tests': 'chromeos_gtests_experimental',
           'isolated_scripts': 'chromeos_isolated_scripts',
         },
         'swarming': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 33c5706..de1ecb1 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3875,6 +3875,29 @@
             ]
         }
     ],
+    "UkmSamplingRate": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Sampled",
+                    "params": {
+                        "_default_sampling": "1"
+                    },
+                    "enable_features": [
+                        "UkmSamplingRate"
+                    ]
+                }
+            ]
+        }
+    ],
     "UpdateMenuItem": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
index 1cebf926..8a5bc023 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
@@ -171,6 +171,7 @@
 crbug.com/836897 virtual/threaded/animations/element-animate-positive-delay.html [ Crash ]
 
 # These scrollbar tests should pass.
+Bug(none) virtual/prefer_compositing_to_lcd_text/scrollbars/ [ Pass ]
 crbug.com/836912 compositing/rtl/rtl-absolute-overflow.html [ Failure ]
 crbug.com/836912 compositing/rtl/rtl-and-writing-mode-scrolling.html [ Failure ]
 crbug.com/836912 compositing/rtl/rtl-fixed-overflow.html [ Failure ]
@@ -179,9 +180,52 @@
 crbug.com/836912 compositing/rtl/rtl-overflow-invalidation.html [ Failure ]
 crbug.com/836912 compositing/scrollbars/nested-overlay-scrollbars.html [ Failure ]
 crbug.com/836912 compositing/squashing/vertical-writing-mode-squashed.html [ Failure ]
-crbug.com/836912 scrollbars/scrollbar-added-during-drag.html [ Crash ]
-crbug.com/836912 scrollbars/scrollbar-removed-by-viewport-crash.html [ Crash ]
+crbug.com/841423 scrollbars/scrollbar-added-during-drag.html [ Crash ]
+crbug.com/841423 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-added-during-drag.html [ Crash ]
+crbug.com/840017 scrollbars/scrollbar-removed-by-viewport-crash.html [ Crash ]
+crbug.com/840017 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-removed-by-viewport-crash.html [ Crash ]
 crbug.com/841342 scrollbars/border-box-rect-clips-scrollbars.html [ Failure ]
+crbug.com/841342 virtual/prefer_compositing_to_lcd_text/scrollbars/border-box-rect-clips-scrollbars.html [ Failure ]
+crbug.com/841342 virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbars-paint-outside-iframe.html [ Failure ]
+
+# These scrolling tests should pass.
+Bug(none) virtual/threaded/fast/scrolling [ Pass ]
+Bug(none) fast/scrolling [ Pass ]
+Bug(none) fast/events [ Pass ]
+crbug.com/840017 fast/scrolling/editor-command-scroll-page-scale.html [ Crash ]
+crbug.com/840017 fast/scrolling/keyboard-scroll-page-scale.html [ Crash ]
+crbug.com/840017 fast/scrolling/overflow-clip-with-page-scale.html [ Crash ]
+crbug.com/840017 fast/scrolling/same-page-navigate.html [ Crash ]
+crbug.com/840017 fast/scrolling/scroll-without-document-element-renderer.html [ Crash ]
+crbug.com/840017 fast/scrolling/scroll-without-document-element.html [ Crash ]
+crbug.com/840017 virtual/threaded/fast/scrolling/editor-command-scroll-page-scale.html [ Crash ]
+crbug.com/840017 virtual/threaded/fast/scrolling/keyboard-scroll-page-scale.html [ Crash ]
+crbug.com/840017 virtual/threaded/fast/scrolling/overflow-clip-with-page-scale.html [ Crash ]
+crbug.com/840017 virtual/threaded/fast/scrolling/same-page-navigate.html [ Crash ]
+crbug.com/840017 virtual/threaded/fast/scrolling/scroll-without-document-element.html [ Crash ]
+crbug.com/840017 virtual/threaded/fast/scrolling/scroll-without-document-element-renderer.html [ Crash ]
+crbug.com/840017 fast/events/gesture-pinch-zoom-scroll-bubble.html [ Crash ]
+crbug.com/840017 fast/events/gesture-pinch-zoom.html [ Crash ]
+crbug.com/840017 fast/events/menu-key-context-menu-document-pinch-zoom.html [ Crash ]
+crbug.com/840017 fast/events/page-scaled-mouse-click-iframe.html [ Crash ]
+crbug.com/840017 fast/events/page-scaled-mouse-click.html [ Crash ]
+crbug.com/840017 fast/events/resize-events.html [ Crash ]
+crbug.com/840017 fast/events/scale-and-scroll-body.html [ Crash ]
+crbug.com/840017 fast/events/scale-and-scroll-div.html [ Crash ]
+crbug.com/840017 fast/events/scale-and-scroll-iframe-body.html [ Crash ]
+crbug.com/840017 fast/events/scale-and-scroll-iframe-window.html [ Crash ]
+crbug.com/840017 fast/events/scale-and-scroll-window.html [ Crash ]
+crbug.com/840017 fast/events/scroll-in-scaled-page-with-overflow-hidden.html [ Crash ]
+crbug.com/840017 fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Crash ]
+crbug.com/840017 fast/events/touch/page-scaled-touch-gesture-click.html [ Crash ]
+crbug.com/840017 fast/events/touch/touch-scaled-scrolled.html [ Crash ]
+crbug.com/840017 fast/events/touch/gesture/touch-gesture-fling-with-page-scale.html [ Crash ]
+crbug.com/840017 fast/events/touch/gesture/touch-gesture-scroll-div-scaled.html [ Crash ]
+crbug.com/836913 virtual/threaded/fast/scrolling/background-paint-scrolled.html [ Failure ]
+crbug.com/836913 virtual/threaded/fast/scrolling/hover-during-scroll.html [ Failure ]
+crbug.com/841567 virtual/threaded/fast/scrolling/listbox-wheel-event.html [ Failure ]
+crbug.com/836913 virtual/threaded/fast/scrolling/overflow-scrollability.html [ Failure ]
+crbug.com/836913 virtual/threaded/fast/scrolling/overlay-scrollbars.html [ Failure ]
 
 # These visual viewport tests should pass.
 Bug(none) external/wpt/visual-viewport [ Pass ]
@@ -194,7 +238,7 @@
 crbug.com/836890 rootscroller/scroll-non-descendant-of-root-scroller.html [ Crash ]
 crbug.com/836890 rootscroller/set-root-scroller.html [ Crash ]
 crbug.com/836890 rootscroller/set-rootscroller-before-load.html [ Crash ]
-crbug.com/836890 virtual/android/frame-size/intersection-observer-root-uses-frame-size.html [ Crash ]
+crbug.com/840017 virtual/android/frame-size/intersection-observer-root-uses-frame-size.html [ Crash ]
 crbug.com/836890 virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ Failure ]
 crbug.com/836890 virtual/android/rootscroller/gesture-scroll-document-not-root-scroller.html [ Failure ]
 crbug.com/836890 virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-hidden.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 17e59858..2120761f 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1060,6 +1060,7 @@
 crbug.com/730284 fast/replaced/border-radius-clip.html [ Failure ]
 
 # Check failed: layer_list_.empty() || *page_scale_factor == 1
+crbug.com/706066 clipboard/copy-image-at-with-pinch-zoom.html [ Crash Timeout ]
 crbug.com/706066 compositing/background-color/background-color-outside-document.html [ Crash Timeout ]
 crbug.com/706066 compositing/overflow/overflow-scaled-descendant-overlapping.html [ Crash Timeout ]
 crbug.com/706066 compositing/gestures/gesture-tapHighlight-simple-scaled-document.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 34b8779..97631e6 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -59,9 +59,6 @@
 # https://crbug.com/786510 - test tries to access cross-origin document body
 crbug.com/606594 http/tests/local/serviceworker/fetch-request-body-file.html [ Skip ]
 
-# https://crbug.com/607991 - MockWebClipboardImpl not replicated across OOPIFs.
-crbug.com/607991 http/tests/misc/copy-resolves-urls.html [ Failure ]
-
 # https://crbug.com/616626 - allow_universal_access_from_file_urls doesn't work with --site-per-process.
 # https://crbug.com/665058 - EventSender drag-and-drop simulation doesn't support OOPIFs.
 crbug.com/665058 http/tests/local/drag-over-remote-content.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 6f8dc3d7..f5b48569 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -5,10 +5,11 @@
 # Intentional failures to test the layout test system.
 Bug(intentional) harness-tests/crash.html [ Crash ]
 Bug(intentional) harness-tests/timeout.html [ Timeout ]
-Bug(intentional) external/wpt/infrastructure/reftest/reftest_timeout.html [ Timeout ]
+Bug(intentional) external/wpt/infrastructure/reftest/reftest_match_fail.html [ Failure ]
 Bug(intentional) external/wpt/infrastructure/reftest/reftest_mismatch_fail.html [ Failure ]
 Bug(intentional) external/wpt/infrastructure/reftest/reftest_ref_timeout.html [ Timeout ]
-Bug(intentional) external/wpt/infrastructure/reftest/reftest_match_fail.html [ Failure ]
+Bug(intentional) external/wpt/infrastructure/reftest/reftest_timeout.html [ Timeout ]
+Bug(intentional) external/wpt/infrastructure/expected-fail/timeout.html [ Timeout ]
 
 crbug.com/807686 crbug.com/24182 jquery/manipulation.html [ Timeout Pass ]
 
@@ -2788,6 +2789,7 @@
 crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Win7 ] external/wpt/pointerevents/pointerevent_pointerout_received_once-manual.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-016.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-013.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-011.html [ Failure ]
@@ -3703,6 +3705,8 @@
 crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.percent.worker.html [ Failure ]
 crbug.com/709227 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.trailingjunk.worker.html [ Failure ]
 crbug.com/709227 external/wpt/user-timing/invoke_with_timing_attributes.worker.html [ Failure ]
+crbug.com/839947 external/wpt/console/console-counting-label-conversion.any.html [ Failure ]
+crbug.com/839947 external/wpt/console/console-counting-label-conversion.any.worker.html [ Failure ]
 
 # Timeouts
 crbug.com/709227 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.worker.html [ Timeout ]
@@ -3711,7 +3715,6 @@
 # Crashes
 crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ]
 
-
 # ====== Tests from enabling .any.js/.worker.js tests end here ========
 
 crbug.com/789139 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Failure Pass Timeout Crash ]
@@ -4201,6 +4204,9 @@
 
 crbug.com/766129 svg/wicd/test-rightsizing-b.xhtml [ Failure Pass ]
 
+crbug.com/841567 virtual/threaded/fast/scrolling/listbox-wheel-event.html [ Failure ]
+crbug.com/841567 virtual/threaded/fast/scrolling/hover-during-scroll.html [ Timeout ]
+
 # Workaround crbug.com/817175 . Very difficult to fix with old-world compositing. Pass with SPv2.
 crbug.com/817175 compositing/overflow/clip-escaping-reverse-order-should-not-crash.html [ Failure ]
 crbug.com/817175 virtual/disable-spv175/compositing/overflow/clip-escaping-reverse-order-should-not-crash.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 40469be..a339d2f 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -12,8 +12,7 @@
   {
     "prefix": "gpu",
     "base": "fast/canvas",
-    "args": ["--enable-accelerated-2d-canvas",
-             "--disable-display-list-2d-canvas"]
+    "args": ["--enable-accelerated-2d-canvas"]
   },
   {
     "prefix": "threaded",
@@ -73,6 +72,12 @@
              "--enable-prefer-compositing-to-lcd-text"]
   },
   {
+    "prefix": "threaded",
+    "base": "fast/scrolling",
+    "args": ["--enable-threaded-compositing",
+             "--enable-prefer-compositing-to-lcd-text"]
+  },
+  {
     "prefix": "gpu-rasterization",
     "base": "images",
     "args": ["--force-gpu-rasterization"]
diff --git a/third_party/WebKit/LayoutTests/clipboard/copy-image-at-expected.txt b/third_party/WebKit/LayoutTests/clipboard/copy-image-at-expected.txt
new file mode 100644
index 0000000..43e5eeed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/clipboard/copy-image-at-expected.txt
@@ -0,0 +1,4 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/clipboard/copy-image-at-with-pinch-zoom-expected.txt b/third_party/WebKit/LayoutTests/clipboard/copy-image-at-with-pinch-zoom-expected.txt
new file mode 100644
index 0000000..43e5eeed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/clipboard/copy-image-at-with-pinch-zoom-expected.txt
@@ -0,0 +1,4 @@
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/clipboard/copy-image-at-with-pinch-zoom.html b/third_party/WebKit/LayoutTests/clipboard/copy-image-at-with-pinch-zoom.html
new file mode 100644
index 0000000..4af320a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/clipboard/copy-image-at-with-pinch-zoom.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas style="position:absolute; top:40px; left:40px" width="200" height="200"></canvas>
+<script src="../resources/js-test.js"></script>
+<script>
+testRunner.waitUntilDone();
+testRunner.dumpAsText();
+requestAnimationFrame(() => {
+  var canvas = document.querySelector("canvas");
+  var context = canvas.getContext("2d");
+  context.fillStyle = "red";
+  context.fillRect(0, 0, 200, 200);
+  window.internals.setPageScaleFactor(2);
+  window.internals.setVisualViewportOffset(200, 200);
+  requestAnimationFrame(() => {
+    testRunner.copyImageAtAndCapturePixelsAsyncThen(0, 0, (width, height, snapshot) => {
+      try {
+        if (width !== 200 || height !== 200)
+          testFailed("The copied image must be 200x200.");
+        var topleft = new Uint8Array(snapshot).subarray(0, 4);
+        if (topleft[0] !== 255 || topleft[1] !== 0 || topleft[2] !== 0 || topleft[3] !== 255)
+          testFailed("The copied image's top left must be red. " + JSON.stringify(topleft));
+      } catch (e) {
+        testFailed("" + e);
+      }
+      testRunner.notifyDone();
+    });
+  });
+});
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/clipboard/copy-image-at.html b/third_party/WebKit/LayoutTests/clipboard/copy-image-at.html
new file mode 100644
index 0000000..85ef14a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/clipboard/copy-image-at.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas style="position:absolute; top:40px; left:40px" width="200" height="200"></canvas>
+<script src="../resources/js-test.js"></script>
+<script>
+testRunner.waitUntilDone();
+testRunner.dumpAsText();
+requestAnimationFrame(() => {
+  var canvas = document.querySelector("canvas");
+  var context = canvas.getContext("2d");
+  context.fillStyle = "red";
+  context.fillRect(0, 0, 200, 200);
+  requestAnimationFrame(() => {
+    testRunner.copyImageAtAndCapturePixelsAsyncThen(50, 50, (width, height, snapshot) => {
+      try {
+        if (width !== 200 || height !== 200)
+          testFailed("The copied image must be 200x200.");
+        var topleft = new Uint8Array(snapshot).subarray(0, 4);
+        if (topleft[0] !== 255 || topleft[1] !== 0 || topleft[2] !== 0 || topleft[3] !== 255)
+          testFailed("The copied image's top left must be red. " + JSON.stringify(topleft));
+      } catch (e) {
+        testFailed("" + e);
+      }
+      testRunner.notifyDone();
+    });
+  });
+});
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 1dfd2edd..1e428ef 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -152361,6 +152361,11 @@
      {}
     ]
    ],
+   "html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/scripting-1/the-script-element/module/import-something-namespace.js": [
     [
      {}
@@ -154521,6 +154526,11 @@
      {}
     ]
    ],
+   "infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini": [
+    [
+     {}
+    ]
+   ],
    "infrastructure/metadata/infrastructure/reftest/reftest_and_fail.html.ini": [
     [
      {}
@@ -168851,6 +168861,11 @@
      {}
     ]
    ],
+   "workers/modules/dedicated-worker-import-meta-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "workers/modules/resources/dynamic-import-and-then-static-import-worker.js": [
     [
      {}
@@ -211086,6 +211101,12 @@
      {}
     ]
    ],
+   "infrastructure/expected-fail/timeout.html": [
+    [
+     "/infrastructure/expected-fail/timeout.html",
+     {}
+    ]
+   ],
    "infrastructure/server/secure-context.https.any.js": [
     [
      "/infrastructure/server/secure-context.https.any.html",
@@ -354863,8 +354884,12 @@
    "bc8e6d649615d09b970e328873bc138093f1c14d",
    "support"
   ],
+  "html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url-expected.txt": [
+   "4283a063a51cfb5bbb02028a79be1df50e704852",
+   "support"
+  ],
   "html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html": [
-   "9758a62ec1f943c00dcd9b58ca62464c5c78bbb3",
+   "3328350068373e6ad5cfd06f1180468ea4dccfb8",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/import-something-namespace.js": [
@@ -358171,6 +358196,10 @@
    "c832afb4826fd43d2fcc4f5e3fd6a773a6ee35f0",
    "testharness"
   ],
+  "infrastructure/expected-fail/timeout.html": [
+   "a91279f3455bdaf63412e9487192502da1e51baf",
+   "testharness"
+  ],
   "infrastructure/metadata/infrastructure/assumptions/html-elements.html.ini": [
    "0f536ac59a959769966d56c5a546f9f2c2557e97",
    "support"
@@ -358179,6 +358208,10 @@
    "7eecbfc4845e6befe54b0f007d587a1a003993dc",
    "support"
   ],
+  "infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini": [
+   "03ddb1ea28337dabd61082a566149fa1e94f3e97",
+   "support"
+  ],
   "infrastructure/metadata/infrastructure/reftest/reftest_and_fail.html.ini": [
    "b6c1fe38e610a8ffaf843c0c0b791c65fe6d5145",
    "support"
@@ -392543,8 +392576,12 @@
    "6bffa3be83d81e2faa93119e710e4fee93fb855e",
    "testharness"
   ],
+  "workers/modules/dedicated-worker-import-meta-expected.txt": [
+   "572182b28a89039a4fa5ce5df89da53e083d1307",
+   "support"
+  ],
   "workers/modules/dedicated-worker-import-meta.html": [
-   "ba8b24064e23f018ffd3ac9e4184d6f856123bff",
+   "32cd3419ff904a2440d9a6eaa7cb28f78d4a7e32",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical-expected.txt
deleted file mode 100644
index f2193a15..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This is a testharness.js-based test.
-PASS Historical Document member: selectedStyleSheetSet
-PASS Historical Document member: lastStyleSheetSet
-PASS Historical Document member: preferredStyleSheetSet
-PASS Historical Document member: styleSheetSets
-PASS Historical Document member: enableStyleSheetsForSet
-FAIL Historical Document member: selectedStylesheetSet assert_false: expected false got true
-FAIL Historical Document member: preferredStylesheetSet assert_false: expected false got true
-PASS Historical Element member: cascadedStyle
-PASS Historical Element member: defaultStyle
-PASS Historical Element member: rawComputedStyle
-PASS Historical Element member: usedStyle
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/preferred-stylesheet-order.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/preferred-stylesheet-order.html
new file mode 100644
index 0000000..dc990131
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/preferred-stylesheet-order.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/cssom/#add-a-css-style-sheet">
+<link rel="help" href="https://drafts.csswg.org/cssom/#create-a-css-style-sheet">
+<link rel="help" href="https://html.spec.whatwg.org/#update-a-style-block">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="t1">This text should be green</div>
+<script>
+function createStyleElement(text, title) {
+    var elm = document.createElement("style");
+    elm.setAttribute("title", title);
+    elm.appendChild(document.createTextNode(text));
+    return elm;
+}
+
+test(function() {
+    document.head.appendChild(createStyleElement("#t1 {color:green}", "preferred"));
+    document.head.appendChild(createStyleElement("#t1 {color:red}", "notpreferred"));
+
+    assert_equals(getComputedStyle(t1).color, "rgb(0, 128, 0)");
+}, "Preferred stylesheet where insertion order is reversed tree order");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/preferred-stylesheet-reversed-order.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/preferred-stylesheet-reversed-order.html
new file mode 100644
index 0000000..ff3a8b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/preferred-stylesheet-reversed-order.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/cssom/#add-a-css-style-sheet">
+<link rel="help" href="https://drafts.csswg.org/cssom/#create-a-css-style-sheet">
+<link rel="help" href="https://html.spec.whatwg.org/#update-a-style-block">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="t1">This text should be green</div>
+<script>
+function createStyleElement(text, title) {
+    var elm = document.createElement("style");
+    elm.setAttribute("title", title);
+    elm.appendChild(document.createTextNode(text));
+    return elm;
+}
+
+test(function() {
+    document.head.insertBefore(createStyleElement("#t1 {color:green}", "preferred"), document.head.firstChild);
+    document.head.insertBefore(createStyleElement("#t1 {color:red}", "notpreferred"), document.head.firstChild);
+
+    assert_equals(getComputedStyle(t1).color, "rgb(0, 128, 0)");
+}, "Preferred stylesheet where insertion order is tree order");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url-expected.txt
new file mode 100644
index 0000000..4c25322
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS import.meta.url in a root inline script
+PASS import.meta.url in a root external script
+PASS import.meta.url in a dependent external script
+FAIL import.meta.url when importing the module with different fragments assert_equals: expected "http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js#1" but got "http://web-platform.test:8001/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
index 3c853b2..fa1c7dee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
@@ -20,4 +20,26 @@
   assert_equals(importMetaOnDependentModule.url,
                 base + "/import-meta-dependent.js");
 }, "import.meta.url in a dependent external script");
+
+import { importMetaOnRootModule as hashedImportMetaOnRootModule1,
+         importMetaOnDependentModule as hashedImportMetaOnDependentModule1 }
+       from "./import-meta-root.js#1";
+
+import { importMetaOnRootModule as hashedImportMetaOnRootModule2,
+         importMetaOnDependentModule as hashedImportMetaOnDependentModule2 }
+       from "./import-meta-root.js#2";
+
+test(() => {
+  assert_equals(hashedImportMetaOnRootModule1.url,
+                base + "/import-meta-root.js#1");
+  assert_equals(hashedImportMetaOnRootModule2.url,
+                base + "/import-meta-root.js#2");
+
+  // Must not be affected
+  assert_equals(hashedImportMetaOnDependentModule1.url,
+                base + "/import-meta-dependent.js");
+  assert_equals(hashedImportMetaOnDependentModule2.url,
+                base + "/import-meta-dependent.js");
+}, "import.meta.url when importing the module with different fragments");
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/infrastructure/expected-fail/timeout.html b/third_party/WebKit/LayoutTests/external/wpt/infrastructure/expected-fail/timeout.html
new file mode 100644
index 0000000..29ff348
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/infrastructure/expected-fail/timeout.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test that should time out</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test()
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini b/third_party/WebKit/LayoutTests/external/wpt/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini
new file mode 100644
index 0000000..53b281f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini
@@ -0,0 +1,4 @@
+[timeout.html]
+  expected: TIMEOUT
+  [Test that should time out]
+    expected: NOTRUN
diff --git a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html
index 14d3f822..58135b1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html
@@ -44,8 +44,6 @@
 
 
 }), 'A_04_01_11_T2');
-
-// TODO check selectedStyleSheetSet, lastStyleSheetSet, preferredStyleSheetSet, styleSheetSets
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta-expected.txt
new file mode 100644
index 0000000..229c339
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS Test import.meta.url on the top-level module script.
+PASS Test import.meta.url on the imported module script.
+FAIL Test import.meta.url on the imported module script with a fragment. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta.html b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta.html
index ae59fda..6960cbe 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/modules/dedicated-worker-import-meta.html
@@ -20,4 +20,19 @@
       .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
 }, 'Test import.meta.url on the imported module script.');
 
+promise_test(() => {
+  const script_url = 'import-meta-url-worker.js';
+  const worker = new Worker('resources/dynamic-import-given-url-worker.js',
+                            { type: 'module' });
+  worker.postMessage('./' + script_url);
+
+  return new Promise(resolve => worker.onmessage = resolve)
+      .then(msg_event => assert_true(msg_event.data.endsWith(script_url)))
+      .then(() => {
+        worker.postMessage('./' + script_url + '#1');
+        return new Promise(resolve => worker.onmessage = resolve);
+      })
+      .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
+}, 'Test import.meta.url on the imported module script with a fragment.');
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr-expected.txt b/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr-expected.txt
index 887d2abb..cc69d4f8 100644
--- a/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr-expected.txt
@@ -19,10 +19,6 @@
 FAIL link.disabled should be true. Was false.
 PASS link.sheet is non-null.
 FAIL getComputedStyle(testElement).backgroundColor should be rgb(0, 128, 0). Was rgba(0, 0, 0, 0).
-FAIL link.disabled should be true. Was false.
-PASS getComputedStyle(testElement).backgroundColor is originalBG
-PASS link.disabled is false
-FAIL getComputedStyle(testElement).backgroundColor should be rgb(0, 128, 0). Was rgba(0, 0, 0, 0).
 PASS getComputedStyle(testElement).backgroundColor is originalBG
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr.html b/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr.html
index 3e24be2..994a7d0 100644
--- a/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr.html
+++ b/third_party/WebKit/LayoutTests/fast/css/link-disabled-attr.html
@@ -75,19 +75,6 @@
     shouldBeNonNull("link.sheet");
     shouldBe("getComputedStyle(testElement).backgroundColor", "'rgb(0, 128, 0)'");
 
-    // Enabling a stylsheet set modifies disabled status of style sheets.
-
-    document.selectedStyleSheetSet = "nosuchset";
-    shouldBeTrue("link.disabled");
-    shouldBe("getComputedStyle(testElement).backgroundColor", "originalBG");
-
-    document.selectedStyleSheetSet = "altset";
-    shouldBeFalse("link.disabled");
-    shouldBe("getComputedStyle(testElement).backgroundColor", "'rgb(0, 128, 0)'");
-
-    // Disabling a stylesheet *after* its stylesheet set has been selected
-    // de-activates it.
-
     link.disabled = true;
     shouldBe("getComputedStyle(testElement).backgroundColor", "originalBG");
 
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order-expected.txt b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order-expected.txt
deleted file mode 100644
index be77474..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Preferred stylesheet where insertion order is reversed tree order
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS getComputedStyle(t1).color is "rgb(0, 128, 0)"
-PASS document.preferredStylesheetSet is "preferred"
-PASS document.selectedStylesheetSet is "preferred"
-PASS successfullyParsed is true
-
-TEST COMPLETE
-This text should be green
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order.html b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order.html
deleted file mode 100644
index b28225e..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-order.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<div id="t1">This text should be green</div>
-<script>
-description("Preferred stylesheet where insertion order is reversed tree order");
-
-function createStyleElement(text, title) {
-    var elm = document.createElement("style");
-    elm.setAttribute("title", title);
-    elm.appendChild(document.createTextNode(text));
-    return elm;
-}
-
-document.head.appendChild(createStyleElement("#t1 {color:green}", "preferred"));
-document.head.appendChild(createStyleElement("#t1 {color:red}", "notpreferred"));
-
-shouldBeEqualToString("getComputedStyle(t1).color", "rgb(0, 128, 0)");
-shouldBeEqualToString("document.preferredStylesheetSet", "preferred");
-shouldBeEqualToString("document.selectedStylesheetSet", "preferred");
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order-expected.txt b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order-expected.txt
deleted file mode 100644
index b78f3a9..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Preferred stylesheet where insertion order is tree order
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS getComputedStyle(t1).color is "rgb(0, 128, 0)"
-PASS document.preferredStylesheetSet is "preferred"
-PASS document.selectedStylesheetSet is "preferred"
-PASS successfullyParsed is true
-
-TEST COMPLETE
-This text should be green
diff --git a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order.html b/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order.html
deleted file mode 100644
index f3278801..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/preferred-stylesheet-reversed-order.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<div id="t1">This text should be green</div>
-<script>
-description("Preferred stylesheet where insertion order is tree order");
-
-function createStyleElement(text, title) {
-    var elm = document.createElement("style");
-    elm.setAttribute("title", title);
-    elm.appendChild(document.createTextNode(text));
-    return elm;
-}
-
-document.head.insertBefore(createStyleElement("#t1 {color:green}", "preferred"), document.head.firstChild);
-document.head.insertBefore(createStyleElement("#t1 {color:red}", "notpreferred"), document.head.firstChild);
-
-shouldBeEqualToString("getComputedStyle(t1).color", "rgb(0, 128, 0)");
-shouldBeEqualToString("document.preferredStylesheetSet", "preferred");
-shouldBeEqualToString("document.selectedStylesheetSet", "preferred");
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null-expected.txt
index 1769da5..13d0d2f 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null-expected.txt
@@ -5,7 +5,6 @@
 TEST SUCCEEDED: The value was the string 'UTF-8'. [tested Document.charset]
 TEST SUCCEEDED: The value was the string 'UTF-8'. [tested Document.characterSet]
 TEST SUCCEEDED: The value was the string 'UTF-8'. [tested Document.inputEncoding]
-TEST SUCCEEDED: The value was null. [tested Document.selectedStylesheetSet]
 
 TEST SUCCEEDED: The value was 'null'. [tested HTMLDocument.title]
 TEST SUCCEEDED: The value was the empty string. [tested HTMLDocument.cookie]
diff --git a/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null.html b/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null.html
index 3c617d0d..4c48a01 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/document-attribute-js-null.html
@@ -70,8 +70,7 @@
                         {name: 'documentURI', expectedNull: 'about:blank'},
                         {name: 'charset', expectedNull: 'UTF-8'},
                         {name: 'characterSet', expectedNull: 'UTF-8'},
-                        {name: 'inputEncoding', expectedNull: 'UTF-8'},
-                        {name: 'selectedStylesheetSet', expectedNull: null}
+                        {name: 'inputEncoding', expectedNull: 'UTF-8'}
                     ]
                 },
                 {
diff --git a/third_party/WebKit/LayoutTests/fast/dom/document-preferredStylesheetSet-use-counter.html b/third_party/WebKit/LayoutTests/fast/dom/document-preferredStylesheetSet-use-counter.html
deleted file mode 100644
index dad9b77..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/document-preferredStylesheetSet-use-counter.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<title>document preferredStylesheetSet UseCounter</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style>
-</style>
-<script>
-test(function() {
-  const DocumentGetPreferredStylesheetSet = 2211; // From enums.xml
-  assert_false(internals.isUseCounted(document, DocumentGetPreferredStylesheetSet));
-  document.preferredStylesheetSet;
-  assert_true(internals.isUseCounted(document, DocumentGetPreferredStylesheetSet));
-}, 'document.preferredStylesheetSet is use counted');
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/document-selectedStylesheetSet-use-counter-001.html b/third_party/WebKit/LayoutTests/fast/dom/document-selectedStylesheetSet-use-counter-001.html
deleted file mode 100644
index e6dd725..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/document-selectedStylesheetSet-use-counter-001.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<title>document selectedStylesheetSet UseCounters</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style>
-</style>
-<script>
-test(function() {
-  const DocumentGetSelectedStylesheetSet = 2212; // From enums.xml
-  const DocumentSetSelectedStylesheetSet = 2213; // From enums.xml
-  assert_false(internals.isUseCounted(document, DocumentGetSelectedStylesheetSet));
-  document.selectedStylesheetSet;
-  assert_true(internals.isUseCounted(document, DocumentGetSelectedStylesheetSet));
-  assert_false(internals.isUseCounted(document, DocumentSetSelectedStylesheetSet));
-}, 'document get selectedStylesheetSet is use counted');
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/document-selectedStylesheetSet-use-counter-002.html b/third_party/WebKit/LayoutTests/fast/dom/document-selectedStylesheetSet-use-counter-002.html
deleted file mode 100644
index e6ef8ad..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/document-selectedStylesheetSet-use-counter-002.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<title>document preferredStylesheetSet UseCounter</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style>
-</style>
-<script>
-test(function() {
-  const DocumentGetSelectedStylesheetSet = 2212; // From enums.xml
-  const DocumentSetSelectedStylesheetSet = 2213; // From enums.xml
-  assert_false(internals.isUseCounted(document, DocumentSetSelectedStylesheetSet));
-  document.selectedStylesheetSet = '';
-  assert_true(internals.isUseCounted(document, DocumentSetSelectedStylesheetSet));
-  assert_false(internals.isUseCounted(document, DocumentGetSelectedStylesheetSet));
-}, 'document set selectedStylesheetSet is use counted');
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left-expected.txt
index 369b270..8a389fc 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left-expected.txt
@@ -4,11 +4,8 @@
 X
 X
 PASS elementRect('s1').top is 0
-FAIL elementRect('s1').left should be 347. Was 347.09375.
 PASS elementRect('s2').top is 20
-FAIL elementRect('s2').left should be 390. Was 389.984375.
 PASS elementRect('s3').top is 40
-FAIL elementRect('s3').left should be 417. Was 417.1875.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left.html b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left.html
index ff7ccbd..e24456a 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left.html
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-left.html
@@ -74,13 +74,13 @@
 var quiet = true; // PASS output depends on SubPixelLayout.isEnabled()
 
 shouldBe("elementRect('s1').top", "0");
-shouldBe("elementRect('s1').left", marginEllipseLeftXIntercept(20, 225, 225, 125), quiet);
+shouldBe("elementRect('s1').left", marginEllipseLeftXIntercept(20, 225, 225, 125), quiet, 1);
 
 shouldBe("elementRect('s2').top", "20");
-shouldBe("elementRect('s2').left", marginEllipseLeftXIntercept(40, 225, 225, 125), quiet);
+shouldBe("elementRect('s2').left", marginEllipseLeftXIntercept(40, 225, 225, 125), quiet, 1);
 
 shouldBe("elementRect('s3').top", "40");
-shouldBe("elementRect('s3').left", marginEllipseLeftXIntercept(60, 225, 225, 125), quiet);
+shouldBe("elementRect('s3').left", marginEllipseLeftXIntercept(60, 225, 225, 125), quiet, 1);
 
 </script>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right-expected.txt b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right-expected.txt
index 62c846d5..7085e88 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right-expected.txt
@@ -4,11 +4,8 @@
 X
 X
 PASS elementRect('s1').top is 0
-FAIL elementRect('s1').right should be 152. Was 152.90625.
 PASS elementRect('s2').top is 20
-FAIL elementRect('s2').right should be 110. Was 110.015625.
 PASS elementRect('s3').top is 40
-FAIL elementRect('s3').right should be 82. Was 82.8125.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right.html b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right.html
index eb7248e..f8ef26e9 100644
--- a/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right.html
+++ b/third_party/WebKit/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-ellipse-margin-right.html
@@ -76,13 +76,13 @@
 var quiet = true; // PASS output depends on SubPixelLayout.isEnabled()
 
 shouldBe("elementRect('s1').top", "0");
-shouldBe("elementRect('s1').right", marginEllipseRightXIntercept(20, 225, 225, 125), quiet);
+shouldBe("elementRect('s1').right", marginEllipseRightXIntercept(20, 225, 225, 125), quiet, 1);
 
 shouldBe("elementRect('s2').top", "20");
-shouldBe("elementRect('s2').right", marginEllipseRightXIntercept(40, 225, 225, 125), quiet);
+shouldBe("elementRect('s2').right", marginEllipseRightXIntercept(40, 225, 225, 125), quiet, 1);
 
 shouldBe("elementRect('s3').top", "40");
-shouldBe("elementRect('s3').right", marginEllipseRightXIntercept(60, 225, 225, 125), quiet);
+shouldBe("elementRect('s3').right", marginEllipseRightXIntercept(60, 225, 225, 125), quiet, 1);
 
 </script>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-space-inside.html b/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-space-inside.html
new file mode 100644
index 0000000..1423c2e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-space-inside.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>

+<script src="../../../resources/testharness.js"></script>

+<script src="../../../resources/testharnessreport.js"></script>

+<style>

+.container {

+  width:200px;

+  background-color:#eee;

+}

+.spacer {

+  height:10px; background-color:black;

+}

+.nowrap {

+  white-space: nowrap;

+}

+</style>

+<body>

+<p>Spaces in nowrap shold not break when the text before it fits but the space overflows.</p>

+<template id=template>

+  <div class=container>

+    <img class=spacer />

+    <span class=nowrap><span>foo</span> <span>bar</span></span>

+  </div>

+</template>

+<script>

+run();

+function run() {

+  let tests = [];

+  for (let width = 170; width < 180; width++) {

+    let element = template.content.children[0].cloneNode(true);

+    let spacer = element.querySelector('img');

+    spacer.style.width = width + 'px';

+    document.body.appendChild(element);

+    tests.push({width: width, element: element});

+  }

+  let results = [];

+  for (let t of tests) {

+    test(() => {

+      let nowrap = t.element.querySelector('.nowrap');

+      let child1 = nowrap.children[0];

+      let child2 = nowrap.children[1];

+      assert_equals(child1.offsetTop, child2.offsetTop);

+    }, `width: ${t.width}`);

+  }

+}

+</script>

+</body>

+

diff --git a/third_party/WebKit/LayoutTests/http/tests/appcache/fallback.html b/third_party/WebKit/LayoutTests/http/tests/appcache/fallback.html
index 6a0b7b5..663ba9f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/appcache/fallback.html
+++ b/third_party/WebKit/LayoutTests/http/tests/appcache/fallback.html
@@ -143,24 +143,11 @@
 {
     setNetworkEnabled(false);
 
-    var req = new XMLHttpRequest;
-    req.open("GET", testURL);
-    req.onerror = function() {
+    if (load(testURL) != load("resources/simple.txt")) {
         log("FAIL: Loading an URL from fallback namespace when network is disabled returned unexpected response");
         hadError = true;
-        finish();
     }
-    req.onload = function() {
-        if (req.responseText != "Hello, World!") {
-            hadError = true;
-            log("FAIL: Loading an URL from fallback namespace when network is disabled returned unexpected response");
-        }
-        finish();
-    }
-    req.send("");
-}
 
-function finish() {
     log(hadError ? "FAILURE" : "SUCCESS");
     if (window.testRunner)
         testRunner.notifyDone();
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.png
index 8c092715..8b85b370 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.txt
deleted file mode 100644
index 5fd4eba..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-inner-bleed-expected.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x356
-  LayoutBlockFlow {HTML} at (0,0) size 800x356
-    LayoutBlockFlow {BODY} at (8,8) size 784x340
-      LayoutTable {TABLE} at (0,0) size 610x340
-        LayoutTableSection {TBODY} at (0,0) size 610x340
-          LayoutTableRow {TR} at (0,2) size 610x155
-            LayoutTableCell {TD} at (2,2) size 150x155 [r=0 c=0 rs=1 cs=1]
-            LayoutTableCell {TD} at (154,2) size 150x155 [r=0 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (306,2) size 150x155 [r=0 c=2 rs=1 cs=1]
-            LayoutTableCell {TD} at (458,2) size 150x155 [r=0 c=3 rs=1 cs=1]
-          LayoutTableRow {TR} at (0,316) size 610x22
-            LayoutTableCell {TD} at (2,316) size 150x22 [r=2 c=0 rs=1 cs=1]
-              LayoutText {#text} at (58,1) size 34x19
-                text run at (58,1) width 34: "PNG"
-            LayoutTableCell {TD} at (154,316) size 150x22 [r=2 c=1 rs=1 cs=1]
-              LayoutText {#text} at (58,1) size 34x19
-                text run at (58,1) width 34: "SVG"
-            LayoutTableCell {TD} at (306,316) size 150x22 [r=2 c=2 rs=1 cs=1]
-              LayoutText {#text} at (58,1) size 34x19
-                text run at (58,1) width 34: "PNG"
-            LayoutTableCell {TD} at (458,316) size 150x22 [r=2 c=3 rs=1 cs=1]
-              LayoutText {#text} at (58,1) size 34x19
-                text run at (58,1) width 34: "SVG"
-layer at (31,31) size 108x108 clip at (35,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (183,31) size 108x108 clip at (187,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (335,31) size 108x108 clip at (339,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (487,31) size 108x108 clip at (491,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (8,167) size 610x155
-  LayoutTableRow {TR} at (0,159) size 610x155
-    LayoutTableCell {TD} at (2,159) size 150x155 [r=1 c=0 rs=1 cs=1]
-    LayoutTableCell {TD} at (154,159) size 150x155 [r=1 c=1 rs=1 cs=1]
-    LayoutTableCell {TD} at (306,159) size 150x155 [r=1 c=2 rs=1 cs=1]
-    LayoutTableCell {TD} at (458,159) size 150x155 [r=1 c=3 rs=1 cs=1]
-layer at (31,188) size 108x108 clip at (35,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (183,188) size 108x108 clip at (187,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (335,188) size 108x108 clip at (339,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (487,188) size 108x108 clip at (491,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/mask-with-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/mask-with-filter-expected.png
index 770e873..21229b8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/mask-with-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/mask-with-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.png
index a56937f..b48966d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.txt
deleted file mode 100644
index e6330f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-inner-bleed-expected.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x352
-  LayoutBlockFlow {HTML} at (0,0) size 800x352
-    LayoutBlockFlow {BODY} at (8,8) size 784x336
-      LayoutTable {TABLE} at (0,0) size 610x336
-        LayoutTableSection {TBODY} at (0,0) size 610x336
-          LayoutTableRow {TR} at (0,2) size 610x154
-            LayoutTableCell {TD} at (2,2) size 150x154 [r=0 c=0 rs=1 cs=1]
-            LayoutTableCell {TD} at (154,2) size 150x154 [r=0 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (306,2) size 150x154 [r=0 c=2 rs=1 cs=1]
-            LayoutTableCell {TD} at (458,2) size 150x154 [r=0 c=3 rs=1 cs=1]
-          LayoutTableRow {TR} at (0,314) size 610x20
-            LayoutTableCell {TD} at (2,314) size 150x20 [r=2 c=0 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x18
-                text run at (59,1) width 32: "PNG"
-            LayoutTableCell {TD} at (154,314) size 150x20 [r=2 c=1 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x18
-                text run at (59,1) width 32: "SVG"
-            LayoutTableCell {TD} at (306,314) size 150x20 [r=2 c=2 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x18
-                text run at (59,1) width 32: "PNG"
-            LayoutTableCell {TD} at (458,314) size 150x20 [r=2 c=3 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x18
-                text run at (59,1) width 32: "SVG"
-layer at (31,31) size 108x108 clip at (35,35) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (183,31) size 108x108 clip at (187,35) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (335,31) size 108x108 clip at (339,35) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (487,31) size 108x108 clip at (491,35) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (8,166) size 610x154
-  LayoutTableRow {TR} at (0,158) size 610x154
-    LayoutTableCell {TD} at (2,158) size 150x154 [r=1 c=0 rs=1 cs=1]
-    LayoutTableCell {TD} at (154,158) size 150x154 [r=1 c=1 rs=1 cs=1]
-    LayoutTableCell {TD} at (306,158) size 150x154 [r=1 c=2 rs=1 cs=1]
-    LayoutTableCell {TD} at (458,158) size 150x154 [r=1 c=3 rs=1 cs=1]
-layer at (31,187) size 108x108 clip at (35,191) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (183,187) size 108x108 clip at (187,191) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (335,187) size 108x108 clip at (339,191) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (487,187) size 108x108 clip at (491,191) size 100x100 scrollHeight 104
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/mask-with-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/mask-with-filter-expected.png
index da7d6c0..bfaa23e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/mask-with-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/mask-with-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.png
index 4e6f491c..ea3710c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.txt
deleted file mode 100644
index 3e86da1..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-inner-bleed-expected.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x356
-  LayoutBlockFlow {HTML} at (0,0) size 800x356
-    LayoutBlockFlow {BODY} at (8,8) size 784x340
-      LayoutTable {TABLE} at (0,0) size 610x340
-        LayoutTableSection {TBODY} at (0,0) size 610x340
-          LayoutTableRow {TR} at (0,2) size 610x155
-            LayoutTableCell {TD} at (2,2) size 150x155 [r=0 c=0 rs=1 cs=1]
-            LayoutTableCell {TD} at (154,2) size 150x155 [r=0 c=1 rs=1 cs=1]
-            LayoutTableCell {TD} at (306,2) size 150x155 [r=0 c=2 rs=1 cs=1]
-            LayoutTableCell {TD} at (458,2) size 150x155 [r=0 c=3 rs=1 cs=1]
-          LayoutTableRow {TR} at (0,316) size 610x22
-            LayoutTableCell {TD} at (2,316) size 150x22 [r=2 c=0 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x19
-                text run at (59,1) width 32: "PNG"
-            LayoutTableCell {TD} at (154,316) size 150x22 [r=2 c=1 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x19
-                text run at (59,1) width 32: "SVG"
-            LayoutTableCell {TD} at (306,316) size 150x22 [r=2 c=2 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x19
-                text run at (59,1) width 32: "PNG"
-            LayoutTableCell {TD} at (458,316) size 150x22 [r=2 c=3 rs=1 cs=1]
-              LayoutText {#text} at (59,1) size 32x19
-                text run at (59,1) width 32: "SVG"
-layer at (31,31) size 108x108 clip at (35,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (183,31) size 108x108 clip at (187,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (335,31) size 108x108 clip at (339,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (487,31) size 108x108 clip at (491,35) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (8,167) size 610x155
-  LayoutTableRow {TR} at (0,159) size 610x155
-    LayoutTableCell {TD} at (2,159) size 150x155 [r=1 c=0 rs=1 cs=1]
-    LayoutTableCell {TD} at (154,159) size 150x155 [r=1 c=1 rs=1 cs=1]
-    LayoutTableCell {TD} at (306,159) size 150x155 [r=1 c=2 rs=1 cs=1]
-    LayoutTableCell {TD} at (458,159) size 150x155 [r=1 c=3 rs=1 cs=1]
-layer at (31,188) size 108x108 clip at (35,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (183,188) size 108x108 clip at (187,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (335,188) size 108x108 clip at (339,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
-layer at (487,188) size 108x108 clip at (491,192) size 100x100 scrollHeight 105
-  LayoutBlockFlow {DIV} at (21,21) size 108x108 [bgcolor=#FF0000] [border: (4px solid #008000)]
-    LayoutImage {IMG} at (4,4) size 100x100
-    LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/transferFromImageBitmap.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/transferFromImageBitmap.html
new file mode 100644
index 0000000..05b3784
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/transferFromImageBitmap.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// This test examines the color managed ImageBitmapRenderingContext.
+//  - We first draw on 2D canvas with different color space and alpha
+//    properties.
+//  - Next, the canvas is used as a source image to create an ImageBitmap.
+//    Different colorSpaceConversion values are tested when creating the
+//    intermediate ImageBitmap object.
+//  - Next, ImageBitmap is transferred to an ImageBitmapRenderingContext.
+//  - Since we cannot read back pixels from ImageBitmapRenderingContext, we
+//    draw it to another 2D canvas and read back the pixels.
+//  - Finally, we compare the pixels read from the first 2D canvas with those
+//    read from the final 2D canvas. We expect them to match with some
+//     tolerance.
+
+function testPixels(actualPixels, expectedPixels, testScenario)
+{
+    var tolerance = 0;
+
+    // When using a linear gamma image bitmap as the intermediate image object
+    // for sRGB source canvas, {sRGB-> wide gamut -> sRGB} color conversion in
+    // Skia introduces some variance in color values. Hence, in this case we
+    // set the tolerance to 8 (6 is the max error observed on Linux for the used
+    // pixels). For a thorough investigation, please see:
+    // https://fiddle.skia.org/c/584fbc0b778a32a6cc2ea3ecbf2c6e8e
+    if (testScenario.colorSpace == "srgb" &&
+        testScenario.pixelFormat == "8-8-8-8" &&
+        ['linear-rgb', 'rec2020', 'p3'].indexOf(
+            testScenario.colorSpaceConversion) > -1)
+        tolerance = 8;
+
+    // Otherwise, if the source color space is wide gamut, we set the tolerance
+    // to 0.01.
+    else if (testScenario.pixelFormat == "float16")
+        tolerance = 0.01;
+
+    assert_array_approx_equals(actualPixels, expectedPixels, tolerance);
+}
+
+function generateFillStyle(red, green, blue, alpha) {
+    return "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
+}
+
+function generateExpectedResult(testScenario, canvas)
+{
+    var ctx = canvas.getContext('2d', {colorSpace: testScenario.colorSpace,
+                                       pixelFormat: testScenario.pixelFormat});
+    ctx.fillStyle = generateFillStyle(155, 27, 27, testScenario.alpha);
+    ctx.fillRect(0, 0, 1, 1);
+    ctx.fillStyle = generateFillStyle(27, 155, 27, testScenario.alpha);
+    ctx.fillRect(1, 0, 1, 1);
+    ctx.fillStyle = generateFillStyle(27, 27, 155, testScenario.alpha);
+    ctx.fillRect(0, 1, 1, 1);
+    ctx.fillStyle = generateFillStyle(27, 27, 27, testScenario.alpha);
+    ctx.fillRect(1, 1, 1, 1);
+    return ctx.getImageData(0, 0, 2, 2).dataUnion;
+}
+
+function generateTestName(testScenario) {
+    var str = "Testing ImageBitmapRenderingContext:" +
+              " Source color space: " + testScenario.colorSpace +
+              ", pixel format: " + testScenario.pixelFormat +
+              ", alpha: " + testScenario.alpha +
+              ", intermediate color space: " +
+              testScenario.colorSpaceConversion;
+    return str;
+}
+
+function runTransferFromImageBitmapTest(testScenario) {
+    var canvas = document.createElement("canvas");
+    canvas.width = 2;
+    canvas.height = 2;
+    var expectedPixels = generateExpectedResult(testScenario, canvas);
+
+    promise_test(function() {
+        var options = {colorSpaceConversion: testScenario.colorSpaceConversion};
+        var promise = createImageBitmap(canvas, options);
+        return Promise.all([promise]).then(([imagebitmap]) => {
+            var dstCanvas = document.createElement("canvas");
+            dstCanvas.width = 2;
+            dstCanvas.height = 2;
+            var dstCtx = dstCanvas.getContext('bitmaprenderer');
+            dstCtx.transferFromImageBitmap(imagebitmap);
+
+            // ImageBitmapRenderingContext does not have ImageData, so we draw
+            // it on another canvas and read back the data.
+            var finalCanvas = document.createElement("canvas");
+            finalCanvas.width = 2;
+            finalCanvas.height = 2;
+            var ctx = finalCanvas.getContext('2d',
+                {colorSpace: testScenario.colorSpace,
+                 pixelFormat: testScenario.pixelFormat});
+            ctx.drawImage(dstCanvas, 0, 0);
+            var actualPixels = ctx.getImageData(0, 0, 2, 2).dataUnion;
+            testPixels(actualPixels, expectedPixels, testScenario);
+        });
+       }, generateTestName(testScenario));
+}
+
+
+function runAllTests() {
+    var colorSpaces = [
+        {colorSpace: 'srgb', pixelFormat: '8-8-8-8'},
+        {colorSpace: 'srgb', pixelFormat: 'float16'},
+        {colorSpace: 'rec2020', pixelFormat: 'float16'},
+        {colorSpace: 'p3', pixelFormat: 'float16'}
+        ];
+    var alphaValues = [0.5, 1];
+    var colorSpaceConversions = [
+        'none', 'default', 'srgb', 'linear-rgb', 'rec2020', 'p3'];
+
+    var testScenarios = [];
+    for (var i = 0; i < colorSpaces.length; i++)
+        for (var j = 0; j < alphaValues.length; j++)
+            for (var k = 0; k < colorSpaceConversions.length; k++) {
+                var testScenario = {};
+                testScenario.colorSpace = colorSpaces[i].colorSpace;
+                testScenario.pixelFormat = colorSpaces[i].pixelFormat;
+                testScenario.alpha = alphaValues[j];
+                testScenario.colorSpaceConversion = colorSpaceConversions[k];
+                testScenarios.push(testScenario);
+            }
+
+    for (var i = 0; i < testScenarios.length; i++)
+        runTransferFromImageBitmapTest(testScenarios[i]);
+}
+
+runAllTests();
+
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 2735c3ea..53c56d4d 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1277,13 +1277,11 @@
     getter origin
     getter plugins
     getter pointerLockElement
-    getter preferredStylesheetSet
     getter readyState
     getter referrer
     getter rootElement
     getter scripts
     getter scrollingElement
-    getter selectedStylesheetSet
     getter styleSheets
     getter title
     getter visibilityState
@@ -1447,7 +1445,6 @@
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
     setter onwheel
-    setter selectedStylesheetSet
     setter title
     setter vlinkColor
     setter xmlStandalone
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dispose.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dispose.html
deleted file mode 100644
index adabe40..0000000
--- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline-dispose.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<title>Regression test to ensure detaching a ScrollTimeline shouldn't crash</title>
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-
-<script src="resources/animation-worklet-tests.js"></script>
-
-<style>
-#scroller {
-  overflow: auto;
-  height: 100px;
-  width: 100px;
-}
-
-#contents {
-  height: 1000px;
-  width: 100%;
-}
-</style>
-
-<div id="box"></div>
-<div id="scroller">
-  <div id="contents"></div>
-</div>
-
-<script>
-// This is a regression test for the crash seen when http://crrev.com/ddd9f0ee
-// landed. The root of the crash was assuming a WeakMember from a static object
-// would still be alive during a USING_PRE_FINALIZER method, which is not true.
-async_test(t => {
-  const box = document.getElementById('box');
-  const effect = new KeyframeEffect(box, null);
-
-  let scroller = document.getElementById('scroller');
-  let timeline = new ScrollTimeline({
-    scrollSource: scroller,
-    timeRange: 1000,
-    orientation: 'block'
-  });
-  // Creating the animation will cause the scroller to be registered as being
-  // used in an attached ScrollTimeline.
-  let animation = new WorkletAnimation('test_animator', effect, timeline, {});
-
-  // Now free up everything at once.
-  scroller.remove();
-  animation.cancel();
-  scroller = undefined;
-  timeline = undefined;
-  animation = undefined;
-
-  requestAnimationFrame(t.step_func_done(() => {
-    // Force GC - this shouldn't crash.
-    gc();
-  }));
-}, 'Disposing of an attached ScrollTimeline should not crash');
-</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html
index 2a63b1b..c96ed4e 100644
--- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html
@@ -16,6 +16,7 @@
   overflow: auto;
   height: 100px;
   width: 100px;
+  will-change: transform; /* force compositing */
 }
 
 #contents {
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/scrolling/README.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scrolling/README.txt
new file mode 100644
index 0000000..0df19af2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scrolling/README.txt
@@ -0,0 +1,3 @@
+# This suite runs the tests in fast/scrolling with a threaded compositor and
+# compositing sub-scrollers even if they'd lose LCD text.  See the
+# virtual_test_suites() method in tools/blinkpy/web_tests/port/base.py.
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 9ad512d..b18e177 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1600,14 +1600,12 @@
     getter plugins
     getter pointerLockElement
     getter policy
-    getter preferredStylesheetSet
     getter readyState
     getter referrer
     getter rootElement
     getter rootScroller
     getter scripts
     getter scrollingElement
-    getter selectedStylesheetSet
     getter styleSheets
     getter timeline
     getter title
@@ -1784,7 +1782,6 @@
     setter onwebkitfullscreenerror
     setter onwheel
     setter rootScroller
-    setter selectedStylesheetSet
     setter title
     setter vlinkColor
     setter xmlStandalone
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn
index b2d88aa..7d6b8d1 100644
--- a/third_party/blink/common/BUILD.gn
+++ b/third_party/blink/common/BUILD.gn
@@ -25,6 +25,7 @@
     "message_port/cloneable_message_struct_traits.cc",
     "message_port/cloneable_message_struct_traits.h",
     "message_port/message_port_channel.cc",
+    "message_port/string_message_codec.cc",
     "message_port/transferable_message.cc",
     "message_port/transferable_message_struct_traits.cc",
     "message_port/transferable_message_struct_traits.h",
@@ -64,6 +65,7 @@
   sources = [
     "device_memory/approximated_device_memory_unittest.cc",
     "feature_policy/feature_policy_unittest.cc",
+    "message_port/string_message_codec_unittest.cc",
     "mime_util/mime_util_unittest.cc",
     "origin_manifest/origin_manifest_unittest.cc",
     "origin_trials/trial_token_unittest.cc",
@@ -78,5 +80,7 @@
     "//testing/gtest",
     "//third_party/blink/public/common:headers",
     "//third_party/boringssl",
+    "//v8",
+    "//v8:v8_libplatform",
   ]
 }
diff --git a/third_party/blink/common/DEPS b/third_party/blink/common/DEPS
index 3308652..50d39c7 100644
--- a/third_party/blink/common/DEPS
+++ b/third_party/blink/common/DEPS
@@ -18,3 +18,6 @@
     "+third_party/blink/public/mojom",
     "+url",
 ]
+specific_include_rules = {
+  '.*unittest.?.cc': [ "+v8" ],
+}
diff --git a/content/browser/android/string_message_codec.cc b/third_party/blink/common/message_port/string_message_codec.cc
similarity index 94%
rename from content/browser/android/string_message_codec.cc
rename to third_party/blink/common/message_port/string_message_codec.cc
index 5303ac43..45f5e26 100644
--- a/content/browser/android/string_message_codec.cc
+++ b/third_party/blink/common/message_port/string_message_codec.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/android/string_message_codec.h"
+#include "third_party/blink/public/common/message_port/string_message_codec.h"
 
 #include <vector>
 
 #include "base/logging.h"
 
-namespace content {
+namespace blink {
 namespace {
 
 const uint32_t kVarIntShift = 7;
@@ -46,7 +46,8 @@
   }
 }
 
-void WriteBytes(const char* bytes, size_t num_bytes,
+void WriteBytes(const char* bytes,
+                size_t num_bytes,
                 std::vector<uint8_t>* buffer) {
   buffer->insert(buffer->end(), bytes, bytes + num_bytes);
 }
@@ -79,7 +80,7 @@
   return !(x & 0xFF00);
 }
 
-} // namespace
+}  // namespace
 
 std::vector<uint8_t> EncodeStringMessage(const base::string16& data) {
   std::vector<uint8_t> buffer;
@@ -142,4 +143,4 @@
   return false;
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/browser/android/string_message_codec_unittest.cc b/third_party/blink/common/message_port/string_message_codec_unittest.cc
similarity index 91%
rename from content/browser/android/string_message_codec_unittest.cc
rename to third_party/blink/common/message_port/string_message_codec_unittest.cc
index d32233e3..42435ca 100644
--- a/content/browser/android/string_message_codec_unittest.cc
+++ b/third_party/blink/common/message_port/string_message_codec_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/android/string_message_codec.h"
+#include "third_party/blink/public/common/message_port/string_message_codec.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "v8/include/v8.h"
 
-namespace content {
+namespace blink {
 namespace {
 
 base::string16 DecodeWithV8(const std::vector<uint8_t>& encoded) {
@@ -36,7 +36,7 @@
     v8::Local<v8::String> str = value->ToString(context).ToLocalChecked();
 
     result.resize(str->Length());
-    str->Write(&result[0], 0, result.size());
+    str->Write(reinterpret_cast<uint16_t*>(&result[0]), 0, result.size());
   }
   isolate->Dispose();
   delete params.array_buffer_allocator;
@@ -59,10 +59,10 @@
     v8::Local<v8::Context> context = v8::Context::New(isolate);
 
     v8::Local<v8::String> message_as_value =
-        v8::String::NewFromTwoByte(isolate,
-                                   message.data(),
-                                   v8::NewStringType::kNormal,
-                                   message.size()).ToLocalChecked();
+        v8::String::NewFromTwoByte(
+            isolate, reinterpret_cast<const uint16_t*>(message.data()),
+            v8::NewStringType::kNormal, message.size())
+            .ToLocalChecked();
 
     v8::ValueSerializer serializer(isolate);
     serializer.WriteHeader();
@@ -136,4 +136,4 @@
 }
 
 }  // namespace
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/common/test/run_all_unittests.cc b/third_party/blink/common/test/run_all_unittests.cc
index a85d337..aaa1df0 100644
--- a/third_party/blink/common/test/run_all_unittests.cc
+++ b/third_party/blink/common/test/run_all_unittests.cc
@@ -8,10 +8,18 @@
 
 #include "base/bind.h"
 #include "base/test/test_suite.h"
+#include "v8/include/libplatform/libplatform.h"
+#include "v8/include/v8.h"
 
 int main(int argc, char** argv) {
   base::TestSuite test_suite(argc, argv);
 
+  v8::V8::InitializeICUDefaultLocation(argv[0]);
+  v8::V8::InitializeExternalStartupData(argv[0]);
+  auto platform = base::WrapUnique(v8::platform::CreateDefaultPlatform());
+  v8::V8::InitializePlatform(platform.get());
+  v8::V8::Initialize();
+
   return base::LaunchUnitTests(
       argc, argv,
       base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 5f52eb9..f085dd9 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -328,7 +328,6 @@
     "platform/web_menu_source_type.h",
     "platform/web_mixed_content.h",
     "platform/web_mixed_content_context_type.h",
-    "platform/web_mock_clipboard.h",
     "platform/web_mouse_event.h",
     "platform/web_mouse_wheel_event.h",
     "platform/web_native_scroll_behavior.h",
@@ -382,8 +381,6 @@
     "platform/web_scrollbar_behavior.h",
     "platform/web_scrollbar_buttons_placement.h",
     "platform/web_scrollbar_overlay_color_theme.h",
-    "platform/web_scrollbar_theme_geometry.h",
-    "platform/web_scrollbar_theme_painter.h",
     "platform/web_security_origin.h",
     "platform/web_security_style.h",
     "platform/web_selection_bound.h",
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index ceff049..e354c4ca 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -41,6 +41,7 @@
     "frame/sandbox_flags.h",
     "message_port/cloneable_message.h",
     "message_port/message_port_channel.h",
+    "message_port/string_message_codec.h",
     "message_port/transferable_message.h",
     "mime_util/mime_util.h",
     "origin_manifest/origin_manifest.h",
diff --git a/content/browser/android/string_message_codec.h b/third_party/blink/public/common/message_port/string_message_codec.h
similarity index 69%
rename from content/browser/android/string_message_codec.h
rename to third_party/blink/public/common/message_port/string_message_codec.h
index a613f05..98a6615e 100644
--- a/content/browser/android/string_message_codec.h
+++ b/third_party/blink/public/common/message_port/string_message_codec.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_ANDROID_STRING_MESSAGE_CODEC_H_
-#define CONTENT_BROWSER_ANDROID_STRING_MESSAGE_CODEC_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_STRING_MESSAGE_CODEC_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_STRING_MESSAGE_CODEC_H_
 
 #include <vector>
 #include "base/strings/string16.h"
-#include "content/common/content_export.h"
+#include "third_party/blink/common/common_export.h"
 
-namespace content {
+namespace blink {
 
 // To support exposing HTML message ports to Java, it is necessary to be able
 // to encode and decode message data using the same serialization format as V8.
@@ -21,13 +21,13 @@
 // handle string messages and this serialization format is static, as it is a
 // format we currently persist to disk via IndexedDB.
 
-CONTENT_EXPORT std::vector<uint8_t> EncodeStringMessage(
+BLINK_COMMON_EXPORT std::vector<uint8_t> EncodeStringMessage(
     const base::string16& data);
 
-CONTENT_EXPORT bool DecodeStringMessage(
+BLINK_COMMON_EXPORT bool DecodeStringMessage(
     const std::vector<uint8_t>& encoded_data,
     base::string16* result);
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_BROWSER_ANDROID_STRING_MESSAGE_CODEC_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_STRING_MESSAGE_CODEC_H_
diff --git a/third_party/blink/public/mojom/use_counter/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
index f8abb73d..93d9d3d 100644
--- a/third_party/blink/public/mojom/use_counter/css_property_id.mojom
+++ b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-const int32 kMaximumCSSSampleId = 592;
+const int32 kMaximumCSSSampleId = 593;
 
 // This CSSSampleId represents page load for CSS histograms. It is recorded once
 // per page visit for each CSS histogram being logged on the blink side and the
diff --git a/third_party/blink/public/platform/web_compositor_support.h b/third_party/blink/public/platform/web_compositor_support.h
index 4dc25f9..d86c764 100644
--- a/third_party/blink/public/platform/web_compositor_support.h
+++ b/third_party/blink/public/platform/web_compositor_support.h
@@ -30,7 +30,6 @@
 #include "third_party/blink/public/platform/web_float_point.h"
 #include "third_party/blink/public/platform/web_layer_tree_view.h"
 #include "third_party/blink/public/platform/web_scrollbar.h"
-#include "third_party/blink/public/platform/web_scrollbar_theme_painter.h"
 
 #include <memory>
 
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 71480e2..3eee6102 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1686,9 +1686,6 @@
   kMicrophoneDisabledByFeaturePolicyEstimate = 2208,
   kCameraDisabledByFeaturePolicyEstimate = 2209,
   kMidiDisabledByFeaturePolicy = 2210,
-  kDocumentGetPreferredStylesheetSet = 2211,
-  kDocumentGetSelectedStylesheetSet = 2212,
-  kDocumentSetSelectedStylesheetSet = 2213,
   kGeolocationGetCurrentPosition = 2214,
   kGeolocationWatchPosition = 2215,
   kDataUriHasOctothorpe = 2216,
diff --git a/third_party/blink/public/platform/web_mock_clipboard.h b/third_party/blink/public/platform/web_mock_clipboard.h
deleted file mode 100644
index 7773402..0000000
--- a/third_party/blink/public/platform/web_mock_clipboard.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MOCK_CLIPBOARD_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MOCK_CLIPBOARD_H_
-
-#include "base/containers/span.h"
-#include "third_party/blink/public/platform/web_clipboard.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_image.h"
-
-namespace blink {
-
-// Provides convenience methods for retrieving data from the mock clipboard
-// used in layout and unit tests.
-class BLINK_PLATFORM_EXPORT WebMockClipboard : public WebClipboard {
- public:
-  virtual WebImage ReadRawImage(mojom::ClipboardBuffer) { return WebImage(); }
-
- protected:
-  // Convenience method for WebMockClipoard implementations to create a blob
-  // from bytes.
-  WebBlobInfo CreateBlobFromData(base::span<const uint8_t> data,
-                                 const WebString& mime_type);
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/public/platform/web_scrollbar.h b/third_party/blink/public/platform/web_scrollbar.h
index 73029e8..2900455 100644
--- a/third_party/blink/public/platform/web_scrollbar.h
+++ b/third_party/blink/public/platform/web_scrollbar.h
@@ -25,71 +25,13 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SCROLLBAR_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SCROLLBAR_H_
 
-#include "third_party/blink/public/platform/web_point.h"
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/platform/web_scrollbar_overlay_color_theme.h"
-#include "third_party/blink/public/platform/web_size.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
 namespace blink {
 
-// A const accessor interface for a WebKit scrollbar
-class BLINK_PLATFORM_EXPORT WebScrollbar {
+// TODO(jbroman): Clean up these, which are used elsewhere.
+class WebScrollbar {
  public:
   enum Orientation { kHorizontal, kVertical };
-
-  enum ScrollDirection { kScrollBackward, kScrollForward };
-
-  enum ScrollGranularity {
-    kScrollByLine,
-    kScrollByPage,
-    kScrollByDocument,
-    kScrollByPixel
-  };
-
-  enum ScrollbarControlSize { kRegularScrollbar, kSmallScrollbar };
-
-  enum ScrollbarPart {
-    kNoPart = 0,
-    kBackButtonStartPart = 1,
-    kForwardButtonStartPart = 1 << 1,
-    kBackTrackPart = 1 << 2,
-    kThumbPart = 1 << 3,
-    kForwardTrackPart = 1 << 4,
-    kBackButtonEndPart = 1 << 5,
-    kForwardButtonEndPart = 1 << 6,
-    kScrollbarBGPart = 1 << 7,
-    kTrackBGPart = 1 << 8,
-    kAllParts = 0xffffffff
-  };
-
   enum class ScrollingMode { kAuto, kAlwaysOff, kAlwaysOn, kLast = kAlwaysOn };
-
-  virtual ~WebScrollbar() = default;
-
-  // Return true if this is an overlay scrollbar.
-  virtual bool IsOverlay() const = 0;
-
-  // Gets the current value (i.e. position inside the region).
-  virtual int Value() const = 0;
-
-  virtual WebPoint Location() const = 0;
-  virtual WebSize Size() const = 0;
-  virtual bool Enabled() const = 0;
-  virtual int Maximum() const = 0;
-  virtual int TotalSize() const = 0;
-  virtual bool IsScrollableAreaActive() const = 0;
-  virtual bool HasTickmarks() const = 0;
-  virtual void GetTickmarks(WebVector<WebRect>& tickmarks) const = 0;
-  virtual ScrollbarControlSize GetControlSize() const = 0;
-  virtual ScrollbarPart PressedPart() const = 0;
-  virtual ScrollbarPart HoveredPart() const = 0;
-  virtual WebScrollbarOverlayColorTheme ScrollbarOverlayColorTheme() const = 0;
-  virtual bool IsCustomScrollbar() const = 0;
-  virtual Orientation GetOrientation() const = 0;
-  virtual bool IsLeftSideVerticalScrollbar() const = 0;
-  virtual float ElasticOverscroll() const = 0;
-  virtual void SetElasticOverscroll(float) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/platform/web_scrollbar_theme_geometry.h b/third_party/blink/public/platform/web_scrollbar_theme_geometry.h
deleted file mode 100644
index 94ac1c1..0000000
--- a/third_party/blink/public/platform/web_scrollbar_theme_geometry.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SCROLLBAR_THEME_GEOMETRY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SCROLLBAR_THEME_GEOMETRY_H_
-
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/platform/web_size.h"
-
-namespace blink {
-
-class WebScrollbar;
-
-class BLINK_PLATFORM_EXPORT WebScrollbarThemeGeometry {
- public:
-  virtual ~WebScrollbarThemeGeometry() = default;
-
-  virtual bool HasButtons(WebScrollbar*) = 0;
-  virtual bool HasThumb(WebScrollbar*) = 0;
-  virtual WebRect TrackRect(WebScrollbar*) = 0;
-  virtual WebRect ThumbRect(WebScrollbar*) = 0;
-  virtual WebRect BackButtonStartRect(WebScrollbar*) = 0;
-  virtual WebRect BackButtonEndRect(WebScrollbar*) = 0;
-  virtual WebRect ForwardButtonStartRect(WebScrollbar*) = 0;
-  virtual WebRect ForwardButtonEndRect(WebScrollbar*) = 0;
-  virtual WebSize NinePatchThumbCanvasSize(WebScrollbar*) = 0;
-  virtual WebRect NinePatchThumbAperture(WebScrollbar*) = 0;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/public/platform/web_scrollbar_theme_painter.h b/third_party/blink/public/platform/web_scrollbar_theme_painter.h
deleted file mode 100644
index e8aa55c..0000000
--- a/third_party/blink/public/platform/web_scrollbar_theme_painter.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SCROLLBAR_THEME_PAINTER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SCROLLBAR_THEME_PAINTER_H_
-
-#include "third_party/blink/public/platform/web_canvas.h"
-#include "third_party/blink/public/platform/web_private_ptr.h"
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/platform/web_size.h"
-
-namespace blink {
-
-class ScrollbarTheme;
-class Scrollbar;
-class WebScrollbar;
-
-class WebScrollbarThemePainter {
- public:
-  WebScrollbarThemePainter() : theme_(0), device_scale_factor_(1.0) {}
-  WebScrollbarThemePainter(const WebScrollbarThemePainter& painter) {
-    Assign(painter);
-  }
-  virtual ~WebScrollbarThemePainter() { Reset(); }
-  WebScrollbarThemePainter& operator=(const WebScrollbarThemePainter& painter) {
-    Assign(painter);
-    return *this;
-  }
-
-  BLINK_PLATFORM_EXPORT void Assign(const WebScrollbarThemePainter&);
-  BLINK_PLATFORM_EXPORT void Reset();
-
-  BLINK_PLATFORM_EXPORT void PaintScrollbarBackground(WebCanvas*,
-                                                      const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintTrackBackground(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintBackTrackPart(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintForwardTrackPart(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintBackButtonStart(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintBackButtonEnd(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintForwardButtonStart(WebCanvas*,
-                                                     const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintForwardButtonEnd(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintTickmarks(WebCanvas*, const WebRect&);
-  BLINK_PLATFORM_EXPORT void PaintThumb(WebCanvas*, const WebRect&);
-
-  // This opacity is applied on top of the content that is painted for the
-  // thumb.
-  BLINK_PLATFORM_EXPORT float ThumbOpacity() const;
-
-  BLINK_PLATFORM_EXPORT bool TrackNeedsRepaint() const;
-  BLINK_PLATFORM_EXPORT bool ThumbNeedsRepaint() const;
-
-  BLINK_PLATFORM_EXPORT bool UsesNinePatchThumbResource() const;
-
-#if INSIDE_BLINK
-  BLINK_PLATFORM_EXPORT WebScrollbarThemePainter(ScrollbarTheme&,
-                                                 Scrollbar&,
-                                                 float device_scale_factor);
-#endif
-
-  BLINK_PLATFORM_EXPORT float DeviceScaleFactor() const {
-    return device_scale_factor_;
-  }
-
- private:
-  // The theme is not owned by this class. It is assumed that the theme is a
-  // static pointer and its lifetime is essentially infinite. The functions
-  // called from the painter may not be thread-safe, so all calls must be made
-  // from the same thread that it is created on.
-  ScrollbarTheme* theme_;
-
-  // It is assumed that the constructor of this paint object is responsible
-  // for the lifetime of this scrollbar. The painter has to use the real
-  // scrollbar (and not a WebScrollbar wrapper) due to static_casts for
-  // LayoutScrollbar and pointer-based HashMap lookups for Lion scrollbars.
-  WebPrivatePtr<Scrollbar> scrollbar_;
-
-  float device_scale_factor_;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/public/platform/web_url_loader.h b/third_party/blink/public/platform/web_url_loader.h
index 5e0ec2b..ffe1180 100644
--- a/third_party/blink/public/platform/web_url_loader.h
+++ b/third_party/blink/public/platform/web_url_loader.h
@@ -56,7 +56,6 @@
   // will instead be redirected to a blob, which is passed out in
   // |downloaded_blob|.
   virtual void LoadSynchronously(
-      WebURLLoaderClient*,
       const WebURLRequest&,
       WebURLResponse&,
       base::Optional<WebURLError>&,
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index d5dc388..cd1aff4 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1633,7 +1633,6 @@
     "animation/keyframe_effect_model_test.cc",
     "animation/keyframe_effect_test.cc",
     "animation/property_handle_test.cc",
-    "animation/scroll_timeline_test.cc",
     "animation/timing_calculations_test.cc",
     "animation/timing_input_test.cc",
     "clipboard/data_object_test.cc",
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.cc b/third_party/blink/renderer/core/animation/scroll_timeline.cc
index bb4712b1..020e66b 100644
--- a/third_party/blink/renderer/core/animation/scroll_timeline.cc
+++ b/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -6,18 +6,11 @@
 
 #include "third_party/blink/renderer/core/dom/exception_code.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 
 namespace blink {
 
 namespace {
-using ActiveScrollTimelineSet = PersistentHeapHashCountedSet<WeakMember<Node>>;
-ActiveScrollTimelineSet& GetActiveScrollTimelineSet() {
-  DEFINE_STATIC_LOCAL(ActiveScrollTimelineSet, set, ());
-  return set;
-}
-
 bool StringToScrollDirection(String scroll_direction,
                              ScrollTimeline::ScrollDirection& result) {
   // TODO(smcgruer): Support 'auto' value.
@@ -53,17 +46,17 @@
     return nullptr;
   }
 
-  return new ScrollTimeline(scroll_source, orientation,
+  return new ScrollTimeline(document, scroll_source, orientation,
                             options.timeRange().GetAsDouble());
 }
 
-ScrollTimeline::ScrollTimeline(Element* scroll_source,
+ScrollTimeline::ScrollTimeline(const Document& document,
+                               Element* scroll_source,
                                ScrollDirection orientation,
                                double time_range)
     : scroll_source_(scroll_source),
       orientation_(orientation),
       time_range_(time_range) {
-  DCHECK(scroll_source_);
 }
 
 double ScrollTimeline::currentTime(bool& is_null) {
@@ -147,31 +140,9 @@
   result.SetDouble(time_range_);
 }
 
-void ScrollTimeline::AttachAnimation() {
-  GetActiveScrollTimelineSet().insert(scroll_source_);
-  scroll_source_->GetDocument()
-      .GetLayoutView()
-      ->Compositor()
-      ->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
-}
-
-void ScrollTimeline::DetachAnimation() {
-  GetActiveScrollTimelineSet().erase(scroll_source_);
-  scroll_source_->GetDocument()
-      .GetLayoutView()
-      ->Compositor()
-      ->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
-}
-
 void ScrollTimeline::Trace(blink::Visitor* visitor) {
   visitor->Trace(scroll_source_);
   AnimationTimeline::Trace(visitor);
 }
 
-bool ScrollTimeline::HasActiveScrollTimeline(Node* node) {
-  ActiveScrollTimelineSet& set = GetActiveScrollTimelineSet();
-  auto it = set.find(node);
-  return it != set.end() && it->value > 0;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.h b/third_party/blink/renderer/core/animation/scroll_timeline.h
index f33ef32..06ea148 100644
--- a/third_party/blink/renderer/core/animation/scroll_timeline.h
+++ b/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -46,22 +46,10 @@
 
   ScrollDirection GetOrientation() const { return orientation_; }
 
-  // Must be called when this ScrollTimeline is attached/unattached from an
-  // animation.
-  void AttachAnimation();
-  void DetachAnimation();
-
   void Trace(blink::Visitor*) override;
 
-  // For the AnimationWorklet origin trial, we need to automatically composite
-  // elements that are targets of ScrollTimelines (http://crbug.com/776533). We
-  // expose a static lookup method to enable this.
-  //
-  // TODO(crbug.com/839341): Remove once WorkletAnimations can run on main.
-  static bool HasActiveScrollTimeline(Node* node);
-
  private:
-  ScrollTimeline(Element*, ScrollDirection, double);
+  ScrollTimeline(const Document&, Element*, ScrollDirection, double);
 
   Member<Element> scroll_source_;
   ScrollDirection orientation_;
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline_test.cc b/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
deleted file mode 100644
index 195c6d5..0000000
--- a/third_party/blink/renderer/core/animation/scroll_timeline_test.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/exception_state.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
-
-namespace blink {
-
-using ScrollTimelineTest = RenderingTest;
-
-TEST_F(ScrollTimelineTest,
-       AttachingAndDetachingAnimationCausesCompositingUpdate) {
-  EnableCompositing();
-
-  SetBodyInnerHTML(R"HTML(
-    <style>#scroller { overflow: scroll; width: 100px; height: 100px; }</style>
-    <div id='scroller'></div>
-  )HTML");
-
-  LayoutBoxModelObject* scroller =
-      ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
-  ASSERT_TRUE(scroller);
-
-  // Invariant: the scroller is not composited by default.
-  EXPECT_EQ(DocumentLifecycle::kPaintClean,
-            GetDocument().Lifecycle().GetState());
-  EXPECT_EQ(kNotComposited, scroller->Layer()->GetCompositingState());
-
-  // Create the ScrollTimeline. This shouldn't cause the scrollSource to need
-  // compositing, as it isn't attached to any animation yet.
-  ScrollTimelineOptions options;
-  DoubleOrScrollTimelineAutoKeyword time_range =
-      DoubleOrScrollTimelineAutoKeyword::FromDouble(100);
-  options.setTimeRange(time_range);
-  options.setScrollSource(GetElementById("scroller"));
-  ScrollTimeline* scroll_timeline =
-      ScrollTimeline::Create(GetDocument(), options, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(DocumentLifecycle::kPaintClean,
-            GetDocument().Lifecycle().GetState());
-  EXPECT_EQ(kNotComposited, scroller->Layer()->GetCompositingState());
-
-  // Now attach an animation. This should require a compositing update.
-  scroll_timeline->AttachAnimation();
-
-  UpdateAllLifecyclePhases();
-  EXPECT_NE(scroller->Layer()->GetCompositingState(), kNotComposited);
-
-  // Now detach an animation. This should again require a compositing update.
-  scroll_timeline->DetachAnimation();
-
-  UpdateAllLifecyclePhases();
-  EXPECT_EQ(scroller->Layer()->GetCompositingState(), kNotComposited);
-}
-
-}  //  namespace blink
diff --git a/third_party/blink/renderer/core/css/CSSProperties.json5 b/third_party/blink/renderer/core/css/CSSProperties.json5
index 41b62d0..4871182 100644
--- a/third_party/blink/renderer/core/css/CSSProperties.json5
+++ b/third_party/blink/renderer/core/css/CSSProperties.json5
@@ -4200,6 +4200,12 @@
       is_descriptor: true,
       is_property: false,
     },
+    {
+      name: "viewport-fit",
+      is_descriptor: true,
+      is_property: false,
+      runtime_flag: "DisplayCutoutViewportFit",
+    },
 
     // Shorthands
     {
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser.cc b/third_party/blink/renderer/core/css/parser/css_property_parser.cc
index 7e67290..8a78b16 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser.cc
@@ -270,6 +270,8 @@
     case CSSPropertyOrientation:
       return ConsumeIdent<CSSValueAuto, CSSValuePortrait, CSSValueLandscape>(
           range);
+    case CSSPropertyViewportFit:
+      return ConsumeIdent<CSSValueAuto, CSSValueContain, CSSValueCover>(range);
     default:
       NOTREACHED();
       break;
@@ -325,6 +327,7 @@
                   *parsed_properties_);
       return true;
     }
+    case CSSPropertyViewportFit:
     case CSSPropertyMinWidth:
     case CSSPropertyMaxWidth:
     case CSSPropertyMinHeight:
diff --git a/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc b/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
index a10b48d..202cf64 100644
--- a/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.cc
@@ -52,6 +52,16 @@
 
 namespace blink {
 
+namespace {
+
+bool HasViewportFitProperty(const CSSPropertyValueSet* property_set) {
+  DCHECK(property_set);
+  return RuntimeEnabledFeatures::DisplayCutoutViewportFitEnabled() &&
+         property_set->HasProperty(CSSPropertyViewportFit);
+}
+
+}  // namespace
+
 ViewportStyleResolver::ViewportStyleResolver(Document& document)
     : document_(document) {
   DCHECK(document.GetFrame());
@@ -205,6 +215,8 @@
   description.min_height = ViewportLengthValue(CSSPropertyMinHeight);
   description.max_height = ViewportLengthValue(CSSPropertyMaxHeight);
   description.orientation = ViewportArgumentValue(CSSPropertyOrientation);
+  if (HasViewportFitProperty(property_set_))
+    description.SetViewportFit(ViewportFitValue());
 
   document_->SetViewportDescription(description);
 
@@ -310,6 +322,26 @@
   return result;
 }
 
+ViewportDescription::ViewportFit ViewportStyleResolver::ViewportFitValue()
+    const {
+  const CSSValue* value =
+      property_set_->GetPropertyCSSValue(CSSPropertyViewportFit);
+  if (value->IsIdentifierValue()) {
+    switch (ToCSSIdentifierValue(value)->GetValueID()) {
+      case CSSValueCover:
+        return ViewportDescription::ViewportFit::kCover;
+      case CSSValueContain:
+        return ViewportDescription::ViewportFit::kContain;
+      case CSSValueAuto:
+      default:
+        return ViewportDescription::ViewportFit::kAuto;
+    }
+  }
+
+  NOTREACHED();
+  return ViewportDescription::ViewportFit::kAuto;
+}
+
 void ViewportStyleResolver::InitialStyleChanged() {
   initial_style_ = nullptr;
   // We need to recollect if the initial font size changed and media queries
diff --git a/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h b/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h
index 74677cee..45a122d 100644
--- a/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/viewport_style_resolver.h
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/rule_set.h"
 #include "third_party/blink/renderer/core/css_property_names.h"
+#include "third_party/blink/renderer/core/dom/viewport_description.h"
 #include "third_party/blink/renderer/platform/length.h"
 
 namespace blink {
@@ -78,6 +79,7 @@
 
   float ViewportArgumentValue(CSSPropertyID) const;
   Length ViewportLengthValue(CSSPropertyID);
+  ViewportDescription::ViewportFit ViewportFitValue() const;
 
   Member<Document> document_;
   Member<MutableCSSPropertyValueSet> property_set_;
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 82c200b..905a986 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -1101,24 +1101,9 @@
   if (!preferred_stylesheet_set_name_.IsEmpty())
     return;
   preferred_stylesheet_set_name_ = name;
-  // TODO(futhark@chromium.org): Setting the selected set here is wrong if the
-  // set has been previously set by through Document.selectedStylesheetSet. Our
-  // current implementation ignores the effect of Document.selectedStylesheetSet
-  // and either only collects persistent style, or additionally preferred
-  // style when present.
-  selected_stylesheet_set_name_ = name;
   MarkDocumentDirty();
 }
 
-void StyleEngine::SetSelectedStylesheetSetName(const String& name) {
-  selected_stylesheet_set_name_ = name;
-  // TODO(futhark@chromium.org): Setting Document.selectedStylesheetSet
-  // currently has no other effect than the ability to read back the set value
-  // using the same api. If it did have an effect, we should have marked the
-  // document scope dirty and triggered an update of the active stylesheets
-  // from here.
-}
-
 void StyleEngine::SetHttpDefaultStyle(const String& content) {
   if (!content.IsEmpty())
     SetPreferredStylesheetSetNameIfNotSet(content);
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index e0246d2..4c99c81 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -155,11 +155,7 @@
   String PreferredStylesheetSetName() const {
     return preferred_stylesheet_set_name_;
   }
-  String SelectedStylesheetSetName() const {
-    return selected_stylesheet_set_name_;
-  }
   void SetPreferredStylesheetSetNameIfNotSet(const String&);
-  void SetSelectedStylesheetSetName(const String&);
   void SetHttpDefaultStyle(const String&);
 
   void AddPendingSheet(StyleEngineContext&);
@@ -434,7 +430,6 @@
   TreeOrderedList tree_boundary_crossing_scopes_;
 
   String preferred_stylesheet_set_name_;
-  String selected_stylesheet_set_name_;
 
   bool uses_rem_units_ = false;
   bool ignore_pending_stylesheets_ = false;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 091955aa..db31d08 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -4325,20 +4325,6 @@
   return *style_sheet_list_;
 }
 
-String Document::preferredStylesheetSet() const {
-  return style_engine_->PreferredStylesheetSetName();
-}
-
-String Document::selectedStylesheetSet() const {
-  UseCounter::Count(*this, WebFeature::kDocumentGetSelectedStylesheetSet);
-  return style_engine_->SelectedStylesheetSetName();
-}
-
-void Document::setSelectedStylesheetSet(const String& a_string) {
-  UseCounter::Count(*this, WebFeature::kDocumentSetSelectedStylesheetSet);
-  GetStyleEngine().SetSelectedStylesheetSetName(a_string);
-}
-
 void Document::EvaluateMediaQueryListIfNeeded() {
   if (!evaluate_media_queries_on_style_recalc_)
     return;
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index d7455a1..f17f46f 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -748,14 +748,6 @@
                                                         const LayoutPoint&,
                                                         const WebMouseEvent&);
 
-  /* Newly proposed CSS3 mechanism for selecting alternate
-       stylesheets using the DOM. May be subject to change as
-       spec matures. - dwh
-    */
-  String preferredStylesheetSet() const;
-  String selectedStylesheetSet() const;
-  void setSelectedStylesheetSet(const String&);
-
   bool SetFocusedElement(Element*, const FocusParams&);
   void ClearFocusedElement();
   Element* FocusedElement() const { return focused_element_.Get(); }
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl
index 6352393..a51ccaf 100644
--- a/third_party/blink/renderer/core/dom/document.idl
+++ b/third_party/blink/renderer/core/dom/document.idl
@@ -159,11 +159,6 @@
 
     [SameObject, MeasureAs=DocumentAll] readonly attribute HTMLAllCollection all;
 
-    // CSS Object Model (CSSOM)
-    // https://drafts.csswg.org/cssom/#extensions-to-the-document-interface
-    attribute DOMString? selectedStylesheetSet;
-    [MeasureAs=DocumentGetPreferredStylesheetSet] readonly attribute DOMString? preferredStylesheetSet;
-
     [Affects=Nothing] readonly attribute Element? scrollingElement;
 
     // Pointer Lock
diff --git a/third_party/blink/renderer/core/dom/document_test.cc b/third_party/blink/renderer/core/dom/document_test.cc
index 0226714..94fa217 100644
--- a/third_party/blink/renderer/core/dom/document_test.cc
+++ b/third_party/blink/renderer/core/dom/document_test.cc
@@ -1061,4 +1061,123 @@
   EXPECT_EQ(GetDocument().ElementFromPoint(1, 12), GetDocument().body());
 }
 
+/**
+ * Tests for viewport-fit propagation.
+ */
+
+class ViewportFitDocumentTest : public DocumentTest {
+ public:
+  void SetUp() override {
+    DocumentTest::SetUp();
+
+    RuntimeEnabledFeatures::SetDisplayCutoutViewportFitEnabled(true);
+    GetDocument().GetSettings()->SetViewportMetaEnabled(true);
+  }
+};
+
+// Test both meta and @viewport present but no viewport-fit.
+TEST_F(ViewportFitDocumentTest, MetaCSSViewportButNoFit) {
+  SetHtmlInnerHTML(
+      "<style>@viewport { min-width: 100px; }</style>"
+      "<meta name='viewport' content='initial-scale=1'>");
+
+  EXPECT_EQ(ViewportDescription::ViewportFit::kAuto,
+            GetDocument().GetViewportDescription().GetViewportFit());
+}
+
+// Test @viewport present but no viewport-fit.
+TEST_F(ViewportFitDocumentTest, CSSViewportButNoFit) {
+  SetHtmlInnerHTML("<style>@viewport { min-width: 100px; }</style>");
+
+  EXPECT_EQ(ViewportDescription::ViewportFit::kAuto,
+            GetDocument().GetViewportDescription().GetViewportFit());
+}
+
+// Test meta viewport present but no viewport-fit.
+TEST_F(ViewportFitDocumentTest, MetaViewportButNoFit) {
+  SetHtmlInnerHTML("<meta name='viewport' content='initial-scale=1'>");
+
+  EXPECT_EQ(ViewportDescription::ViewportFit::kAuto,
+            GetDocument().GetViewportDescription().GetViewportFit());
+}
+
+// This is a test case for testing a combination of viewport-fit meta value,
+// viewport CSS value and the expected outcome.
+using ViewportTestCase =
+    std::tuple<const char*, const char*, ViewportDescription::ViewportFit>;
+
+class ParameterizedViewportFitDocumentTest
+    : public ViewportFitDocumentTest,
+      public testing::WithParamInterface<ViewportTestCase> {
+ protected:
+  void LoadTestHTML() {
+    const char* kMetaValue = std::get<0>(GetParam());
+    const char* kCSSValue = std::get<1>(GetParam());
+    StringBuilder html;
+
+    if (kCSSValue) {
+      html.Append("<style>@viewport { viewport-fit: ");
+      html.Append(kCSSValue);
+      html.Append("; }</style>");
+    }
+
+    if (kMetaValue) {
+      html.Append("<meta name='viewport' content='viewport-fit=");
+      html.Append(kMetaValue);
+      html.Append("'>");
+    }
+
+    GetDocument().documentElement()->SetInnerHTMLFromString(html.ToString());
+    GetDocument().View()->UpdateAllLifecyclePhases();
+  }
+};
+
+TEST_P(ParameterizedViewportFitDocumentTest, EffectiveViewportFit) {
+  LoadTestHTML();
+  EXPECT_EQ(std::get<2>(GetParam()),
+            GetDocument().GetViewportDescription().GetViewportFit());
+}
+
+INSTANTIATE_TEST_CASE_P(
+    All,
+    ParameterizedViewportFitDocumentTest,
+    testing::Values(
+        // Test the default case.
+        ViewportTestCase(nullptr,
+                         nullptr,
+                         ViewportDescription::ViewportFit::kAuto),
+        // Test the different values set through CSS.
+        ViewportTestCase(nullptr,
+                         "auto",
+                         ViewportDescription::ViewportFit::kAuto),
+        ViewportTestCase(nullptr,
+                         "contain",
+                         ViewportDescription::ViewportFit::kContain),
+        ViewportTestCase(nullptr,
+                         "cover",
+                         ViewportDescription::ViewportFit::kCover),
+        ViewportTestCase(nullptr,
+                         "invalid",
+                         ViewportDescription::ViewportFit::kAuto),
+        // Test the different values set through the meta tag.
+        ViewportTestCase("auto",
+                         nullptr,
+                         ViewportDescription::ViewportFit::kAuto),
+        ViewportTestCase("contain",
+                         nullptr,
+                         ViewportDescription::ViewportFit::kContain),
+        ViewportTestCase("cover",
+                         nullptr,
+                         ViewportDescription::ViewportFit::kCover),
+        ViewportTestCase("invalid",
+                         nullptr,
+                         ViewportDescription::ViewportFit::kAuto),
+        // Test that the CSS should override the meta tag.
+        ViewportTestCase("cover",
+                         "auto",
+                         ViewportDescription::ViewportFit::kAuto),
+        ViewportTestCase("cover",
+                         "contain",
+                         ViewportDescription::ViewportFit::kContain)));
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/viewport_description.h b/third_party/blink/renderer/core/dom/viewport_description.h
index 44b0281..5dacc0f 100644
--- a/third_party/blink/renderer/core/dom/viewport_description.h
+++ b/third_party/blink/renderer/core/dom/viewport_description.h
@@ -29,6 +29,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_VIEWPORT_DESCRIPTION_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_VIEWPORT_DESCRIPTION_H_
 
+#include "base/optional.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/page_scale_constraints.h"
 #include "third_party/blink/renderer/platform/geometry/float_size.h"
@@ -132,7 +133,10 @@
   bool max_zoom_is_explicit;
   bool user_zoom_is_explicit;
 
-  ViewportFit viewport_fit = ViewportFit::kAuto;
+  ViewportFit GetViewportFit() const {
+    return viewport_fit_.value_or(ViewportFit::kAuto);
+  }
+  void SetViewportFit(ViewportFit value) { viewport_fit_ = value; }
 
   bool operator==(const ViewportDescription& other) const {
     // Used for figuring out whether to reset the viewport or not,
@@ -148,7 +152,7 @@
            min_zoom_is_explicit == other.min_zoom_is_explicit &&
            max_zoom_is_explicit == other.max_zoom_is_explicit &&
            user_zoom_is_explicit == other.user_zoom_is_explicit &&
-           viewport_fit == other.viewport_fit;
+           viewport_fit_ == other.viewport_fit_;
   }
 
   bool operator!=(const ViewportDescription& other) const {
@@ -172,6 +176,8 @@
   static float ResolveViewportLength(const Length&,
                                      const FloatSize& initial_viewport_size,
                                      Direction);
+
+  base::Optional<ViewportFit> viewport_fit_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 41407a51b..a296689 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -50,7 +50,6 @@
 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
 #include "third_party/blink/public/platform/web_float_rect.h"
 #include "third_party/blink/public/platform/web_keyboard_event.h"
-#include "third_party/blink/public/platform/web_mock_clipboard.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_thread.h"
 #include "third_party/blink/public/platform/web_url.h"
@@ -11232,57 +11231,6 @@
   helper.Reset();
 }
 
-TEST_P(ParameterizedWebFrameTest, CopyImageAt) {
-  std::string url = base_url_ + "canvas-copy-image.html";
-  RegisterMockedURLLoadFromBase(base_url_, "canvas-copy-image.html");
-
-  FrameTestHelpers::WebViewHelper helper;
-  WebViewImpl* web_view = helper.InitializeAndLoad(url);
-  web_view->Resize(WebSize(400, 400));
-
-  uint64_t sequence = Platform::Current()->Clipboard()->SequenceNumber(
-      mojom::ClipboardBuffer::kStandard);
-
-  WebLocalFrame* local_frame = web_view->MainFrameImpl();
-  local_frame->CopyImageAt(WebPoint(50, 50));
-
-  EXPECT_NE(sequence, Platform::Current()->Clipboard()->SequenceNumber(
-                          mojom::ClipboardBuffer::kStandard));
-
-  WebImage image =
-      static_cast<WebMockClipboard*>(Platform::Current()->Clipboard())
-          ->ReadRawImage(mojom::ClipboardBuffer::kStandard);
-
-  EXPECT_EQ(SkColorSetARGB(255, 255, 0, 0), image.GetSkBitmap().getColor(0, 0));
-}
-
-TEST_P(ParameterizedWebFrameTest, CopyImageAtWithPinchZoom) {
-  std::string url = base_url_ + "canvas-copy-image.html";
-  RegisterMockedURLLoadFromBase(base_url_, "canvas-copy-image.html");
-
-  FrameTestHelpers::WebViewHelper helper;
-  WebViewImpl* web_view = helper.InitializeAndLoad(url);
-  web_view->Resize(WebSize(400, 400));
-  web_view->UpdateAllLifecyclePhases();
-  web_view->SetPageScaleFactor(2);
-  web_view->SetVisualViewportOffset(WebFloatPoint(200, 200));
-
-  uint64_t sequence = Platform::Current()->Clipboard()->SequenceNumber(
-      mojom::ClipboardBuffer::kStandard);
-
-  WebLocalFrame* local_frame = web_view->MainFrameImpl();
-  local_frame->CopyImageAt(WebPoint(0, 0));
-
-  EXPECT_NE(sequence, Platform::Current()->Clipboard()->SequenceNumber(
-                          mojom::ClipboardBuffer::kStandard));
-
-  WebImage image =
-      static_cast<WebMockClipboard*>(Platform::Current()->Clipboard())
-          ->ReadRawImage(mojom::ClipboardBuffer::kStandard);
-
-  EXPECT_EQ(SkColorSetARGB(255, 255, 0, 0), image.GetSkBitmap().getColor(0, 0));
-}
-
 TEST_P(ParameterizedWebFrameTest, CopyImageWithImageMap) {
   SaveImageFromDataURLWebFrameClient client;
 
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
index 440fe27..08e8de5 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -247,13 +247,16 @@
 }
 
 WebString ReadClipboard() {
+  // Run all tasks in a message loop to allow asynchronous clipboard writing
+  // to happen before reading from it synchronously.
+  test::RunPendingTasks();
   return Platform::Current()->Clipboard()->ReadPlainText(
       mojom::ClipboardBuffer::kStandard);
 }
 
 void ClearClipboardBuffer() {
-  Platform::Current()->Clipboard()->WritePlainText(WebString());
-  EXPECT_EQ(WebString(), ReadClipboard());
+  Platform::Current()->Clipboard()->WritePlainText(WebString(""));
+  EXPECT_EQ(WebString(""), ReadClipboard());
 }
 
 void CreateAndHandleKeyboardEvent(WebElement* plugin_container_one_element,
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 3b8e633..afc8278e 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -50,7 +50,6 @@
 #include "third_party/blink/public/platform/web_input_event.h"
 #include "third_party/blink/public/platform/web_keyboard_event.h"
 #include "third_party/blink/public/platform/web_layer_tree_view.h"
-#include "third_party/blink/public/platform/web_mock_clipboard.h"
 #include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_thread.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 66b7e9b..025d199c 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2767,7 +2767,7 @@
   else
     contents_size = ContentsSize();
 
-  IntSize visible_content_size = VisibleContentRect().Size();
+  IntSize visible_content_size = VisibleContentSize();
   if (contents_size.Height() <= visible_content_size.Height() &&
       contents_size.Width() <= visible_content_size.Width())
     return kNotScrollableNoOverflow;
@@ -4459,7 +4459,7 @@
 
   // If no scrollbars are present, the content may still be scrollable.
   if (!scrollbar) {
-    IntSize scroll_size = ContentsSize() - VisibleContentRect().Size();
+    IntSize scroll_size = ContentsSize() - VisibleContentSize();
     scroll_size.ClampNegativeToZero();
     return orientation == kHorizontalScrollbar ? scroll_size.Width()
                                                : scroll_size.Height();
@@ -4585,7 +4585,7 @@
   if (HasOverlayScrollbars())
     return;
 
-  IntSize full_visible_size = VisibleContentRect(kIncludeScrollbars).Size();
+  IntSize full_visible_size = VisibleContentSize(kIncludeScrollbars);
 
   bool attempt_to_remove_scrollbars =
       (option == kFirstPass && doc_size.Width() <= full_visible_size.Width() &&
diff --git a/third_party/blink/renderer/core/frame/use_counter.cc b/third_party/blink/renderer/core/frame/use_counter.cc
index f52f81f..27709ed 100644
--- a/third_party/blink/renderer/core/frame/use_counter.cc
+++ b/third_party/blink/renderer/core/frame/use_counter.cc
@@ -1136,6 +1136,8 @@
       return 591;
     case CSSPropertyGap:
       return 592;
+    case CSSPropertyViewportFit:
+      return 593;
     // 1. Add new features above this line (don't change the assigned numbers of
     // the existing items).
     // 2. Update kMaximumCSSSampleId (defined in
diff --git a/third_party/blink/renderer/core/html/html_meta_element.cc b/third_party/blink/renderer/core/html/html_meta_element.cc
index 6dfa9b9a..f8d660b 100644
--- a/third_party/blink/renderer/core/html/html_meta_element.cc
+++ b/third_party/blink/renderer/core/html/html_meta_element.cc
@@ -368,8 +368,8 @@
   } else if (key_string == "viewport-fit") {
     if (RuntimeEnabledFeatures::DisplayCutoutViewportFitEnabled()) {
       bool unknown_value = false;
-      description->viewport_fit =
-          ParseViewportFitValueAsEnum(unknown_value, value_string);
+      description->SetViewportFit(
+          ParseViewportFitValueAsEnum(unknown_value, value_string));
 
       // If we got an unknown value then report a warning.
       if (unknown_value) {
@@ -451,6 +451,7 @@
     description.min_zoom = std::min(description.min_zoom, float(5));
   }
 }
+
 void HTMLMetaElement::ProcessViewportContentAttribute(
     const String& content,
     ViewportDescription::Type origin) {
diff --git a/third_party/blink/renderer/core/html/html_meta_element_test.cc b/third_party/blink/renderer/core/html/html_meta_element_test.cc
index 7f14a0a..bca197d 100644
--- a/third_party/blink/renderer/core/html/html_meta_element_test.cc
+++ b/third_party/blink/renderer/core/html/html_meta_element_test.cc
@@ -24,7 +24,7 @@
   ViewportDescription::ViewportFit LoadTestPageAndReturnViewportFit(
       const String& value) {
     LoadTestPageWithViewportFitValue(value);
-    return GetDocument().GetViewportDescription().viewport_fit;
+    return GetDocument().GetViewportDescription().GetViewportFit();
   }
 
  private:
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn
index 93f5ae5..8cc67ac 100644
--- a/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -282,6 +282,8 @@
     "multi_column_fragmentainer_group.h",
     "ng/exclusions/ng_exclusion_space.cc",
     "ng/exclusions/ng_exclusion_space.h",
+    "ng/exclusions/ng_layout_opportunity.h",
+    "ng/exclusions/ng_line_layout_opportunity.h",
     "ng/geometry/ng_bfc_offset.cc",
     "ng/geometry/ng_bfc_offset.h",
     "ng/geometry/ng_bfc_rect.cc",
@@ -290,7 +292,6 @@
     "ng/geometry/ng_border_edges.h",
     "ng/geometry/ng_box_strut.cc",
     "ng/geometry/ng_box_strut.h",
-    "ng/geometry/ng_edge.h",
     "ng/geometry/ng_logical_offset.cc",
     "ng/geometry/ng_logical_offset.h",
     "ng/geometry/ng_logical_rect.cc",
diff --git a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
index 0b50205..b948bc2 100644
--- a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
+++ b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -1491,7 +1491,11 @@
   bool check_for_break = auto_wrap_;
   if (width_.CommittedWidth() && !width_.FitsOnLine() &&
       line_break_.GetLineLayoutItem() && curr_ws_ == EWhiteSpace::kNowrap) {
-    if (width_.FitsOnLine(0, kExcludeWhitespace)) {
+    // If this nowrap item fits but its trailing spaces does not, and if the
+    // next item is auto-wrap, break before the next item.
+    // TODO(kojii): This case should be handled when we read next item.
+    if (width_.FitsOnLine(0, kExcludeWhitespace) &&
+        (!next_object_ || next_object_.StyleRef().AutoWrap())) {
       width_.Commit();
       line_break_.MoveToStartOf(next_object_);
     }
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h
index 87e23b39..7516573 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h
@@ -10,6 +10,11 @@
 
 namespace blink {
 
+// This struct represents an 2D-area where a NGFragment can fit within the
+// exclusion space. A layout opportunity is produced by the exclusion space by
+// calling FindLayoutOpportunity, or AllLayoutOpportunities.
+//
+// Its coordinates are relative to the BFC.
 struct CORE_EXPORT NGLayoutOpportunity {
   NGLayoutOpportunity()
       : rect(NGBfcOffset(LayoutUnit::Min(), LayoutUnit::Min()),
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h b/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
new file mode 100644
index 0000000..ee9f8b1
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+// This struct represents a 1D-area where a line can fit. It is only used for
+// representing the inline size.
+struct CORE_EXPORT NGLineLayoutOpportunity {
+  STACK_ALLOCATED();
+
+  NGLineLayoutOpportunity() {}
+  NGLineLayoutOpportunity(LayoutUnit inline_size)
+      : line_right_offset(inline_size), float_line_right_offset(inline_size) {}
+  NGLineLayoutOpportunity(LayoutUnit line_left_offset,
+                          LayoutUnit line_right_offset,
+                          LayoutUnit float_line_left_offset,
+                          LayoutUnit float_line_right_offset,
+                          LayoutUnit bfc_block_offset,
+                          LayoutUnit line_block_size)
+      : line_left_offset(line_left_offset),
+        line_right_offset(line_right_offset),
+        float_line_left_offset(float_line_left_offset),
+        float_line_right_offset(float_line_right_offset),
+        bfc_block_offset(bfc_block_offset),
+        line_block_size(line_block_size) {}
+
+  // The available inline-size of the line, taking shapes into account. Both
+  // offsets are relative to the BFC coordinate system.
+  LayoutUnit line_left_offset;
+  LayoutUnit line_right_offset;
+
+  // The available inline-size of the line *for floats*. This is the same size
+  // as the layout opportunity which generated this object. Both offsets are
+  // relative to the BFC coordinate system.
+  LayoutUnit float_line_left_offset;
+  LayoutUnit float_line_right_offset;
+
+  LayoutUnit bfc_block_offset;
+
+  // The block-size this line layout opportunity was created with. Should
+  // *only* be used for re-querying for a new line layout opportunity with the
+  // same block-size.
+  LayoutUnit line_block_size;
+
+  LayoutUnit AvailableInlineSize() const {
+    DCHECK_GE(line_right_offset, line_left_offset);
+    return line_right_offset - line_left_offset;
+  }
+
+  LayoutUnit AvailableFloatInlineSize() const {
+    DCHECK_GE(float_line_right_offset, float_line_left_offset);
+    return float_line_right_offset - float_line_left_offset;
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h
deleted file mode 100644
index e68fec2..0000000
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h
+++ /dev/null
@@ -1,21 +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 NGEdge_h
-#define NGEdge_h
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
-
-namespace blink {
-
-// Struct to represent a simple edge that has start and end.
-struct CORE_EXPORT NGEdge {
-  LayoutUnit start;
-  LayoutUnit end;
-};
-
-}  // namespace blink
-
-#endif  // NGEdge_h
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index f2c0b8c..9e9bc4a 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -618,6 +618,11 @@
     exclusion_space =
         std::make_unique<NGExclusionSpace>(*initial_exclusion_space);
 
+    NGLineLayoutOpportunity line_opportunity(
+        opportunity.rect.LineStartOffset(), opportunity.rect.LineEndOffset(),
+        opportunity.rect.LineStartOffset(), opportunity.rect.LineEndOffset(),
+        opportunity.rect.BlockStartOffset(), LayoutUnit());
+
     NGLineInfo line_info;
     NGLineBreaker line_breaker(
         Node(), NGLineBreakerMode::kContent, constraint_space_,
@@ -626,14 +631,14 @@
 
     // TODO(ikilpatrick): Does this always succeed when we aren't an empty
     // inline?
-    if (!line_breaker.NextLine(opportunity, &line_info))
+    if (!line_breaker.NextLine(line_opportunity, &line_info))
       break;
 
     // If this fragment will be larger than the inline-size of the opportunity,
     // *and* the opportunity is smaller than the available inline-size, and the
     // container autowraps, continue to the next opportunity.
-    if (line_info.Width() > opportunity.rect.InlineSize() &&
-        opportunity.rect.InlineSize() !=
+    if (line_info.Width() > line_opportunity.AvailableInlineSize() &&
+        line_opportunity.AvailableInlineSize() !=
             ConstraintSpace().AvailableSize().inline_size &&
         Node().Style().AutoWrap())
       continue;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index fe87e49f..595d60c 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -596,8 +596,7 @@
   scoped_refptr<NGInlineBreakToken> break_token;
   NGLineInfo line_info;
   NGExclusionSpace empty_exclusion_space;
-  NGLayoutOpportunity opportunity(NGBfcRect(
-      NGBfcOffset(), NGBfcOffset(available_inline_size, LayoutUnit::Max())));
+  NGLineLayoutOpportunity line_opportunity(available_inline_size);
   LayoutUnit result;
   LayoutUnit previous_floats_inline_size =
       input.float_left_inline_size + input.float_right_inline_size;
@@ -608,7 +607,7 @@
                                &unpositioned_floats,
                                nullptr /* container_builder */,
                                &empty_exclusion_space, 0u, break_token.get());
-    if (!line_breaker.NextLine(opportunity, &line_info))
+    if (!line_breaker.NextLine(line_opportunity, &line_info))
       break;
 
     break_token = line_breaker.CreateBreakToken(line_info, nullptr);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 76fa8e0..e659d97 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -153,8 +153,9 @@
 }
 
 // Initialize internal states for the next line.
-void NGLineBreaker::PrepareNextLine(const NGLayoutOpportunity& opportunity,
-                                    NGLineInfo* line_info) {
+void NGLineBreaker::PrepareNextLine(
+    const NGLineLayoutOpportunity& line_opportunity,
+    NGLineInfo* line_info) {
   NGInlineItemResults* item_results = &line_info->Results();
   item_results->clear();
   line_info->SetStartOffset(offset_);
@@ -177,17 +178,12 @@
   // regardless of 'text-indent'.
   line_.position = line_info->TextIndent();
 
-  line_.opportunity = opportunity;
-  line_.line_left_bfc_offset = opportunity.rect.LineStartOffset();
-  line_.line_right_bfc_offset = opportunity.rect.LineEndOffset();
-  bfc_block_offset_ = opportunity.rect.BlockStartOffset();
+  line_.line_opportunity = line_opportunity;
 }
 
-bool NGLineBreaker::NextLine(const NGLayoutOpportunity& opportunity,
+bool NGLineBreaker::NextLine(const NGLineLayoutOpportunity& line_opportunity,
                              NGLineInfo* line_info) {
-  bfc_block_offset_ = constraint_space_.BfcOffset().block_offset;
-
-  PrepareNextLine(opportunity, line_info);
+  PrepareNextLine(line_opportunity, line_info);
   BreakLine(line_info);
 
   if (line_info->Results().IsEmpty())
@@ -294,14 +290,14 @@
 }
 
 void NGLineBreaker::ComputeLineLocation(NGLineInfo* line_info) const {
-  LayoutUnit bfc_line_offset = line_.line_left_bfc_offset;
+  LayoutUnit bfc_line_offset = line_.line_opportunity.line_left_offset;
   LayoutUnit available_width = line_.AvailableWidth();
 
   // Negative margins can make the position negative, but the inline size is
   // always positive or 0.
-  line_info->SetLineBfcOffset({bfc_line_offset, bfc_block_offset_},
-                              available_width,
-                              line_.position.ClampNegativeToZero());
+  line_info->SetLineBfcOffset(
+      {bfc_line_offset, line_.line_opportunity.bfc_block_offset},
+      available_width, line_.position.ClampNegativeToZero());
 }
 
 NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
@@ -397,7 +393,7 @@
   //   * If offset == item.EndOffset(): the break opportunity at the end fits,
   //     or the first break opportunity is beyond the end.
   //     There may be room for more characters.
-  // * If width > available_width: The first break opporunity does not fit.
+  // * If width > available_width: The first break opportunity does not fit.
   //   offset is the first break opportunity, either inside, at the end, or
   //   beyond the end.
   if (item_result->end_offset < item.EndOffset()) {
@@ -643,8 +639,6 @@
 // We have this check if there are already UnpositionedFloats as we aren't
 // allowed to position a float "above" another float which has come before us
 // in the document.
-//
-// TODO(glebl): Add the support of clearance for inline floats.
 void NGLineBreaker::HandleFloat(const NGInlineItem& item,
                                 NGLineInfo* line_info,
                                 NGInlineItemResult* item_result) {
@@ -691,6 +685,8 @@
        margins.InlineSum())
           .ClampNegativeToZero();
 
+  LayoutUnit bfc_block_offset = line_.line_opportunity.bfc_block_offset;
+
   // The float should be positioned after the current line if:
   //  - It can't fit.
   //  - It will be moved down due to block-start edge alignment.
@@ -700,9 +696,9 @@
   //    the line breaker has run).
   bool float_after_line =
       !line_.CanFit(inline_margin_size) ||
-      exclusion_space_->LastFloatBlockStart() > bfc_block_offset_ ||
+      exclusion_space_->LastFloatBlockStart() > bfc_block_offset ||
       exclusion_space_->ClearanceOffset(float_style.Clear()) >
-          bfc_block_offset_ ||
+          bfc_block_offset ||
       mode_ != NGLineBreakerMode::kContent;
 
   // Check if we already have a pending float. That's because a float cannot be
@@ -711,30 +707,26 @@
     AddUnpositionedFloat(unpositioned_floats_, container_builder_,
                          std::move(unpositioned_float));
   } else {
-    LayoutUnit origin_block_offset = bfc_block_offset_;
-
     NGPositionedFloat positioned_float = PositionFloat(
-        origin_block_offset, constraint_space_.BfcOffset().block_offset,
+        bfc_block_offset, constraint_space_.BfcOffset().block_offset,
         unpositioned_float.get(), constraint_space_, exclusion_space_);
     positioned_floats_->push_back(positioned_float);
 
     DCHECK_EQ(positioned_float.bfc_offset.block_offset,
-              bfc_block_offset_ + margins.block_start);
+              bfc_block_offset + margins.block_start);
 
     if (float_style.Floating() == EFloat::kLeft) {
-      line_.line_left_bfc_offset = std::max(
-          line_.line_left_bfc_offset,
+      line_.line_opportunity.line_left_offset = std::max(
+          line_.line_opportunity.line_left_offset,
           positioned_float.bfc_offset.line_offset + inline_margin_size -
               margins.LineLeft(TextDirection::kLtr));
     } else {
-      line_.line_right_bfc_offset =
-          std::min(line_.line_right_bfc_offset,
+      line_.line_opportunity.line_right_offset =
+          std::min(line_.line_opportunity.line_right_offset,
                    positioned_float.bfc_offset.line_offset -
                        margins.LineLeft(TextDirection::kLtr));
     }
 
-    DCHECK_GE(line_.line_left_bfc_offset, LayoutUnit());
-    DCHECK_GE(line_.line_right_bfc_offset, LayoutUnit());
     DCHECK_GE(line_.AvailableWidth(), LayoutUnit());
   }
 }
@@ -930,7 +922,7 @@
   }
 
   // Let this line overflow.
-  // If there was a break opporunity, the overflow should stop there.
+  // If there was a break opportunity, the overflow should stop there.
   if (break_before) {
     Rewind(line_info, break_before);
     return LineBreakState::kTrailing;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 01ff0d8..f9a4be8 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -6,7 +6,7 @@
 #define NGLineBreaker_h
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h"
+#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.h"
@@ -47,7 +47,7 @@
 
   // Compute the next line break point and produces NGInlineItemResults for
   // the line.
-  bool NextLine(const NGLayoutOpportunity&, NGLineInfo*);
+  bool NextLine(const NGLineLayoutOpportunity& line_opportunity, NGLineInfo*);
 
   // Create an NGInlineBreakToken for the last line returned by NextLine().
   scoped_refptr<NGInlineBreakToken> CreateBreakToken(
@@ -71,11 +71,7 @@
     // that computes position in visual order, this position in logical order.
     LayoutUnit position;
 
-    // The current opportunity.
-    NGLayoutOpportunity opportunity;
-
-    LayoutUnit line_left_bfc_offset;
-    LayoutUnit line_right_bfc_offset;
+    NGLineLayoutOpportunity line_opportunity;
 
     // True if this line is the "first formatted line".
     // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
@@ -95,8 +91,7 @@
     bool is_after_forced_break = false;
 
     LayoutUnit AvailableWidth() const {
-      DCHECK_GE(line_right_bfc_offset, line_left_bfc_offset);
-      return line_right_bfc_offset - line_left_bfc_offset;
+      return line_opportunity.AvailableInlineSize();
     }
     bool CanFit() const { return position <= AvailableWidth(); }
     bool CanFit(LayoutUnit extra) const {
@@ -116,7 +111,7 @@
 
   void BreakLine(NGLineInfo*);
 
-  void PrepareNextLine(const NGLayoutOpportunity&, NGLineInfo*);
+  void PrepareNextLine(const NGLineLayoutOpportunity&, NGLineInfo*);
 
   void UpdatePosition(const NGInlineItemResults&);
   void ComputeLineLocation(NGLineInfo*) const;
@@ -187,8 +182,6 @@
   HarfBuzzShaper shaper_;
   ShapeResultSpacing<String> spacing_;
   bool previous_line_had_forced_break_ = false;
-  LayoutUnit bfc_line_offset_;
-  LayoutUnit bfc_block_offset_;
   const Hyphenation* hyphenation_ = nullptr;
 
   // Keep track of handled float items. See HandleFloat().
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index 34e1835..f67054c 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -46,16 +46,14 @@
 
     Vector<NGInlineItemResults> lines;
     NGExclusionSpace exclusion_space;
-    NGLayoutOpportunity opportunity;
-    opportunity.rect =
-        NGBfcRect(NGBfcOffset(), {available_width, LayoutUnit::Max()});
+    NGLineLayoutOpportunity line_opportunity(available_width);
     NGLineInfo line_info;
     while (!break_token || !break_token->IsFinished()) {
       NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, *space,
                                  &positioned_floats, &unpositioned_floats,
                                  /* container_builder */ nullptr,
                                  &exclusion_space, 0u, break_token.get());
-      if (!line_breaker.NextLine(opportunity, &line_info))
+      if (!line_breaker.NextLine(line_opportunity, &line_info))
         break;
 
       break_token = line_breaker.CreateBreakToken(line_info, nullptr);
diff --git a/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc b/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
index dffb0d1..371d08e 100644
--- a/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
+++ b/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
@@ -143,7 +143,7 @@
   TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(15), LayoutUnit(6), 0, 100);
   TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(20), LayoutUnit(50), 0, 100);
   TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(69), LayoutUnit(5), 0, 100);
-  TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(85), LayoutUnit(10), 0, 97.320511f);
+  TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(85), LayoutUnit(10), 0, 97.3125f);
 }
 
 }  // anonymous namespace
diff --git a/third_party/blink/renderer/core/layout/shapes/shape.h b/third_party/blink/renderer/core/layout/shapes/shape.h
index 778a89ee..b940726 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape.h
+++ b/third_party/blink/renderer/core/layout/shapes/shape.h
@@ -51,8 +51,8 @@
         logical_right(logical_right),
         is_valid(true) {}
 
-  float logical_left;
-  float logical_right;
+  LayoutUnit logical_left;
+  LayoutUnit logical_right;
   bool is_valid;
 };
 
diff --git a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
index 1997812..5ee3148 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
+++ b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -371,8 +371,8 @@
             containing_block.Style()->IsLeftToRightDirection()
                 ? containing_block.MarginStartForChild(layout_box_)
                 : containing_block.MarginEndForChild(layout_box_);
-        LayoutUnit raw_left_margin_box_delta(
-            segment.logical_left + LogicalLeftOffset() + logical_left_margin);
+        LayoutUnit raw_left_margin_box_delta =
+            segment.logical_left + LogicalLeftOffset() + logical_left_margin;
         LayoutUnit left_margin_box_delta = clampTo<LayoutUnit>(
             raw_left_margin_box_delta, LayoutUnit(), float_margin_box_width);
 
@@ -380,10 +380,10 @@
             containing_block.Style()->IsLeftToRightDirection()
                 ? containing_block.MarginEndForChild(layout_box_)
                 : containing_block.MarginStartForChild(layout_box_);
-        LayoutUnit raw_right_margin_box_delta(
+        LayoutUnit raw_right_margin_box_delta =
             segment.logical_right + LogicalLeftOffset() -
             containing_block.LogicalWidthForChild(layout_box_) -
-            logical_right_margin);
+            logical_right_margin;
         LayoutUnit right_margin_box_delta = clampTo<LayoutUnit>(
             raw_right_margin_box_delta, -float_margin_box_width, LayoutUnit());
 
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index 3534d56..3035a74 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -54,8 +54,6 @@
 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_host.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
-#include "third_party/blink/renderer/platform/exported/web_scrollbar_impl.h"
-#include "third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.h"
 #include "third_party/blink/renderer/platform/geometry/region.h"
 #include "third_party/blink/renderer/platform/geometry/transform_state.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
@@ -69,8 +67,6 @@
 #include "third_party/blink/public/platform/web_compositor_support.h"
 #include "third_party/blink/public/platform/web_layer.h"
 #include "third_party/blink/public/platform/web_layer_tree_view.h"
-#include "third_party/blink/public/platform/web_scrollbar_theme_geometry.h"
-#include "third_party/blink/public/platform/web_scrollbar_theme_painter.h"
 #include "third_party/blink/renderer/platform/scroll/main_thread_scrolling_reason.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_animator_base.h"
 #include "third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.h"
@@ -329,10 +325,8 @@
 static std::unique_ptr<ScrollingCoordinator::ScrollbarLayerGroup>
 CreateScrollbarLayer(Scrollbar& scrollbar, float device_scale_factor) {
   ScrollbarTheme& theme = scrollbar.GetTheme();
-  auto scrollbar_delegate = std::make_unique<ScrollbarLayerDelegate>(
-      WebScrollbarImpl::Create(&scrollbar),
-      WebScrollbarThemePainter(theme, scrollbar, device_scale_factor),
-      WebScrollbarThemeGeometryNative::Create(theme));
+  auto scrollbar_delegate =
+      std::make_unique<ScrollbarLayerDelegate>(scrollbar, device_scale_factor);
 
   auto layer_group =
       std::make_unique<ScrollingCoordinator::ScrollbarLayerGroup>();
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 724d23f..e5298a4 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -1777,7 +1777,7 @@
   FloatSize background_size = relative_compositing_bounds_size;
   if (BackgroundLayerPaintsFixedRootBackground()) {
     LocalFrameView* frame_view = ToLayoutView(GetLayoutObject()).GetFrameView();
-    background_size = FloatSize(frame_view->VisibleContentRect().Size());
+    background_size = FloatSize(frame_view->VisibleContentSize());
   }
   background_layer_->SetPosition(FloatPoint());
   if (background_size != background_layer_->Size()) {
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
index b4b2944..bc01240 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
 
-#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
 #include "third_party/blink/renderer/core/css_property_names.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -178,14 +177,6 @@
   if (RequiresCompositingForScrollDependentPosition(layer, ignore_lcd_text))
     direct_reasons |= CompositingReason::kScrollDependentPosition;
 
-  // TODO(crbug.com/839341): Remove once we support main-thread AnimationWorklet
-  // and don't need to promote the scroll-source.
-  if (layer->GetScrollableArea() && layer->GetLayoutObject().GetNode() &&
-      ScrollTimeline::HasActiveScrollTimeline(
-          layer->GetLayoutObject().GetNode())) {
-    direct_reasons |= CompositingReason::kScrollTimelineTarget;
-  }
-
   direct_reasons |= layout_object.AdditionalCompositingReasons();
 
   DCHECK(
diff --git a/third_party/blink/renderer/core/paint/frame_painter.cc b/third_party/blink/renderer/core/paint/frame_painter.cc
index 6bf0c566..45c2de470 100644
--- a/third_party/blink/renderer/core/paint/frame_painter.cc
+++ b/third_party/blink/renderer/core/paint/frame_painter.cc
@@ -40,8 +40,8 @@
 
   IntRect document_dirty_rect;
   IntPoint frame_view_location(GetFrameView().Location());
-  IntRect visible_area_without_scrollbars(
-      frame_view_location, GetFrameView().VisibleContentRect().Size());
+  IntRect visible_area_without_scrollbars(frame_view_location,
+                                          GetFrameView().VisibleContentSize());
   IntPoint content_offset =
       -frame_view_location + GetFrameView().ScrollOffsetInt();
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
@@ -95,7 +95,7 @@
     IntRect scroll_view_dirty_rect = rect.rect_;
     IntRect visible_area_with_scrollbars(
         frame_view_location,
-        GetFrameView().VisibleContentRect(kIncludeScrollbars).Size());
+        GetFrameView().VisibleContentSize(kIncludeScrollbars));
     scroll_view_dirty_rect.Intersect(visible_area_with_scrollbars);
     scroll_view_dirty_rect.MoveBy(-frame_view_location);
 
diff --git a/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc b/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
index 182e06c6..b964d3eb 100644
--- a/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
+++ b/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/core/xlink_names.h"
 #include "third_party/blink/renderer/platform/geometry/int_size.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -71,6 +72,9 @@
   Pasteboard* pasteboard = Pasteboard::GeneralPasteboard();
   pasteboard->WriteHTML(html_to_paste, BlankURL(), "",
                         Pasteboard::kCannotSmartReplace);
+  // Run all tasks in a message loop to allow asynchronous clipboard writing
+  // to happen before reading from it synchronously.
+  test::RunPendingTasks();
   EXPECT_TRUE(frame.GetEditor().ExecuteCommand("Paste"));
 
   return body->InnerHTMLAsString();
diff --git a/third_party/blink/renderer/core/testing/data/canvas-copy-image.html b/third_party/blink/renderer/core/testing/data/canvas-copy-image.html
deleted file mode 100644
index 875ea4d..0000000
--- a/third_party/blink/renderer/core/testing/data/canvas-copy-image.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<canvas style="position:absolute; top:40px; left:40px" width="200" height="200"></canvas>
-<script>
-var canvas = document.querySelector("canvas");
-var context = canvas.getContext("2d");
-context.fillStyle = "red";
-context.fillRect(0, 0, 200, 200);
-</script>
-</body>
-</html>
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc
index b9cc84c..b586099b 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -172,6 +172,27 @@
   context_proxy_->TerminateGlobalScope();
 }
 
+BeginFrameProviderParams DedicatedWorker::CreateBeginFrameProviderParams() {
+  DCHECK(GetExecutionContext()->IsContextThread());
+  // If we don't have a frame or we are not in Document, some of the SinkIds
+  // won't be initialized. If that's the case, the Worker will initialize it by
+  // itself later.
+  BeginFrameProviderParams begin_frame_provider_params;
+  if (GetExecutionContext()->IsDocument()) {
+    LocalFrame* frame = ToDocument(GetExecutionContext())->GetFrame();
+    WebLayerTreeView* layer_tree_view = nullptr;
+    if (frame) {
+      layer_tree_view =
+          frame->GetPage()->GetChromeClient().GetWebLayerTreeView(frame);
+      begin_frame_provider_params.parent_frame_sink_id =
+          layer_tree_view->GetFrameSinkId();
+    }
+    begin_frame_provider_params.frame_sink_id =
+        Platform::Current()->GenerateFrameSinkId();
+  }
+  return begin_frame_provider_params;
+}
+
 void DedicatedWorker::ContextDestroyed(ExecutionContext*) {
   DCHECK(GetExecutionContext()->IsContextThread());
   if (classic_script_loader_)
@@ -260,23 +281,6 @@
     settings = WorkerSettings::Copy(worker_global_scope->GetWorkerSettings());
   }
 
-  BeginFrameProviderParams begin_frame_provider_params;
-  if (GetExecutionContext()->IsDocument()) {
-    LocalFrame* frame = ToDocument(GetExecutionContext())->GetFrame();
-    WebLayerTreeView* layer_tree_view = nullptr;
-    // TODO(fserb): what to do when there's no frame?
-    if (frame) {
-      layer_tree_view =
-          frame->GetPage()->GetChromeClient().GetWebLayerTreeView(frame);
-      begin_frame_provider_params.parent_frame_sink_id =
-          layer_tree_view->GetFrameSinkId();
-    }
-    begin_frame_provider_params.frame_sink_id =
-        Platform::Current()->GenerateFrameSinkId();
-  } else if (GetExecutionContext()->IsWorkerGlobalScope()) {
-    // TODO(fserb): copies parent/frame sink_id into new worker or reset it.
-  }
-
   ScriptType script_type = (options_.type() == "classic") ? ScriptType::kClassic
                                                           : ScriptType::kModule;
   return std::make_unique<GlobalScopeCreationParams>(
@@ -290,7 +294,7 @@
       module_fetch_coordinator_.Get(),
       ConnectToWorkerInterfaceProvider(GetExecutionContext(),
                                        SecurityOrigin::Create(script_url_)),
-      std::move(begin_frame_provider_params));
+      CreateBeginFrameProviderParams());
 }
 
 const AtomicString& DedicatedWorker::InterfaceName() const {
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.h b/third_party/blink/renderer/core/workers/dedicated_worker.h
index 4515550..a35fb9f 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker.h
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.h
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/workers/abstract_worker.h"
 #include "third_party/blink/renderer/core/workers/worker_options.h"
+#include "third_party/blink/renderer/platform/graphics/begin_frame_provider.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace v8_inspector {
@@ -59,6 +60,7 @@
                    ExceptionState&);
   static bool CanTransferArrayBuffersAndImageBitmaps() { return true; }
   void terminate();
+  BeginFrameProviderParams CreateBeginFrameProviderParams();
 
   // Implements ContextLifecycleObserver (via AbstractWorker).
   void ContextDestroyed(ExecutionContext*) override;
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
index 329361a3..03ae8ff7 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
@@ -70,10 +70,15 @@
 
   void Trace(blink::Visitor*) override;
 
- private:
   DedicatedWorkerObjectProxy& WorkerObjectProxy() const;
 };
 
+DEFINE_TYPE_CASTS(DedicatedWorkerGlobalScope,
+                  ExecutionContext,
+                  context,
+                  context->IsDedicatedWorkerGlobalScope(),
+                  context.IsDedicatedWorkerGlobalScope());
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_DEDICATED_WORKER_GLOBAL_SCOPE_H_
diff --git a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
index 600c54e7..e372b78 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
+++ b/third_party/blink/renderer/core/xml/parser/xml_document_parser.cc
@@ -596,8 +596,6 @@
     ResourceLoaderOptions options;
     options.initiator_info.name = FetchInitiatorTypeNames::xml;
     FetchParameters params(ResourceRequest(url), options);
-    params.MutableResourceRequest().SetFetchRequestMode(
-        network::mojom::FetchRequestMode::kSameOrigin);
     Resource* resource =
         RawResource::FetchSynchronously(params, document->Fetcher());
     if (!resource->ErrorOccurred()) {
diff --git a/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc b/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
index 1605256..cdbc4f8 100644
--- a/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
+++ b/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
@@ -109,8 +109,6 @@
       fetch_options.initiator_info.name = FetchInitiatorTypeNames::xml;
       FetchParameters params(ResourceRequest(url), fetch_options);
       params.SetOriginRestriction(FetchParameters::kRestrictToSameOrigin);
-      params.MutableResourceRequest().SetFetchRequestMode(
-          network::mojom::FetchRequestMode::kSameOrigin);
       Resource* resource =
           RawResource::FetchSynchronously(params, g_global_resource_fetcher);
       if (!g_global_processor)
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index 3a81289..28e2bee 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -231,9 +231,6 @@
 
   AnimationEffect* target_effect = effects_.at(0);
   target_effect->Attach(this);
-
-  if (timeline_.IsScrollTimeline())
-    timeline.GetAsScrollTimeline()->AttachAnimation();
 }
 
 String WorkletAnimation::playState() {
@@ -434,8 +431,6 @@
 
 void WorkletAnimation::Dispose() {
   DCHECK(IsMainThread());
-  if (timeline_.IsScrollTimeline())
-    timeline_.GetAsScrollTimeline()->DetachAnimation();
   DestroyCompositorAnimation();
 }
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 8c6bc64e..9bea4bf 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -570,7 +570,6 @@
     "exported/web_media_stream_track.cc",
     "exported/web_memory_coordinator.cc",
     "exported/web_mixed_content.cc",
-    "exported/web_mock_clipboard.cc",
     "exported/web_network_state_notifier.cc",
     "exported/web_prerender.cc",
     "exported/web_prerendering_support.cc",
@@ -587,13 +586,6 @@
     "exported/web_rtc_stats_response.cc",
     "exported/web_rtc_void_request.cc",
     "exported/web_runtime_features.cc",
-    "exported/web_scrollbar_impl.cc",
-    "exported/web_scrollbar_impl.h",
-    "exported/web_scrollbar_theme_client_impl.cc",
-    "exported/web_scrollbar_theme_client_impl.h",
-    "exported/web_scrollbar_theme_geometry_native.cc",
-    "exported/web_scrollbar_theme_geometry_native.h",
-    "exported/web_scrollbar_theme_painter.cc",
     "exported/web_security_origin.cc",
     "exported/web_service_worker_installed_scripts_manager.cc",
     "exported/web_service_worker_request.cc",
@@ -1852,6 +1844,7 @@
     "graphics/paint/property_tree_state_test.cc",
     "graphics/paint_invalidation_reason_test.cc",
     "graphics/placeholder_image_test.cc",
+    "graphics/skia/skia_utils_test.cc",
     "graphics/static_bitmap_image_test.cc",
     "graphics/video_frame_submitter_test.cc",
     "histogram_test.cc",
diff --git a/third_party/blink/renderer/platform/exported/web_clipboard_impl.cc b/third_party/blink/renderer/platform/exported/web_clipboard_impl.cc
index fadda48..c335b64d 100644
--- a/third_party/blink/renderer/platform/exported/web_clipboard_impl.cc
+++ b/third_party/blink/renderer/platform/exported/web_clipboard_impl.cc
@@ -44,8 +44,7 @@
         result.text = item.string_data;
       } else if (item.string_type == blink::kMimeTypeTextHTML) {
         result.html = item.string_data;
-      } else if (item.string_type != blink::kMimeTypeTextURIList &&
-                 item.string_type != blink::kMimeTypeDownloadURL) {
+      } else if (item.string_type != blink::kMimeTypeDownloadURL) {
         result.custom_data.insert(item.string_type, item.string_data);
       }
     }
@@ -177,7 +176,8 @@
 }
 
 void WebClipboardImpl::WritePlainText(const WebString& plain_text) {
-  clipboard_->WriteText(mojom::ClipboardBuffer::kStandard, plain_text);
+  clipboard_->WriteText(mojom::ClipboardBuffer::kStandard,
+                        EnsureNotNullWTFString(plain_text));
   clipboard_->CommitWrite(mojom::ClipboardBuffer::kStandard);
 }
 
@@ -185,9 +185,10 @@
                                  const WebURL& source_url,
                                  const WebString& plain_text,
                                  bool write_smart_paste) {
-  clipboard_->WriteHtml(mojom::ClipboardBuffer::kStandard, html_text,
-                        source_url);
-  clipboard_->WriteText(mojom::ClipboardBuffer::kStandard, plain_text);
+  clipboard_->WriteHtml(mojom::ClipboardBuffer::kStandard,
+                        EnsureNotNullWTFString(html_text), source_url);
+  clipboard_->WriteText(mojom::ClipboardBuffer::kStandard,
+                        EnsureNotNullWTFString(plain_text));
 
   if (write_smart_paste)
     clipboard_->WriteSmartPasteMarker(mojom::ClipboardBuffer::kStandard);
diff --git a/third_party/blink/renderer/platform/exported/web_mock_clipboard.cc b/third_party/blink/renderer/platform/exported/web_mock_clipboard.cc
deleted file mode 100644
index 52d2c5d..0000000
--- a/third_party/blink/renderer/platform/exported/web_mock_clipboard.cc
+++ /dev/null
@@ -1,23 +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 "third_party/blink/public/platform/web_mock_clipboard.h"
-
-#include "third_party/blink/renderer/platform/blob/blob_data.h"
-
-namespace blink {
-
-WebBlobInfo WebMockClipboard::CreateBlobFromData(base::span<const uint8_t> data,
-                                                 const WebString& mime_type) {
-  auto blob_data = BlobData::Create();
-  blob_data->SetContentType(mime_type);
-  blob_data->AppendBytes(data.data(), data.size());
-  auto blob_data_handle =
-      BlobDataHandle::Create(std::move(blob_data), data.size());
-  return WebBlobInfo(
-      blob_data_handle->Uuid(), mime_type, data.size(),
-      blob_data_handle->CloneBlobPtr().PassInterface().PassHandle());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_impl.cc b/third_party/blink/renderer/platform/exported/web_scrollbar_impl.cc
deleted file mode 100644
index 825beb9..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_impl.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/exported/web_scrollbar_impl.h"
-
-#include "third_party/blink/renderer/platform/geometry/int_rect.h"
-#include "third_party/blink/renderer/platform/scroll/scrollbar.h"
-
-namespace blink {
-
-WebScrollbarImpl::WebScrollbarImpl(Scrollbar* scrollbar)
-    : scrollbar_(scrollbar) {}
-
-bool WebScrollbarImpl::IsOverlay() const {
-  return scrollbar_->IsOverlayScrollbar();
-}
-
-int WebScrollbarImpl::Value() const {
-  return scrollbar_->Value();
-}
-
-WebPoint WebScrollbarImpl::Location() const {
-  return scrollbar_->Location();
-}
-
-WebSize WebScrollbarImpl::Size() const {
-  return scrollbar_->Size();
-}
-
-bool WebScrollbarImpl::Enabled() const {
-  return scrollbar_->Enabled();
-}
-
-int WebScrollbarImpl::Maximum() const {
-  return scrollbar_->Maximum();
-}
-
-int WebScrollbarImpl::TotalSize() const {
-  return scrollbar_->TotalSize();
-}
-
-bool WebScrollbarImpl::IsScrollableAreaActive() const {
-  return scrollbar_->IsScrollableAreaActive();
-}
-
-bool WebScrollbarImpl::HasTickmarks() const {
-  Vector<IntRect> tickmarks;
-  scrollbar_->GetTickmarks(tickmarks);
-
-  return !tickmarks.IsEmpty();
-}
-
-void WebScrollbarImpl::GetTickmarks(WebVector<WebRect>& web_tickmarks) const {
-  Vector<IntRect> tickmarks;
-  scrollbar_->GetTickmarks(tickmarks);
-
-  WebVector<WebRect> result(tickmarks.size());
-  for (size_t i = 0; i < tickmarks.size(); ++i)
-    result[i] = tickmarks[i];
-
-  web_tickmarks.Swap(result);
-}
-
-WebScrollbar::ScrollbarControlSize WebScrollbarImpl::GetControlSize() const {
-  return static_cast<WebScrollbar::ScrollbarControlSize>(
-      scrollbar_->GetControlSize());
-}
-
-WebScrollbar::ScrollbarPart WebScrollbarImpl::PressedPart() const {
-  return static_cast<WebScrollbar::ScrollbarPart>(scrollbar_->PressedPart());
-}
-
-WebScrollbar::ScrollbarPart WebScrollbarImpl::HoveredPart() const {
-  return static_cast<WebScrollbar::ScrollbarPart>(scrollbar_->HoveredPart());
-}
-
-WebScrollbarOverlayColorTheme WebScrollbarImpl::ScrollbarOverlayColorTheme()
-    const {
-  return static_cast<WebScrollbarOverlayColorTheme>(
-      scrollbar_->GetScrollbarOverlayColorTheme());
-}
-
-WebScrollbar::Orientation WebScrollbarImpl::GetOrientation() const {
-  return static_cast<WebScrollbar::Orientation>(scrollbar_->Orientation());
-}
-
-bool WebScrollbarImpl::IsLeftSideVerticalScrollbar() const {
-  return scrollbar_->IsLeftSideVerticalScrollbar();
-}
-
-bool WebScrollbarImpl::IsCustomScrollbar() const {
-  return scrollbar_->IsCustomScrollbar();
-}
-
-float WebScrollbarImpl::ElasticOverscroll() const {
-  return scrollbar_->ElasticOverscroll();
-}
-
-void WebScrollbarImpl::SetElasticOverscroll(float elastic_overscroll) {
-  scrollbar_->SetElasticOverscroll(elastic_overscroll);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_impl.h b/third_party/blink/renderer/platform/exported/web_scrollbar_impl.h
deleted file mode 100644
index b6938a6..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_impl.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_IMPL_H_
-
-#include "base/memory/ptr_util.h"
-#include "third_party/blink/public/platform/web_scrollbar.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
-
-#include <memory>
-
-namespace blink {
-
-class Scrollbar;
-class PLATFORM_EXPORT WebScrollbarImpl final : public WebScrollbar {
-  USING_FAST_MALLOC(WebScrollbarImpl);
-  WTF_MAKE_NONCOPYABLE(WebScrollbarImpl);
-
- public:
-  static std::unique_ptr<WebScrollbarImpl> Create(Scrollbar* scrollbar) {
-    return base::WrapUnique(new WebScrollbarImpl(scrollbar));
-  }
-
-  // Implement WebScrollbar methods
-  bool IsOverlay() const override;
-  int Value() const override;
-  WebPoint Location() const override;
-  WebSize Size() const override;
-  bool Enabled() const override;
-  int Maximum() const override;
-  int TotalSize() const override;
-  bool IsScrollableAreaActive() const override;
-  bool HasTickmarks() const override;
-  void GetTickmarks(WebVector<WebRect>& tickmarks) const override;
-  ScrollbarControlSize GetControlSize() const override;
-  ScrollbarPart PressedPart() const override;
-  ScrollbarPart HoveredPart() const override;
-  WebScrollbarOverlayColorTheme ScrollbarOverlayColorTheme() const override;
-  bool IsCustomScrollbar() const override;
-  Orientation GetOrientation() const override;
-  bool IsLeftSideVerticalScrollbar() const override;
-  float ElasticOverscroll() const override;
-  void SetElasticOverscroll(float) override;
-
- private:
-  explicit WebScrollbarImpl(Scrollbar*);
-
-  // Accessed by main and compositor threads, e.g., the compositor thread
-  // checks |orientation()|.
-  //
-  // TODO: minimize or avoid cross-thread use, if possible.
-  CrossThreadPersistent<Scrollbar> scrollbar_;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.cc b/third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.cc
deleted file mode 100644
index eb44177..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.h"
-
-#include "third_party/blink/renderer/platform/scroll/scrollbar_theme.h"
-
-namespace blink {
-
-WebScrollbarThemeClientImpl::WebScrollbarThemeClientImpl(
-    WebScrollbar& scrollbar)
-    : scrollbar_(scrollbar) {
-  ScrollbarTheme::DeprecatedStaticGetTheme().RegisterScrollbar(*this);
-}
-
-WebScrollbarThemeClientImpl::~WebScrollbarThemeClientImpl() {
-  ScrollbarTheme::DeprecatedStaticGetTheme().UnregisterScrollbar(*this);
-}
-
-int WebScrollbarThemeClientImpl::X() const {
-  return Location().X();
-}
-
-int WebScrollbarThemeClientImpl::Y() const {
-  return Location().Y();
-}
-
-int WebScrollbarThemeClientImpl::Width() const {
-  return Size().Width();
-}
-
-int WebScrollbarThemeClientImpl::Height() const {
-  return Size().Height();
-}
-
-IntSize WebScrollbarThemeClientImpl::Size() const {
-  return scrollbar_.Size();
-}
-
-IntPoint WebScrollbarThemeClientImpl::Location() const {
-  return scrollbar_.Location();
-}
-
-void WebScrollbarThemeClientImpl::SetFrameRect(const IntRect&) {
-  // Unused by Chromium scrollbar themes.
-  NOTREACHED();
-}
-
-IntRect WebScrollbarThemeClientImpl::FrameRect() const {
-  return IntRect(Location(), Size());
-}
-
-void WebScrollbarThemeClientImpl::Invalidate() {
-  // Unused by Chromium scrollbar themes.
-  NOTREACHED();
-}
-
-void WebScrollbarThemeClientImpl::InvalidateRect(const IntRect&) {
-  // Unused by Chromium scrollbar themes.
-  NOTREACHED();
-}
-
-ScrollbarOverlayColorTheme
-WebScrollbarThemeClientImpl::GetScrollbarOverlayColorTheme() const {
-  return static_cast<ScrollbarOverlayColorTheme>(
-      scrollbar_.ScrollbarOverlayColorTheme());
-}
-
-void WebScrollbarThemeClientImpl::GetTickmarks(
-    Vector<IntRect>& tickmarks) const {
-  WebVector<WebRect> web_tickmarks;
-  scrollbar_.GetTickmarks(web_tickmarks);
-  tickmarks.resize(web_tickmarks.size());
-  for (size_t i = 0; i < web_tickmarks.size(); ++i)
-    tickmarks[i] = web_tickmarks[i];
-}
-
-bool WebScrollbarThemeClientImpl::IsScrollableAreaActive() const {
-  return scrollbar_.IsScrollableAreaActive();
-}
-
-IntPoint WebScrollbarThemeClientImpl::ConvertFromRootFrame(
-    const IntPoint& point_in_root_frame) const {
-  // Unused by Chromium scrollbar themes.
-  NOTREACHED();
-  return point_in_root_frame;
-}
-
-bool WebScrollbarThemeClientImpl::IsCustomScrollbar() const {
-  return scrollbar_.IsCustomScrollbar();
-}
-
-ScrollbarOrientation WebScrollbarThemeClientImpl::Orientation() const {
-  return static_cast<ScrollbarOrientation>(scrollbar_.GetOrientation());
-}
-
-bool WebScrollbarThemeClientImpl::IsLeftSideVerticalScrollbar() const {
-  return scrollbar_.IsLeftSideVerticalScrollbar();
-}
-
-int WebScrollbarThemeClientImpl::Value() const {
-  return scrollbar_.Value();
-}
-
-float WebScrollbarThemeClientImpl::CurrentPos() const {
-  return Value();
-}
-
-int WebScrollbarThemeClientImpl::VisibleSize() const {
-  return TotalSize() - Maximum();
-}
-
-int WebScrollbarThemeClientImpl::TotalSize() const {
-  return scrollbar_.TotalSize();
-}
-
-int WebScrollbarThemeClientImpl::Maximum() const {
-  return scrollbar_.Maximum();
-}
-
-ScrollbarControlSize WebScrollbarThemeClientImpl::GetControlSize() const {
-  return static_cast<ScrollbarControlSize>(scrollbar_.GetControlSize());
-}
-
-ScrollbarPart WebScrollbarThemeClientImpl::PressedPart() const {
-  return static_cast<ScrollbarPart>(scrollbar_.PressedPart());
-}
-
-ScrollbarPart WebScrollbarThemeClientImpl::HoveredPart() const {
-  return static_cast<ScrollbarPart>(scrollbar_.HoveredPart());
-}
-
-void WebScrollbarThemeClientImpl::StyleChanged() {
-  NOTREACHED();
-}
-
-void WebScrollbarThemeClientImpl::SetScrollbarsHiddenIfOverlay(bool hidden) {
-  NOTREACHED();
-}
-
-bool WebScrollbarThemeClientImpl::Enabled() const {
-  return scrollbar_.Enabled();
-}
-
-void WebScrollbarThemeClientImpl::SetEnabled(bool) {
-  NOTREACHED();
-}
-
-bool WebScrollbarThemeClientImpl::IsOverlayScrollbar() const {
-  return scrollbar_.IsOverlay();
-}
-
-float WebScrollbarThemeClientImpl::ElasticOverscroll() const {
-  return scrollbar_.ElasticOverscroll();
-}
-
-void WebScrollbarThemeClientImpl::SetElasticOverscroll(
-    float elastic_overscroll) {
-  return scrollbar_.SetElasticOverscroll(elastic_overscroll);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.h b/third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.h
deleted file mode 100644
index 34a7d26..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_THEME_CLIENT_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_THEME_CLIENT_IMPL_H_
-
-#include "third_party/blink/public/platform/web_scrollbar.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scroll/scrollbar_theme_client.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
-
-namespace blink {
-
-// Adapts a WebScrollbar to the ScrollbarThemeClient interface
-class PLATFORM_EXPORT WebScrollbarThemeClientImpl
-    : public ScrollbarThemeClient {
-  DISALLOW_NEW();
-  WTF_MAKE_NONCOPYABLE(WebScrollbarThemeClientImpl);
-
- public:
-  // Caller must retain ownership of this pointer and ensure that its lifetime
-  // exceeds this instance.
-  WebScrollbarThemeClientImpl(WebScrollbar&);
-  ~WebScrollbarThemeClientImpl() override;
-
-  // Implement ScrollbarThemeClient interface
-  int X() const override;
-  int Y() const override;
-  int Width() const override;
-  int Height() const override;
-  IntSize Size() const override;
-  IntPoint Location() const override;
-  void SetFrameRect(const IntRect&) override;
-  IntRect FrameRect() const override;
-  void Invalidate() override;
-  void InvalidateRect(const IntRect&) override;
-  ScrollbarOverlayColorTheme GetScrollbarOverlayColorTheme() const override;
-  void GetTickmarks(Vector<IntRect>&) const override;
-  bool IsScrollableAreaActive() const override;
-  IntPoint ConvertFromRootFrame(const IntPoint&) const override;
-  bool IsCustomScrollbar() const override;
-  ScrollbarOrientation Orientation() const override;
-  bool IsLeftSideVerticalScrollbar() const override;
-  int Value() const override;
-  float CurrentPos() const override;
-  int VisibleSize() const override;
-  int TotalSize() const override;
-  int Maximum() const override;
-  ScrollbarControlSize GetControlSize() const override;
-  ScrollbarPart PressedPart() const override;
-  ScrollbarPart HoveredPart() const override;
-  void StyleChanged() override;
-  void SetScrollbarsHiddenIfOverlay(bool) override;
-  bool Enabled() const override;
-  void SetEnabled(bool) override;
-  bool IsOverlayScrollbar() const override;
-  float ElasticOverscroll() const override;
-  void SetElasticOverscroll(float) override;
-
- private:
-  WebScrollbar& scrollbar_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_THEME_CLIENT_IMPL_H_
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.cc b/third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.cc
deleted file mode 100644
index 89c9a73..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.h"
-
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-#include "third_party/blink/public/platform/web_scrollbar.h"
-#include "third_party/blink/renderer/platform/exported/web_scrollbar_theme_client_impl.h"
-#include "third_party/blink/renderer/platform/scroll/scrollbar_theme.h"
-
-namespace blink {
-
-std::unique_ptr<WebScrollbarThemeGeometryNative>
-WebScrollbarThemeGeometryNative::Create(ScrollbarTheme& theme) {
-  return base::WrapUnique(new WebScrollbarThemeGeometryNative(theme));
-}
-
-WebScrollbarThemeGeometryNative::WebScrollbarThemeGeometryNative(
-    ScrollbarTheme& theme)
-    : theme_(theme) {}
-
-bool WebScrollbarThemeGeometryNative::HasButtons(WebScrollbar* scrollbar) {
-  return theme_.HasButtons(WebScrollbarThemeClientImpl(*scrollbar));
-}
-
-bool WebScrollbarThemeGeometryNative::HasThumb(WebScrollbar* scrollbar) {
-  return theme_.HasThumb(WebScrollbarThemeClientImpl(*scrollbar));
-}
-
-WebRect WebScrollbarThemeGeometryNative::TrackRect(WebScrollbar* scrollbar) {
-  return theme_.TrackRect(WebScrollbarThemeClientImpl(*scrollbar));
-}
-
-WebRect WebScrollbarThemeGeometryNative::ThumbRect(WebScrollbar* scrollbar) {
-  return theme_.ThumbRect(WebScrollbarThemeClientImpl(*scrollbar));
-}
-
-WebRect WebScrollbarThemeGeometryNative::BackButtonStartRect(
-    WebScrollbar* scrollbar) {
-  return theme_.BackButtonRect(WebScrollbarThemeClientImpl(*scrollbar),
-                               kBackButtonStartPart, false);
-}
-
-WebRect WebScrollbarThemeGeometryNative::BackButtonEndRect(
-    WebScrollbar* scrollbar) {
-  return theme_.BackButtonRect(WebScrollbarThemeClientImpl(*scrollbar),
-                               kBackButtonEndPart, false);
-}
-
-WebRect WebScrollbarThemeGeometryNative::ForwardButtonStartRect(
-    WebScrollbar* scrollbar) {
-  return theme_.ForwardButtonRect(WebScrollbarThemeClientImpl(*scrollbar),
-                                  kForwardButtonStartPart, false);
-}
-
-WebRect WebScrollbarThemeGeometryNative::ForwardButtonEndRect(
-    WebScrollbar* scrollbar) {
-  return theme_.ForwardButtonRect(WebScrollbarThemeClientImpl(*scrollbar),
-                                  kForwardButtonEndPart, false);
-}
-
-WebSize WebScrollbarThemeGeometryNative::NinePatchThumbCanvasSize(
-    WebScrollbar* scrollbar) {
-  DCHECK(theme_.UsesNinePatchThumbResource());
-  return theme_.NinePatchThumbCanvasSize(
-      WebScrollbarThemeClientImpl(*scrollbar));
-}
-
-WebRect WebScrollbarThemeGeometryNative::NinePatchThumbAperture(
-    WebScrollbar* scrollbar) {
-  DCHECK(theme_.UsesNinePatchThumbResource());
-  return theme_.NinePatchThumbAperture(WebScrollbarThemeClientImpl(*scrollbar));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.h b/third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.h
deleted file mode 100644
index b7606dea..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_geometry_native.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_THEME_GEOMETRY_NATIVE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_EXPORTED_WEB_SCROLLBAR_THEME_GEOMETRY_NATIVE_H_
-
-#include <memory>
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/platform/web_scrollbar_theme_geometry.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
-
-namespace blink {
-
-class ScrollbarTheme;
-class WebScrollbar;
-
-class PLATFORM_EXPORT WebScrollbarThemeGeometryNative
-    : public WebScrollbarThemeGeometry {
-  USING_FAST_MALLOC(WebScrollbarThemeGeometryNative);
-  WTF_MAKE_NONCOPYABLE(WebScrollbarThemeGeometryNative);
-
- public:
-  static std::unique_ptr<WebScrollbarThemeGeometryNative> Create(
-      ScrollbarTheme&);
-
-  bool HasButtons(WebScrollbar*) override;
-  bool HasThumb(WebScrollbar*) override;
-  WebRect TrackRect(WebScrollbar*) override;
-  WebRect ThumbRect(WebScrollbar*) override;
-  WebRect BackButtonStartRect(WebScrollbar*) override;
-  WebRect BackButtonEndRect(WebScrollbar*) override;
-  WebRect ForwardButtonStartRect(WebScrollbar*) override;
-  WebRect ForwardButtonEndRect(WebScrollbar*) override;
-  WebSize NinePatchThumbCanvasSize(WebScrollbar*) override;
-  WebRect NinePatchThumbAperture(WebScrollbar*) override;
-
- private:
-  explicit WebScrollbarThemeGeometryNative(ScrollbarTheme&);
-
-  // The theme is not owned by this class. It is assumed that the theme is a
-  // static pointer and its lifetime is essentially infinite. Only thread-safe
-  // functions on the theme can be called by this theme.
-  ScrollbarTheme& theme_;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_painter.cc b/third_party/blink/renderer/platform/exported/web_scrollbar_theme_painter.cc
deleted file mode 100644
index 6d123b3..0000000
--- a/third_party/blink/renderer/platform/exported/web_scrollbar_theme_painter.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/public/platform/web_scrollbar_theme_painter.h"
-
-#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
-#include "third_party/blink/renderer/platform/scroll/scrollbar.h"
-#include "third_party/blink/renderer/platform/scroll/scrollbar_theme.h"
-
-namespace blink {
-
-// WebScrollbarThemeMac uses GraphicsContextCanvas which doesn't quite support
-// device clip rects not at the origin.  This class translates the recording
-// canvas to the origin and then adjusts it back during playback.
-class ScopedScrollbarPainter {
- public:
-  ScopedScrollbarPainter(WebScrollbarThemePainter* painter,
-                         WebCanvas* canvas,
-                         const WebRect& rect)
-      : int_rect_(IntRect(IntPoint(), IntSize(rect.width, rect.height))),
-        canvas_(canvas),
-        rect_(rect) {
-    builder_.Context().SetDeviceScaleFactor(painter->DeviceScaleFactor());
-  }
-  GraphicsContext& Context() { return builder_.Context(); }
-  const IntRect& Rect() const { return int_rect_; }
-
-  ~ScopedScrollbarPainter() {
-    canvas_->save();
-    canvas_->translate(rect_.x, rect_.y);
-    canvas_->drawPicture(builder_.EndRecording());
-    canvas_->restore();
-  }
-
- protected:
-  IntRect int_rect_;
-  PaintRecordBuilder builder_;
-  WebCanvas* canvas_;
-  const WebRect& rect_;
-};
-
-void WebScrollbarThemePainter::Assign(const WebScrollbarThemePainter& painter) {
-  // This is a pointer to a static object, so no ownership transferral.
-  theme_ = painter.theme_;
-  scrollbar_ = painter.scrollbar_;
-  device_scale_factor_ = painter.device_scale_factor_;
-}
-
-void WebScrollbarThemePainter::Reset() {
-  scrollbar_ = nullptr;
-}
-
-void WebScrollbarThemePainter::PaintScrollbarBackground(WebCanvas* canvas,
-                                                        const WebRect& rect) {
-  SkRect clip = SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height);
-  canvas->clipRect(clip);
-
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintScrollbarBackground(painter.Context(), *scrollbar_);
-}
-
-void WebScrollbarThemePainter::PaintTrackBackground(WebCanvas* canvas,
-                                                    const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintTrackBackground(painter.Context(), *scrollbar_, painter.Rect());
-  if (!theme_->ShouldRepaintAllPartsOnInvalidation())
-    scrollbar_->ClearTrackNeedsRepaint();
-}
-
-void WebScrollbarThemePainter::PaintBackTrackPart(WebCanvas* canvas,
-                                                  const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintTrackPiece(painter.Context(), *scrollbar_, painter.Rect(),
-                          kBackTrackPart);
-}
-
-void WebScrollbarThemePainter::PaintForwardTrackPart(WebCanvas* canvas,
-                                                     const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintTrackPiece(painter.Context(), *scrollbar_, painter.Rect(),
-                          kForwardTrackPart);
-}
-
-void WebScrollbarThemePainter::PaintBackButtonStart(WebCanvas* canvas,
-                                                    const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintButton(painter.Context(), *scrollbar_, painter.Rect(),
-                      kBackButtonStartPart);
-}
-
-void WebScrollbarThemePainter::PaintBackButtonEnd(WebCanvas* canvas,
-                                                  const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintButton(painter.Context(), *scrollbar_, painter.Rect(),
-                      kBackButtonEndPart);
-}
-
-void WebScrollbarThemePainter::PaintForwardButtonStart(WebCanvas* canvas,
-                                                       const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintButton(painter.Context(), *scrollbar_, painter.Rect(),
-                      kForwardButtonStartPart);
-}
-
-void WebScrollbarThemePainter::PaintForwardButtonEnd(WebCanvas* canvas,
-                                                     const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintButton(painter.Context(), *scrollbar_, painter.Rect(),
-                      kForwardButtonEndPart);
-}
-
-void WebScrollbarThemePainter::PaintTickmarks(WebCanvas* canvas,
-                                              const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintTickmarks(painter.Context(), *scrollbar_, painter.Rect());
-}
-
-void WebScrollbarThemePainter::PaintThumb(WebCanvas* canvas,
-                                          const WebRect& rect) {
-  ScopedScrollbarPainter painter(this, canvas, rect);
-  theme_->PaintThumb(painter.Context(), *scrollbar_, painter.Rect());
-  if (!theme_->ShouldRepaintAllPartsOnInvalidation())
-    scrollbar_->ClearThumbNeedsRepaint();
-}
-
-WebScrollbarThemePainter::WebScrollbarThemePainter(ScrollbarTheme& theme,
-                                                   Scrollbar& scrollbar,
-                                                   float device_scale_factor)
-    : theme_(&theme),
-      scrollbar_(&scrollbar),
-      device_scale_factor_(device_scale_factor) {}
-
-float WebScrollbarThemePainter::ThumbOpacity() const {
-  return theme_->ThumbOpacity(*scrollbar_);
-}
-
-bool WebScrollbarThemePainter::TrackNeedsRepaint() const {
-  return scrollbar_->TrackNeedsRepaint();
-}
-
-bool WebScrollbarThemePainter::ThumbNeedsRepaint() const {
-  return scrollbar_->ThumbNeedsRepaint();
-}
-
-bool WebScrollbarThemePainter::UsesNinePatchThumbResource() const {
-  return theme_->UsesNinePatchThumbResource();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/geometry/int_point.cc b/third_party/blink/renderer/platform/geometry/int_point.cc
index 2bfd9fd..3315630a 100644
--- a/third_party/blink/renderer/platform/geometry/int_point.cc
+++ b/third_party/blink/renderer/platform/geometry/int_point.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/geometry/int_point.h"
 
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "ui/gfx/geometry/point.h"
 
 namespace blink {
 
@@ -12,6 +13,10 @@
   return ostream << point.ToString();
 }
 
+IntPoint::operator gfx::Point() const {
+  return gfx::Point(X(), Y());
+}
+
 String IntPoint::ToString() const {
   return String::Format("%d,%d", X(), Y());
 }
diff --git a/third_party/blink/renderer/platform/geometry/int_point.h b/third_party/blink/renderer/platform/geometry/int_point.h
index 6e0072ec..9bbfa8c 100644
--- a/third_party/blink/renderer/platform/geometry/int_point.h
+++ b/third_party/blink/renderer/platform/geometry/int_point.h
@@ -43,6 +43,10 @@
 #endif
 #endif
 
+namespace gfx {
+class Point;
+}
+
 namespace blink {
 
 class PLATFORM_EXPORT IntPoint {
@@ -100,6 +104,8 @@
   operator CGPoint() const;
 #endif
 
+  operator gfx::Point() const;
+
   String ToString() const;
 
  private:
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
index ad518f8..cbc0164 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
@@ -16,14 +16,39 @@
     const BeginFrameProviderParams& begin_frame_provider_params,
     BeginFrameProviderClient* client)
     : needs_begin_frame_(false),
+      requested_needs_begin_frame_(false),
       cfs_binding_(this),
       efs_binding_(this),
       frame_sink_id_(begin_frame_provider_params.frame_sink_id),
       parent_frame_sink_id_(begin_frame_provider_params.parent_frame_sink_id),
-      begin_frame_client_(client) {}
+      begin_frame_client_(client),
+      weak_factory_(this) {}
 
-void BeginFrameProvider::CreateCompositorFrameSink() {
-  DCHECK(frame_sink_id_.is_valid());
+void BeginFrameProvider::ResetCompositorFrameSink() {
+  compositor_frame_sink_.reset();
+  efs_binding_.Close();
+  cfs_binding_.Close();
+  if (needs_begin_frame_) {
+    needs_begin_frame_ = false;
+    RequestBeginFrame();
+  }
+}
+
+void BeginFrameProvider::OnMojoConnectionError(uint32_t custom_reason,
+                                               const std::string& description) {
+  if (custom_reason) {
+    DLOG(ERROR) << description;
+  }
+  ResetCompositorFrameSink();
+}
+
+void BeginFrameProvider::CreateCompositorFrameSinkIfNeeded() {
+  if (!parent_frame_sink_id_.is_valid() || !frame_sink_id_.is_valid()) {
+    return;
+  }
+
+  if (compositor_frame_sink_.is_bound())
+    return;
 
   mojom::blink::EmbeddedFrameSinkProviderPtr provider;
   Platform::Current()->GetInterfaceProvider()->GetInterface(
@@ -43,33 +68,34 @@
   provider->CreateSimpleCompositorFrameSink(
       parent_frame_sink_id_, frame_sink_id_, std::move(efs_client),
       std::move(client), mojo::MakeRequest(&compositor_frame_sink_));
+
+  compositor_frame_sink_.set_connection_error_with_reason_handler(
+      base::BindOnce(&BeginFrameProvider::OnMojoConnectionError,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void BeginFrameProvider::RequestBeginFrame() {
+  requested_needs_begin_frame_ = true;
   if (needs_begin_frame_)
     return;
 
-  if (!compositor_frame_sink_.is_bound()) {
-    CreateCompositorFrameSink();
-    if (!compositor_frame_sink_.is_bound()) {
-      return;
-    }
-  }
+  CreateCompositorFrameSinkIfNeeded();
 
   needs_begin_frame_ = true;
   compositor_frame_sink_->SetNeedsBeginFrame(true);
 }
 
 void BeginFrameProvider::OnBeginFrame(const viz::BeginFrameArgs& args) {
-  // TODO(fserb): we could potentially be nicer here.
-  DCHECK(compositor_frame_sink_.is_bound());
-
-  // OnBeginFrame sometimes happens without a request. So we just skip it.
+  // If there was no need for a BeginFrame, just skip it.
   if (needs_begin_frame_) {
-    needs_begin_frame_ = false;
-    compositor_frame_sink_->SetNeedsBeginFrame(false);
+    requested_needs_begin_frame_ = false;
 
     begin_frame_client_->BeginFrame();
+
+    if (!requested_needs_begin_frame_) {
+      needs_begin_frame_ = false;
+      compositor_frame_sink_->SetNeedsBeginFrame(false);
+    }
   }
 
   viz::BeginFrameAck ack;
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
index aee6fc03..6138658 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
@@ -32,7 +32,7 @@
       const BeginFrameProviderParams& begin_frame_provider_params,
       BeginFrameProviderClient*);
 
-  void CreateCompositorFrameSink();
+  void CreateCompositorFrameSinkIfNeeded();
 
   void RequestBeginFrame();
 
@@ -62,17 +62,25 @@
     NOTIMPLEMENTED();
   }
 
+  void ResetCompositorFrameSink();
+
   ~BeginFrameProvider() override = default;
 
  private:
+  void OnMojoConnectionError(uint32_t custom_reason,
+                             const std::string& description);
+
   bool needs_begin_frame_;
+  bool requested_needs_begin_frame_;
 
   mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient> cfs_binding_;
   mojo::Binding<mojom::blink::EmbeddedFrameSinkClient> efs_binding_;
-  const viz::FrameSinkId frame_sink_id_;
-  const viz::FrameSinkId parent_frame_sink_id_;
+  viz::FrameSinkId frame_sink_id_;
+  viz::FrameSinkId parent_frame_sink_id_;
   viz::mojom::blink::CompositorFrameSinkPtr compositor_frame_sink_;
   BeginFrameProviderClient* begin_frame_client_;
+
+  base::WeakPtrFactory<BeginFrameProvider> weak_factory_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
index 05efcca2..700122d 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
@@ -164,16 +164,11 @@
   void UpdateEffectBounds(const FloatRect&, const TransformPaintPropertyNode*);
 
   // Starts a clip state by adjusting the transform state, applying
-  // |combined_clip_rect| which is combined from multiple rectangular
-  // consecutive clips, and updating the current state.
-  // |lowest_combined_clip_node| is the lowest node of the combined clips.
-  void StartCombinedClip(
-      const FloatRect& combined_clip_rect,
-      const ClipPaintPropertyNode* lowest_combined_clip_node);
-  // Starts a clip state by adjusting the transform state, applying the single
-  // clip node which can't be combined with other clips, and updating the
-  // current state.
-  void StartSingleClip(const ClipPaintPropertyNode*);
+  // |combined_clip_rect| which is combined from one or more consecutive clips,
+  // and updating the current state. |lowest_combined_clip_node| is the lowest
+  // node of the combined clips.
+  void StartClip(const FloatRoundedRect& combined_clip_rect,
+                 const ClipPaintPropertyNode* lowest_combined_clip_node);
   // Pop one clip state from the top of the stack.
   void EndClip();
   // Pop clip states from the top of the stack until the top is an effect state
@@ -274,6 +269,46 @@
   SwitchToTransform(chunk_state.Transform());
 }
 
+// Tries to combine a clip node's clip rect into |combined_clip_rect|.
+// Returns whether the clip has been combined.
+static bool CombineClip(const ClipPaintPropertyNode* clip,
+                        FloatRoundedRect& combined_clip_rect) {
+  // Don't combine into a clip with clip path.
+  if (clip->Parent()->ClipPath())
+    return false;
+
+  // Don't combine clips in different transform spaces.
+  if (clip->LocalTransformSpace() != clip->Parent()->LocalTransformSpace() &&
+      !GeometryMapper::SourceToDestinationProjection(
+           clip->Parent()->LocalTransformSpace(), clip->LocalTransformSpace())
+           .IsIdentity())
+    return false;
+
+  // Don't combine two rounded clip rects.
+  bool clip_is_rounded = clip->ClipRect().IsRounded();
+  bool combined_is_rounded = combined_clip_rect.IsRounded();
+  if (clip_is_rounded && combined_is_rounded)
+    return false;
+
+  // If one is rounded and the other contains the rounded bounds, use the
+  // rounded as the combined.
+  if (combined_is_rounded)
+    return clip->ClipRect().Rect().Contains(combined_clip_rect.Rect());
+  if (clip_is_rounded) {
+    if (combined_clip_rect.Rect().Contains(clip->ClipRect().Rect())) {
+      combined_clip_rect = clip->ClipRect();
+      return true;
+    }
+    return false;
+  }
+
+  // The combined is the intersection if both are rectangular.
+  DCHECK(!combined_is_rounded && !clip_is_rounded);
+  combined_clip_rect = FloatRoundedRect(
+      Intersection(combined_clip_rect.Rect(), clip->ClipRect().Rect()));
+  return true;
+}
+
 void ConversionContext::SwitchToClip(const ClipPaintPropertyNode* target_clip) {
   if (target_clip == current_clip_)
     return;
@@ -317,49 +352,29 @@
   }
 
   // Step 3: Now apply the list of clips in top-down order.
-  base::Optional<FloatRect> pending_combined_clip_rect;
-  const ClipPaintPropertyNode* lowest_combined_clip_node = nullptr;
-  for (size_t i = pending_clips.size(); i--;) {
+  DCHECK(pending_clips.size());
+  auto pending_combined_clip_rect = pending_clips.back()->ClipRect();
+  const auto* lowest_combined_clip_node = pending_clips.back();
+  for (size_t i = pending_clips.size() - 1; i--;) {
     const auto* sub_clip = pending_clips[i];
-    bool has_rounded_clip_or_clip_path =
-        sub_clip->ClipRect().IsRounded() || sub_clip->ClipPath();
-    if (!has_rounded_clip_or_clip_path && pending_combined_clip_rect &&
-        (sub_clip->Parent()->LocalTransformSpace() ==
-             sub_clip->LocalTransformSpace() ||
-         GeometryMapper::SourceToDestinationProjection(
-             sub_clip->Parent()->LocalTransformSpace(),
-             sub_clip->LocalTransformSpace())
-             .IsIdentity())) {
-      // Continue to combine rectangular clips in the same transform space.
-      pending_combined_clip_rect->Intersect(sub_clip->ClipRect().Rect());
+    if (CombineClip(sub_clip, pending_combined_clip_rect)) {
+      // Continue to combine.
       lowest_combined_clip_node = sub_clip;
-      continue;
-    }
-
-    if (pending_combined_clip_rect) {
-      StartCombinedClip(*pending_combined_clip_rect, lowest_combined_clip_node);
-      lowest_combined_clip_node = nullptr;
-      pending_combined_clip_rect.reset();
-    }
-
-    if (has_rounded_clip_or_clip_path) {
-      // The clip can't be combined with others.
-      StartSingleClip(sub_clip);
     } else {
-      // Start to combine clips.
-      pending_combined_clip_rect = sub_clip->ClipRect().Rect();
+      // |sub_clip| can't be combined to previous clips. Output the current
+      // combined clip, and start new combination.
+      StartClip(pending_combined_clip_rect, lowest_combined_clip_node);
+      pending_combined_clip_rect = sub_clip->ClipRect();
       lowest_combined_clip_node = sub_clip;
     }
   }
-
-  if (pending_combined_clip_rect)
-    StartCombinedClip(*pending_combined_clip_rect, lowest_combined_clip_node);
+  StartClip(pending_combined_clip_rect, lowest_combined_clip_node);
 
   DCHECK_EQ(current_clip_, target_clip);
 }
 
-void ConversionContext::StartCombinedClip(
-    const FloatRect& combined_clip_rect,
+void ConversionContext::StartClip(
+    const FloatRoundedRect& combined_clip_rect,
     const ClipPaintPropertyNode* lowest_combined_clip_node) {
   if (lowest_combined_clip_node->LocalTransformSpace() != current_transform_)
     EndTransform();
@@ -367,8 +382,18 @@
   cc_list_.push<cc::SaveOp>();
   ApplyTransform(lowest_combined_clip_node->LocalTransformSpace());
   const bool antialias = true;
-  cc_list_.push<cc::ClipRectOp>(combined_clip_rect, SkClipOp::kIntersect,
-                                antialias);
+  if (combined_clip_rect.IsRounded()) {
+    cc_list_.push<cc::ClipRRectOp>(combined_clip_rect, SkClipOp::kIntersect,
+                                   antialias);
+  } else {
+    cc_list_.push<cc::ClipRectOp>(combined_clip_rect.Rect(),
+                                  SkClipOp::kIntersect, antialias);
+  }
+  if (lowest_combined_clip_node->ClipPath()) {
+    cc_list_.push<cc::ClipPathOp>(
+        lowest_combined_clip_node->ClipPath()->GetSkPath(),
+        SkClipOp::kIntersect, antialias);
+  }
   cc_list_.EndPaintOfPairedBegin();
 
   PushState(StateEntry::kClip, 1);
@@ -376,30 +401,6 @@
   current_transform_ = lowest_combined_clip_node->LocalTransformSpace();
 }
 
-void ConversionContext::StartSingleClip(const ClipPaintPropertyNode* clip) {
-  if (clip->LocalTransformSpace() != current_transform_)
-    EndTransform();
-  cc_list_.StartPaint();
-  cc_list_.push<cc::SaveOp>();
-  ApplyTransform(clip->LocalTransformSpace());
-  const bool antialias = true;
-  cc_list_.push<cc::ClipRectOp>(static_cast<SkRect>(clip->ClipRect().Rect()),
-                                SkClipOp::kIntersect, antialias);
-  if (clip->ClipRect().IsRounded()) {
-    cc_list_.push<cc::ClipRRectOp>(static_cast<SkRRect>(clip->ClipRect()),
-                                   SkClipOp::kIntersect, antialias);
-  }
-  if (clip->ClipPath()) {
-    cc_list_.push<cc::ClipPathOp>(clip->ClipPath()->GetSkPath(),
-                                  SkClipOp::kIntersect, antialias);
-  }
-  cc_list_.EndPaintOfPairedBegin();
-
-  PushState(StateEntry::kClip, 1);
-  current_clip_ = clip;
-  current_transform_ = clip->LocalTransformSpace();
-}
-
 void ConversionContext::SwitchToEffect(
     const EffectPaintPropertyNode* target_effect) {
   if (target_effect == current_effect_)
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index c565d4f..ba85060 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -129,6 +129,22 @@
     EXPECT_EQ(y, translate->dy);                               \
   } while (false)
 
+#define EXPECT_CLIP(r, op_buffer, index)                      \
+  do {                                                        \
+    const auto* clip_op =                                     \
+        (op_buffer).GetOpAtForTesting<cc::ClipRectOp>(index); \
+    ASSERT_NE(nullptr, clip_op);                              \
+    EXPECT_EQ(SkRect(r), clip_op->rect);                      \
+  } while (false)
+
+#define EXPECT_ROUNDED_CLIP(r, op_buffer, index)               \
+  do {                                                         \
+    const auto* clip_op =                                      \
+        (op_buffer).GetOpAtForTesting<cc::ClipRRectOp>(index); \
+    ASSERT_NE(nullptr, clip_op);                               \
+    EXPECT_EQ(SkRRect(r), clip_op->rrect);                     \
+  } while (false)
+
 // Convenient shorthands.
 const TransformPaintPropertyNode* t0() {
   return TransformPaintPropertyNode::Root();
@@ -691,15 +707,12 @@
 
 TEST_F(PaintChunksToCcLayerTest, CombineClips) {
   FloatRoundedRect clip_rect(0, 0, 100, 100);
-  FloatSize corner(5, 5);
-  FloatRoundedRect rounded_clip_rect(clip_rect.Rect(), corner, corner, corner,
-                                     corner);
   auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
   auto c1 = CreateClip(c0(), t0(), clip_rect);
   auto c2 = CreateClip(c1, t0(), clip_rect);
   auto c3 = CreateClip(c2, t1, clip_rect);
   auto c4 = CreateClip(c3, t1, clip_rect);
-  auto c5 = CreateClip(c4, t1, rounded_clip_rect);
+  auto c5 = CreateClipPathClip(c4, t1, clip_rect);
   auto c6 = CreateClip(c5, t1, clip_rect);
 
   TestChunks chunks;
@@ -715,21 +728,65 @@
   EXPECT_THAT(
       *output,
       PaintRecordMatcher::Make(
-          {cc::PaintOpType::Save,       cc::PaintOpType::ClipRect,  // <c1+c2>
-           cc::PaintOpType::Save,       cc::PaintOpType::Concat,    // <t1
-           cc::PaintOpType::ClipRect,                               //  c3+c4>
-           cc::PaintOpType::Save,       cc::PaintOpType::ClipRect,
-           cc::PaintOpType::ClipRRect,                              // <c5>
-           cc::PaintOpType::Save,       cc::PaintOpType::ClipRect,  // <c6>
-           cc::PaintOpType::DrawRecord,                             // <p0/>
-           cc::PaintOpType::Restore,                                // </c6>
-           cc::PaintOpType::Restore,                                // </c5>
-           cc::PaintOpType::Restore,                              // </c3+c4 t1>
-           cc::PaintOpType::Save,       cc::PaintOpType::Concat,  // <t1
-           cc::PaintOpType::ClipRect,                             // c3>
-           cc::PaintOpType::DrawRecord,                           // <p1/>
-           cc::PaintOpType::Restore,                              // </c3 t1>
-           cc::PaintOpType::Restore}));                           // </c1+c2>
+          {cc::PaintOpType::Save, cc::PaintOpType::ClipRect,      // <c1+c2>
+           cc::PaintOpType::Save, cc::PaintOpType::Concat,        // <t1
+           cc::PaintOpType::ClipRect, cc::PaintOpType::ClipPath,  //  c3+c4+c5>
+           cc::PaintOpType::Save, cc::PaintOpType::ClipRect,      // <c6>
+           cc::PaintOpType::DrawRecord,                           // <p0/>
+           cc::PaintOpType::Restore,                              // </c6>
+           cc::PaintOpType::Restore,                        // </c3+c4+c5 t1>
+           cc::PaintOpType::Save, cc::PaintOpType::Concat,  // <t1
+           cc::PaintOpType::ClipRect,                       // c3>
+           cc::PaintOpType::DrawRecord,                     // <p1/>
+           cc::PaintOpType::Restore,                        // </c3 t1>
+           cc::PaintOpType::Restore}));                     // </c1+c2>
+}
+
+TEST_F(PaintChunksToCcLayerTest, CombineClipsWithRoundedRects) {
+  FloatRoundedRect clip_rect(0, 0, 100, 100);
+  FloatSize corner(5, 5);
+  FloatRoundedRect big_rounded_clip_rect(FloatRect(0, 0, 200, 200), corner,
+                                         corner, corner, corner);
+  FloatRoundedRect small_rounded_clip_rect(FloatRect(0, 0, 100, 100), corner,
+                                           corner, corner, corner);
+
+  auto c1 = CreateClip(c0(), t0(), clip_rect);
+  auto c2 = CreateClip(c1, t0(), small_rounded_clip_rect);
+  auto c3 = CreateClip(c2, t0(), clip_rect);
+  auto c4 = CreateClip(c3, t0(), big_rounded_clip_rect);
+  auto c5 = CreateClip(c4, t0(), clip_rect);
+  auto c6 = CreateClip(c5, t0(), big_rounded_clip_rect);
+  auto c7 = CreateClip(c6, t0(), small_rounded_clip_rect);
+
+  TestChunks chunks;
+  chunks.AddChunk(t0(), c7.get(), e0());
+
+  sk_sp<PaintRecord> output =
+      PaintChunksToCcLayer::Convert(
+          chunks.chunks, PropertyTreeState(t0(), c0(), e0()), gfx::Vector2dF(),
+          chunks.items, cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)
+          ->ReleaseAsRecord();
+
+  EXPECT_THAT(
+      *output,
+      PaintRecordMatcher::Make(
+          {cc::PaintOpType::Save, cc::PaintOpType::ClipRRect,  // <c1+c2+c3>
+           cc::PaintOpType::Save, cc::PaintOpType::ClipRRect,  // <c4>
+           cc::PaintOpType::Save, cc::PaintOpType::ClipRect,   // <c5>
+           cc::PaintOpType::Save, cc::PaintOpType::ClipRRect,  // <c6>
+           cc::PaintOpType::Save, cc::PaintOpType::ClipRRect,  // <c7>
+           cc::PaintOpType::DrawRecord,                        // <p0/>
+           cc::PaintOpType::Restore,                           // </c7>
+           cc::PaintOpType::Restore,                           // </c6>
+           cc::PaintOpType::Restore,                           // </c5>
+           cc::PaintOpType::Restore,                           // </c4>
+           cc::PaintOpType::Restore}));                        // </c1+c2+c3>
+
+  EXPECT_ROUNDED_CLIP(small_rounded_clip_rect, *output, 1);
+  EXPECT_ROUNDED_CLIP(big_rounded_clip_rect, *output, 3);
+  EXPECT_CLIP(clip_rect.Rect(), *output, 5);
+  EXPECT_ROUNDED_CLIP(big_rounded_clip_rect, *output, 7);
+  EXPECT_ROUNDED_CLIP(small_rounded_clip_rect, *output, 9);
 }
 
 TEST_F(PaintChunksToCcLayerTest, ChunksSamePropertyTreeState) {
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index 4e8166c7..d5f9b73 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -35,7 +35,6 @@
   V(WillChangeCompositingHint)                                                \
   V(BackdropFilter)                                                           \
   V(RootScroller)                                                             \
-  V(ScrollTimelineTarget)                                                     \
                                                                               \
   /* Overlap reasons that require knowing what's behind you in paint-order    \
      before knowing the answer. */                                            \
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 1c89c15..017030ae 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -268,6 +268,9 @@
 
 DrawingBuffer::RegisteredBitmap DrawingBuffer::CreateOrRecycleBitmap(
     cc::SharedBitmapIdRegistrar* bitmap_registrar) {
+  // When searching for a hit in SharedBitmap, we don't consider the bitmap
+  // format (RGBA 8888 vs F16). We expect to always have the same bitmap format,
+  // matching the back storage of the drawing buffer.
   auto* it = std::remove_if(recycled_bitmaps_.begin(), recycled_bitmaps_.end(),
                             [this](const RegisteredBitmap& registered) {
                               return registered.bitmap->size() !=
@@ -283,11 +286,14 @@
   }
 
   viz::SharedBitmapId id = viz::SharedBitmap::GenerateId();
+  viz::ResourceFormat format = viz::RGBA_8888;
+  if (use_half_float_storage_)
+    format = viz::RGBA_F16;
   std::unique_ptr<base::SharedMemory> shm =
       viz::bitmap_allocation::AllocateMappedBitmap(
-          static_cast<gfx::Size>(size_), viz::RGBA_8888);
+          static_cast<gfx::Size>(size_), format);
   auto bitmap = base::MakeRefCounted<cc::CrossThreadSharedBitmap>(
-      id, std::move(shm), static_cast<gfx::Size>(size_), viz::RGBA_8888);
+      id, std::move(shm), static_cast<gfx::Size>(size_), format);
   RegisteredBitmap registered = {
       bitmap, bitmap_registrar->RegisterSharedBitmapId(id, bitmap)};
   return registered;
@@ -363,8 +369,11 @@
                         op);
   }
 
+  viz::ResourceFormat format = viz::RGBA_8888;
+  if (use_half_float_storage_)
+    format = viz::RGBA_F16;
   *out_resource = viz::TransferableResource::MakeSoftware(
-      registered.bitmap->id(), static_cast<gfx::Size>(size_), viz::RGBA_8888);
+      registered.bitmap->id(), static_cast<gfx::Size>(size_), format);
   out_resource->color_space = storage_color_space_;
 
   // This holds a ref on the DrawingBuffer that will keep it alive until the
@@ -457,6 +466,8 @@
         is_overlay_candidate);
     out_resource->color_space = sampler_color_space_;
     out_resource->format = viz::RGBA_8888;
+    if (use_half_float_storage_)
+      out_resource->format = viz::RGBA_F16;
 
     // This holds a ref on the DrawingBuffer that will keep it alive until the
     // mailbox is released (and while the release callback is running).
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index 1eb9dd0..872e01a 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -15,9 +15,12 @@
 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
 #include "third_party/blink/public/platform/web_layer.h"
 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
 #include "third_party/blink/renderer/platform/graphics/color_behavior.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace blink {
@@ -135,17 +138,22 @@
                   WrapWeakPersistent(this), std::move(image_for_compositor));
     *out_release_callback = viz::SingleReleaseCallback::Create(std::move(func));
   } else {
-    const gfx::Size size(image_for_compositor->width(),
-                         image_for_compositor->height());
-    RegisteredBitmap registered = CreateOrRecycleBitmap(size, bitmap_registrar);
-
     sk_sp<SkImage> sk_image =
         image_for_compositor->PaintImageForCurrentFrame().GetSkImage();
     if (!sk_image)
       return false;
 
-    SkImageInfo dst_info = SkImageInfo::MakeN32Premul(
-        size.width(), size.height(), sk_image->refColorSpace());
+    const gfx::Size size(image_for_compositor->width(),
+                         image_for_compositor->height());
+    viz::ResourceFormat resource_format = viz::RGBA_8888;
+    if (sk_image->colorType() == SkColorType::kRGBA_F16_SkColorType)
+      resource_format = viz::RGBA_F16;
+    RegisteredBitmap registered =
+        CreateOrRecycleBitmap(size, resource_format, bitmap_registrar);
+
+    SkImageInfo dst_info =
+        SkImageInfo::Make(size.width(), size.height(), sk_image->colorType(),
+                          kPremul_SkAlphaType, sk_image->refColorSpace());
     void* pixels = registered.bitmap->shared_memory()->memory();
 
     // Copy from SkImage into SharedMemory owned by |registered|.
@@ -153,25 +161,32 @@
       return false;
 
     *out_resource = viz::TransferableResource::MakeSoftware(
-        registered.bitmap->id(), size, viz::RGBA_8888);
+        registered.bitmap->id(), size, resource_format);
+    if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
+      out_resource->color_space =
+          SkColorSpaceToGfxColorSpace(sk_image->refColorSpace());
+    }
     auto func = WTF::Bind(&ImageLayerBridge::ResourceReleasedSoftware,
                           WrapWeakPersistent(this), std::move(registered));
     *out_release_callback = viz::SingleReleaseCallback::Create(std::move(func));
   }
 
-  // TODO(junov): Figure out how to get the color space info.
-  // out_resource->color_space = ...;
-
   return true;
 }
 
 ImageLayerBridge::RegisteredBitmap ImageLayerBridge::CreateOrRecycleBitmap(
     const gfx::Size& size,
+    viz::ResourceFormat format,
     cc::SharedBitmapIdRegistrar* bitmap_registrar) {
-  auto* it = std::remove_if(recycled_bitmaps_.begin(), recycled_bitmaps_.end(),
-                            [&size](const RegisteredBitmap& registered) {
-                              return registered.bitmap->size() != size;
-                            });
+  auto* it = std::remove_if(
+      recycled_bitmaps_.begin(), recycled_bitmaps_.end(),
+      [&size, &format](const RegisteredBitmap& registered) {
+        unsigned src_bytes_per_pixel =
+            (registered.bitmap->format() == viz::RGBA_8888) ? 4 : 8;
+        unsigned target_bytes_per_pixel = (format == viz::RGBA_8888) ? 4 : 8;
+        return (registered.bitmap->size().GetArea() * src_bytes_per_pixel !=
+                size.GetArea() * target_bytes_per_pixel);
+      });
   recycled_bitmaps_.Shrink(it - recycled_bitmaps_.begin());
 
   if (!recycled_bitmaps_.IsEmpty()) {
@@ -184,11 +199,11 @@
   // There are no bitmaps to recycle so allocate a new one.
   viz::SharedBitmapId id = viz::SharedBitmap::GenerateId();
   std::unique_ptr<base::SharedMemory> shm =
-      viz::bitmap_allocation::AllocateMappedBitmap(size, viz::RGBA_8888);
+      viz::bitmap_allocation::AllocateMappedBitmap(size, format);
 
   RegisteredBitmap registered;
   registered.bitmap = base::MakeRefCounted<cc::CrossThreadSharedBitmap>(
-      id, std::move(shm), size, viz::RGBA_8888);
+      id, std::move(shm), size, format);
   registered.registration =
       bitmap_registrar->RegisterSharedBitmapId(id, registered.bitmap);
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.h b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.h
index 5b39341..789d0d7 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.h
@@ -9,6 +9,7 @@
 
 #include "cc/layers/texture_layer_client.h"
 #include "cc/resources/shared_bitmap_id_registrar.h"
+#include "components/viz/common/resources/resource_format.h"
 #include "third_party/blink/renderer/platform/geometry/float_point.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
@@ -76,6 +77,7 @@
   // recycled bitmaps that are the wrong size.
   RegisteredBitmap CreateOrRecycleBitmap(
       const gfx::Size& size,
+      viz::ResourceFormat format,
       cc::SharedBitmapIdRegistrar* bitmap_registrar);
 
   void ResourceReleasedGpu(scoped_refptr<StaticBitmapImage>,
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.cc
index 11324c1..5bd931b 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.cc
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.cc
@@ -73,7 +73,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     int placeholder_canvas_id,
     scoped_refptr<blink::StaticBitmapImage> image,
-    unsigned resource_id) {
+    viz::ResourceId resource_id) {
   DCHECK(IsMainThread());
   OffscreenCanvasPlaceholder* placeholder_canvas =
       OffscreenCanvasPlaceholder::GetPlaceholderById(placeholder_canvas_id);
@@ -88,7 +88,7 @@
 
 void OffscreenCanvasFrameDispatcher::PostImageToPlaceholderIfNotBlocked(
     scoped_refptr<StaticBitmapImage> image,
-    unsigned resource_id) {
+    viz::ResourceId resource_id) {
   if (placeholder_canvas_id_ == kInvalidPlaceholderCanvasId) {
     offscreen_canvas_resource_provider_->ReclaimResource(resource_id);
     return;
@@ -116,7 +116,7 @@
 
 void OffscreenCanvasFrameDispatcher::PostImageToPlaceholder(
     scoped_refptr<StaticBitmapImage> image,
-    unsigned resource_id) {
+    viz::ResourceId resource_id) {
   scoped_refptr<base::SingleThreadTaskRunner> dispatcher_task_runner =
       Platform::Current()->CurrentThread()->GetTaskRunner();
 
@@ -414,7 +414,8 @@
   offscreen_canvas_resource_provider_->ReclaimResources(resources);
 }
 
-void OffscreenCanvasFrameDispatcher::ReclaimResource(unsigned resource_id) {
+void OffscreenCanvasFrameDispatcher::ReclaimResource(
+    viz::ResourceId resource_id) {
   offscreen_canvas_resource_provider_->ReclaimResource(resource_id);
   num_unreclaimed_frames_posted_--;
 
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.h b/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.h
index 3ad0540..0b31b80 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.h
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_frame_dispatcher.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h"
@@ -48,7 +49,7 @@
   void DispatchFrame(scoped_refptr<StaticBitmapImage>,
                      double commit_start_time,
                      const SkIRect& damage_rect);
-  void ReclaimResource(unsigned resource_id);
+  void ReclaimResource(viz::ResourceId);
   void Reshape(const IntSize&);
 
   // viz::mojom::blink::CompositorFrameSinkClient implementation.
@@ -90,10 +91,10 @@
 
   bool VerifyImageSize(const IntSize);
   void PostImageToPlaceholderIfNotBlocked(scoped_refptr<StaticBitmapImage>,
-                                          unsigned resource_id);
+                                          viz::ResourceId resource_id);
   // virtual for testing
   virtual void PostImageToPlaceholder(scoped_refptr<StaticBitmapImage>,
-                                      unsigned resource_id);
+                                      viz::ResourceId resource_id);
 
   viz::mojom::blink::CompositorFrameSinkPtr sink_;
   mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient> binding_;
@@ -105,7 +106,7 @@
   // The latest_unposted_resource_id_ always refers to the Id of the frame
   // resource used by the latest_unposted_image_.
   scoped_refptr<StaticBitmapImage> latest_unposted_image_;
-  unsigned latest_unposted_resource_id_;
+  viz::ResourceId latest_unposted_resource_id_;
   unsigned num_unreclaimed_frames_posted_;
 
   viz::BeginFrameAck current_begin_frame_ack_;
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
index 4fd962d..d46bf03 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
@@ -24,7 +24,7 @@
 void releaseFrameToDispatcher(
     base::WeakPtr<blink::OffscreenCanvasFrameDispatcher> dispatcher,
     scoped_refptr<blink::Image> oldImage,
-    unsigned resourceId) {
+    viz::ResourceId resourceId) {
   oldImage = nullptr;  // Needed to unref'ed on the right thread
   if (dispatcher) {
     dispatcher->ReclaimResource(resourceId);
@@ -74,7 +74,7 @@
     scoped_refptr<StaticBitmapImage> new_frame,
     base::WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    unsigned resource_id) {
+    viz::ResourceId resource_id) {
   DCHECK(IsPlaceholderRegistered());
   DCHECK(new_frame);
   ReleasePlaceholderFrame();
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
index 37820d2..9db25c5a 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
+#include "components/viz/common/resources/resource_id.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
@@ -24,7 +25,7 @@
       scoped_refptr<StaticBitmapImage>,
       base::WeakPtr<OffscreenCanvasFrameDispatcher>,
       scoped_refptr<base::SingleThreadTaskRunner>,
-      unsigned resource_id);
+      viz::ResourceId resource_id);
   void ReleasePlaceholderFrame();
 
   void SetSuspendOffscreenCanvasAnimation(bool);
@@ -48,7 +49,7 @@
   scoped_refptr<StaticBitmapImage> placeholder_frame_;
   base::WeakPtr<OffscreenCanvasFrameDispatcher> frame_dispatcher_;
   scoped_refptr<base::SingleThreadTaskRunner> frame_dispatcher_task_runner_;
-  unsigned placeholder_frame_resource_id_ = 0;
+  viz::ResourceId placeholder_frame_resource_id_ = 0;
 
   enum {
     kNoPlaceholderId = -1,
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc
index 84de3f8..591e84cc 100644
--- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_resource_provider.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/typed_arrays/uint8_array.h"
 #include "third_party/khronos/GLES2/gl2.h"
@@ -80,12 +81,12 @@
     frame_resource->provider = this;
     frame_resource->shared_bitmap_id = viz::SharedBitmap::GenerateId();
     frame_resource->shared_memory =
-        viz::bitmap_allocation::AllocateMappedBitmap(
-            gfx::Size(width_, height_), viz::ResourceFormat::RGBA_8888);
+        viz::bitmap_allocation::AllocateMappedBitmap(gfx::Size(width_, height_),
+                                                     resource.format);
     sink_->DidAllocateSharedBitmap(
         viz::bitmap_allocation::DuplicateAndCloseMappedBitmap(
             frame_resource->shared_memory.get(), gfx::Size(width_, height_),
-            viz::ResourceFormat::RGBA_8888),
+            resource.format),
         SharedBitmapIdToGpuMailboxPtr(frame_resource->shared_bitmap_id));
   }
   void* pixels = frame_resource->shared_memory->memory();
@@ -102,6 +103,10 @@
       sk_image->refColorSpace());
   if (image_info.isEmpty())
     return;
+
+  if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) {
+    image_info = image_info.makeColorType(sk_image->colorType());
+  }
   bool read_pixels_successful =
       sk_image->readPixels(image_info, pixels, image_info.minRowBytes(), 0, 0);
   DCHECK(read_pixels_successful);
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc b/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
index 5e245b1..efa048b0 100644
--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
 #include "third_party/skia/include/effects/SkCornerPathEffect.h"
+#include "ui/gfx/icc_profile.h"
 
 #include <algorithm>
 #include <cmath>
@@ -317,6 +318,29 @@
   return SkColorSetA(color, rounded_alpha);
 }
 
+gfx::ColorSpace SkColorSpaceToGfxColorSpace(
+    const sk_sp<SkColorSpace> color_space) {
+  if (!color_space)
+    return gfx::ColorSpace::CreateSRGB();
+
+  SkMatrix44 toXYZD50;
+  SkColorSpaceTransferFn transfer_fn;
+  if (color_space->toXYZD50(&toXYZD50) &&
+      color_space->isNumericalTransferFn(&transfer_fn))
+    return gfx::ColorSpace::CreateCustom(toXYZD50, transfer_fn);
+
+  // Use an intermediate ICC profile to convert the color space data structure.
+  // If this fails, we fall back to sRGB.
+  sk_sp<SkData> sk_profile = color_space->serialize();
+  if (sk_profile) {
+    gfx::ICCProfile icc_profile =
+        gfx::ICCProfile::FromData(sk_profile->data(), sk_profile->size());
+    if (icc_profile.IsValid())
+      return icc_profile.GetColorSpace();
+  }
+  return gfx::ColorSpace::CreateSRGB();
+}
+
 template <typename PrimitiveType>
 void DrawFocusRingPrimitive(const PrimitiveType&,
                             PaintCanvas*,
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
index eec0d2a1..b14892d 100644
--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
@@ -71,6 +71,10 @@
 // alpha is in the range [0, 1].
 SkColor PLATFORM_EXPORT ScaleAlpha(SkColor, float);
 
+// Convert a SkColorSpace to a gfx::ColorSpace
+gfx::ColorSpace PLATFORM_EXPORT
+SkColorSpaceToGfxColorSpace(const sk_sp<SkColorSpace>);
+
 // Skia has problems when passed infinite, etc floats, filter them to 0.
 inline SkScalar WebCoreFloatToSkScalar(float f) {
   return SkFloatToScalar(std::isfinite(f) ? f : 0);
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc b/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc
new file mode 100644
index 0000000..7de98907
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils_test.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+class SkiaUtilsTest : public testing::Test {};
+
+// Tests converting a SkColorSpace to a gfx::ColorSpace
+TEST_F(SkiaUtilsTest, SkColorSpaceToGfxColorSpace) {
+  std::vector<sk_sp<SkColorSpace>> skia_color_spaces;
+
+  SkColorSpace::RenderTargetGamma gammas[] = {
+      SkColorSpace::kLinear_RenderTargetGamma,
+      SkColorSpace::kSRGB_RenderTargetGamma};
+
+  SkColorSpace::Gamut gamuts[] = {
+      SkColorSpace::kSRGB_Gamut, SkColorSpace::kAdobeRGB_Gamut,
+      SkColorSpace::kDCIP3_D65_Gamut, SkColorSpace::kRec2020_Gamut,
+  };
+
+  skia_color_spaces.push_back((SkColorSpace::MakeSRGB())->makeColorSpin());
+
+  for (unsigned gamma_itr = 0; gamma_itr < 2; gamma_itr++) {
+    for (unsigned gamut_itr = 0; gamut_itr < 4; gamut_itr++) {
+      skia_color_spaces.push_back(
+          SkColorSpace::MakeRGB(gammas[gamma_itr], gamuts[gamut_itr]));
+    }
+  }
+
+  std::vector<gfx::ColorSpace> gfx_color_spaces;
+  for (unsigned i = 0; i < skia_color_spaces.size(); i++) {
+    gfx::ColorSpace color_space =
+        SkColorSpaceToGfxColorSpace(skia_color_spaces[i]);
+    ASSERT_TRUE(SkColorSpace::Equals(color_space.ToSkColorSpace().get(),
+                                     skia_color_spaces[i].get()));
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
index bafffea5..45048ff 100644
--- a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
@@ -60,10 +60,9 @@
   if (!grcontext)
     return nullptr;  // Can happen if the context is lost.
 
-  // TODO(crbug.com/782383): This can return a SkColorSpace, which should be
-  // passed along.
+  sk_sp<SkImage> sk_image = paint_image_.GetSkImage();
   sk_sp<SkImage> gpu_skimage =
-      paint_image_.GetSkImage()->makeTextureImage(grcontext, nullptr);
+      sk_image->makeTextureImage(grcontext, sk_image->colorSpace());
   if (!gpu_skimage)
     return nullptr;
 
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index a7fea929..140e6513 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -8,16 +8,14 @@
 import("//testing/test.gni")
 
 declare_args() {
-  # Enables incremental marking in Oilpan.
+  # Build Blink with incremental marking infrastructure for Oilpan.
   #
-  # Note: Incremental marking is currently considered experimental and also
-  # enables 'enable_blink_heap_incremental_marking'. See default value below.
-  enable_blink_heap_incremental_marking = false
-}
+  # To turn on incremental marking also use
+  #   --enable-blink-features=HeapIncrementalMarking
+  enable_blink_heap_incremental_marking = true
 
-declare_args() {
   # Enables heap verification.
-  enable_blink_heap_verification = enable_blink_heap_incremental_marking
+  enable_blink_heap_verification = false
 }
 
 buildflag_header("blink_heap_buildflags") {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 322d26b..54750ac 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -740,8 +740,8 @@
   int64_t encoded_body_length = 0;
   base::Optional<int64_t> downloaded_file_length;
   WebBlobInfo downloaded_blob;
-  loader_->LoadSynchronously(this, request_in, response_out, error_out,
-                             data_out, encoded_data_length, encoded_body_length,
+  loader_->LoadSynchronously(request_in, response_out, error_out, data_out,
+                             encoded_data_length, encoded_body_length,
                              downloaded_file_length, downloaded_blob);
 
   // A message dispatched while synchronously fetching the resource
diff --git a/third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc b/third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc
index ccdce6fa..94509a72 100644
--- a/third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc
@@ -52,7 +52,7 @@
     return base::TimeDelta();  // Makes DoWork post an immediate continuation.
 
   base::TimeDelta delay = next_run_time - now;
-  TRACE_EVENT1("renderer.scheduler", "RealTimeDomain::DelayTillNextTask",
+  TRACE_EVENT1("sequence_manager", "RealTimeDomain::DelayTillNextTask",
                "delay_ms", delay.InMillisecondsF());
 
   // The next task is sometime in the future. DoWork will make sure it gets
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc b/third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc
index a0e553d..fe6a0aae 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc
@@ -7,12 +7,12 @@
 #include <memory>
 #include <utility>
 
+#include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/trace_event/blame_context.h"
 #include "third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/base/time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 
 namespace blink {
 namespace scheduler {
@@ -467,7 +467,7 @@
 void TaskQueueImpl::TraceQueueSize() const {
   bool is_tracing;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(
-      TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing);
+      TRACE_DISABLED_BY_DEFAULT("sequence_manager"), &is_tracing);
   if (!is_tracing)
     return;
 
@@ -477,7 +477,7 @@
     return;
 
   base::AutoLock lock(immediate_incoming_queue_lock_);
-  TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), GetName(),
+  TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("sequence_manager"), GetName(),
                  immediate_incoming_queue().size() +
                      main_thread_only().immediate_work_queue->Size() +
                      main_thread_only().delayed_work_queue->Size() +
@@ -513,7 +513,10 @@
   DCHECK(main_thread_only().delayed_work_queue);
   DCHECK(main_thread_only().immediate_work_queue);
 
-  state->SetString("task_queue_id", PointerToString(this));
+  state->SetString(
+      "task_queue_id",
+      base::StringPrintf("0x%" PRIx64, static_cast<uint64_t>(
+                                           reinterpret_cast<uintptr_t>(this))));
   state->SetBoolean("enabled", IsQueueEnabled());
   state->SetString("time_domain_name",
                    main_thread_only().time_domain->GetName());
@@ -539,7 +542,13 @@
         "delayed_fence_seconds_from_now",
         (main_thread_only().delayed_fence.value() - now).InSecondsF());
   }
-  if (AreVerboseSnapshotsEnabled()) {
+
+  bool verbose = false;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+      TRACE_DISABLED_BY_DEFAULT("sequence_manager.verbose_snapshots"),
+      &verbose);
+
+  if (verbose) {
     state->BeginArray("immediate_incoming_queue");
     QueueAsValueInto(immediate_incoming_queue(), now, state);
     state->EndArray();
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc
index f89e700..7d4cb0f4 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/task_queue_manager_impl.cc
@@ -65,9 +65,16 @@
       weak_factory_(this) {
   // TODO(altimin): Create a sequence checker here.
   DCHECK(controller_->RunsTasksInCurrentSequence());
+
+  TRACE_EVENT_WARMUP_CATEGORY("sequence_manager");
+  TRACE_EVENT_WARMUP_CATEGORY(TRACE_DISABLED_BY_DEFAULT("sequence_manager"));
+  TRACE_EVENT_WARMUP_CATEGORY(
+      TRACE_DISABLED_BY_DEFAULT("sequence_manager.debug"));
+  TRACE_EVENT_WARMUP_CATEGORY(
+      TRACE_DISABLED_BY_DEFAULT("sequence_manager.verbose_snapshots"));
+
   TRACE_EVENT_OBJECT_CREATED_WITH_ID(
-      TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager",
-      this);
+      TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "TaskQueueManager", this);
   main_thread_only().selector.SetTaskQueueSelectorObserver(this);
 
   RegisterTimeDomain(main_thread_only().real_time_domain.get());
@@ -78,8 +85,7 @@
 
 TaskQueueManagerImpl::~TaskQueueManagerImpl() {
   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
-      TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager",
-      this);
+      TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "TaskQueueManager", this);
 
   // TODO(altimin): restore default task runner automatically when
   // ThreadController is destroyed.
@@ -152,9 +158,8 @@
 
 void TaskQueueManagerImpl::UnregisterTaskQueueImpl(
     std::unique_ptr<internal::TaskQueueImpl> task_queue) {
-  TRACE_EVENT1("renderer.scheduler",
-               "TaskQueueManagerImpl::UnregisterTaskQueue", "queue_name",
-               task_queue->GetName());
+  TRACE_EVENT1("sequence_manager", "TaskQueueManagerImpl::UnregisterTaskQueue",
+               "queue_name", task_queue->GetName());
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
 
   main_thread_only().selector.RemoveQueue(task_queue.get());
@@ -185,7 +190,7 @@
 }
 
 void TaskQueueManagerImpl::WakeUpReadyDelayedQueues(LazyNow* lazy_now) {
-  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                "TaskQueueManagerImpl::WakeUpReadyDelayedQueues");
 
   for (TimeDomain* time_domain : main_thread_only().time_domains) {
@@ -260,7 +265,7 @@
   CHECK(Validate());
 
   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
-  TRACE_EVENT0("renderer.scheduler", "TaskQueueManagerImpl::TakeTask");
+  TRACE_EVENT0("sequence_manager", "TaskQueueManagerImpl::TakeTask");
 
   IncomingImmediateWorkMap queues_to_reload;
 
@@ -280,9 +285,8 @@
     bool should_run =
         main_thread_only().selector.SelectWorkQueueToService(&work_queue);
     TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
-        TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
-        "TaskQueueManager", this,
-        AsValueWithSelectorResult(should_run, work_queue));
+        TRACE_DISABLED_BY_DEFAULT("sequence_manager.debug"), "TaskQueueManager",
+        this, AsValueWithSelectorResult(should_run, work_queue));
 
     if (!should_run)
       return base::nullopt;
@@ -371,7 +375,7 @@
 
 void TaskQueueManagerImpl::NotifyWillProcessTask(ExecutingTask* executing_task,
                                                  LazyNow* time_before_task) {
-  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                "TaskQueueManagerImpl::NotifyWillProcessTaskObservers");
   if (executing_task->task_queue->GetQuiescenceMonitored())
     main_thread_only().task_was_run_on_quiescence_monitored_queue = true;
@@ -385,14 +389,14 @@
 
   if (executing_task->task_queue->GetShouldNotifyObservers()) {
     {
-      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                    "TaskQueueManager.WillProcessTaskObservers");
       for (auto& observer : main_thread_only().task_observers)
         observer.WillProcessTask(executing_task->pending_task);
     }
 
     {
-      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                    "TaskQueueManager.QueueNotifyWillProcessTask");
       executing_task->task_queue->NotifyWillProcessTask(
           executing_task->pending_task);
@@ -408,14 +412,14 @@
           MonotonicTimeInSeconds(executing_task->task_start_time);
 
       {
-        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                      "TaskQueueManager.WillProcessTaskTimeObservers");
         for (auto& observer : main_thread_only().task_time_observers)
           observer.WillProcessTask(task_start_time_sec);
       }
 
       {
-        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+        TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                      "TaskQueueManager.QueueOnTaskStarted");
         executing_task->task_queue->OnTaskStarted(
             executing_task->pending_task, executing_task->task_start_time);
@@ -431,7 +435,7 @@
 void TaskQueueManagerImpl::NotifyDidProcessTask(
     const ExecutingTask& executing_task,
     LazyNow* time_after_task) {
-  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                "TaskQueueManagerImpl::NotifyDidProcessTaskObservers");
 
   base::ThreadTicks task_end_thread_time;
@@ -448,28 +452,28 @@
   if (task_start_time_sec) {
     task_end_time_sec = MonotonicTimeInSeconds(time_after_task->Now());
 
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                  "TaskQueueManager.DidProcessTaskTimeObservers");
     for (auto& observer : main_thread_only().task_time_observers)
       observer.DidProcessTask(task_start_time_sec, task_end_time_sec);
   }
 
   {
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                  "TaskQueueManager.DidProcessTaskObservers");
     for (auto& observer : main_thread_only().task_observers)
       observer.DidProcessTask(executing_task.pending_task);
   }
 
   {
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                  "TaskQueueManager.QueueNotifyDidProcessTask");
     executing_task.task_queue->NotifyDidProcessTask(
         executing_task.pending_task);
   }
 
   {
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                  "TaskQueueManager.QueueOnTaskCompleted");
     if (task_start_time_sec && task_end_time_sec) {
       executing_task.task_queue->OnTaskCompleted(
diff --git a/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc b/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc
index 87c247e8..daa997dc 100644
--- a/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc
@@ -71,7 +71,7 @@
   }
   any_sequence().immediate_do_work_posted = true;
 
-  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                "ThreadControllerImpl::ScheduleWork::PostTask");
   task_runner_->PostTask(FROM_HERE, immediate_do_work_closure_);
 }
@@ -101,7 +101,7 @@
   }
 
   base::TimeDelta delay = std::max(base::TimeDelta(), run_time - now);
-  TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+  TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                "ThreadControllerImpl::ScheduleDelayedWork::PostDelayedTask",
                "delay_ms", delay.InMillisecondsF());
 
@@ -234,7 +234,7 @@
     any_sequence().nesting_depth++;
     if (!any_sequence().immediate_do_work_posted) {
       any_sequence().immediate_do_work_posted = true;
-      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+      TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
                    "ThreadControllerImpl::OnBeginNestedRunLoop::PostTask");
       task_runner_->PostTask(FROM_HERE, immediate_do_work_closure_);
     }
diff --git a/third_party/blink/renderer/platform/scheduler/child/worker_scheduler_proxy_unittest.cc b/third_party/blink/renderer/platform/scheduler/child/worker_scheduler_proxy_unittest.cc
index f78b06c36..b04cb85 100644
--- a/third_party/blink/renderer/platform/scheduler/child/worker_scheduler_proxy_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/child/worker_scheduler_proxy_unittest.cc
@@ -3,8 +3,9 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/platform/scheduler/child/worker_scheduler_proxy.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "components/viz/test/ordered_simple_task_runner.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/task_queue_manager_for_test.h"
@@ -84,12 +85,14 @@
 class WorkerSchedulerProxyTest : public testing::Test {
  public:
   WorkerSchedulerProxyTest()
-      : mock_main_thread_task_runner_(
-            new cc::OrderedSimpleTaskRunner(&clock_, true)),
+      : task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+            base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED),
         main_thread_scheduler_(std::make_unique<MainThreadSchedulerImpl>(
-            TaskQueueManagerForTest::Create(nullptr,
-                                            mock_main_thread_task_runner_,
-                                            &clock_),
+            TaskQueueManagerForTest::Create(
+                nullptr,
+                base::ThreadTaskRunnerHandle::Get(),
+                task_environment_.GetMockTickClock()),
             base::nullopt)),
         page_scheduler_(
             std::make_unique<PageSchedulerImpl>(nullptr,
@@ -97,7 +100,10 @@
                                                 false)),
         frame_scheduler_(page_scheduler_->CreateFrameSchedulerImpl(
             nullptr,
-            FrameScheduler::FrameType::kMainFrame)) {}
+            FrameScheduler::FrameType::kMainFrame)) {
+    // Null clock triggers some assertions.
+    task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
+  }
 
   ~WorkerSchedulerProxyTest() override {
     frame_scheduler_.reset();
@@ -106,9 +112,7 @@
   }
 
  protected:
-  base::SimpleTestTickClock clock_;
-  scoped_refptr<cc::OrderedSimpleTaskRunner> mock_main_thread_task_runner_;
-
+  base::test::ScopedTaskEnvironment task_environment_;
   std::unique_ptr<MainThreadSchedulerImpl> main_thread_scheduler_;
   std::unique_ptr<PageSchedulerImpl> page_scheduler_;
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler_;
@@ -133,7 +137,7 @@
   DCHECK(worker_thread->GetWorkerScheduler()->throttling_state() ==
          FrameScheduler::ThrottlingState::kNotThrottled);
 
-  mock_main_thread_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 // Tests below check that no crashes occur during different shutdown sequences.
@@ -153,10 +157,10 @@
          FrameScheduler::ThrottlingState::kThrottled);
 
   frame_scheduler_.reset();
-  mock_main_thread_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   worker_thread.reset();
-  mock_main_thread_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(WorkerSchedulerProxyTest, ThreadDestroyed) {
@@ -174,13 +178,13 @@
          FrameScheduler::ThrottlingState::kThrottled);
 
   worker_thread.reset();
-  mock_main_thread_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   page_scheduler_->SetPageVisible(true);
-  mock_main_thread_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   frame_scheduler_.reset();
-  mock_main_thread_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 }  // namespace scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
index 9aba100d8..7218bb1 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
@@ -5,8 +5,9 @@
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 
 #include <memory>
-#include "base/test/simple_test_tick_clock.h"
-#include "components/viz/test/ordered_simple_task_runner.h"
+#include "base/run_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/scheduler/base/task_queue_manager.h"
@@ -26,19 +27,21 @@
   ~AutoAdvancingVirtualTimeDomainTest() override = default;
 
   void SetUp() override {
-    clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
-
-    mock_task_runner_ =
-        base::MakeRefCounted<cc::OrderedSimpleTaskRunner>(&clock_, false);
-
+    test_task_runner_ = base::WrapRefCounted(new base::TestMockTimeTaskRunner(
+        base::TestMockTimeTaskRunner::Type::kBoundToThread));
+    // A null clock triggers some assertions.
+    test_task_runner_->AdvanceMockTickClock(
+        base::TimeDelta::FromMilliseconds(5));
     scheduler_helper_.reset(new NonMainThreadSchedulerHelper(
-        TaskQueueManagerForTest::Create(nullptr, mock_task_runner_, &clock_),
+        TaskQueueManagerForTest::Create(nullptr,
+                                        base::ThreadTaskRunnerHandle::Get(),
+                                        test_task_runner_->GetMockTickClock()),
         nullptr));
 
     scheduler_helper_->AddTaskTimeObserver(&test_task_time_observer_);
     task_queue_ = scheduler_helper_->DefaultWorkerTaskQueue();
     initial_time_ = base::Time::FromJsTime(100000.0);
-    initial_time_ticks_ = clock_.NowTicks();
+    initial_time_ticks_ = test_task_runner_->NowTicks();
     auto_advancing_time_domain_.reset(new AutoAdvancingVirtualTimeDomain(
         initial_time_, initial_time_ticks_, scheduler_helper_.get(),
         AutoAdvancingVirtualTimeDomain::BaseTimeOverridePolicy::OVERRIDE));
@@ -51,10 +54,9 @@
     scheduler_helper_->UnregisterTimeDomain(auto_advancing_time_domain_.get());
   }
 
+  scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
   base::Time initial_time_;
   base::TimeTicks initial_time_ticks_;
-  base::SimpleTestTickClock clock_;
-  scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
   std::unique_ptr<NonMainThreadSchedulerHelper> scheduler_helper_;
   scoped_refptr<TaskQueue> task_queue_;
   std::unique_ptr<AutoAdvancingVirtualTimeDomain> auto_advancing_time_domain_;
@@ -83,9 +85,9 @@
                                delay);
 
   EXPECT_CALL(mock_observer, OnVirtualTimeAdvanced());
-  mock_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(initial_time_ticks_, clock_.NowTicks());
+  EXPECT_EQ(initial_time_ticks_, test_task_runner_->NowTicks());
   EXPECT_EQ(initial_time_ticks_ + delay,
             auto_advancing_time_domain_->CreateLazyNow().Now());
   EXPECT_TRUE(task_run);
@@ -105,9 +107,9 @@
   auto_advancing_time_domain_->SetCanAdvanceVirtualTime(false);
 
   EXPECT_CALL(mock_observer, OnVirtualTimeAdvanced()).Times(0);
-  mock_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(initial_time_ticks_, clock_.NowTicks());
+  EXPECT_EQ(initial_time_ticks_, test_task_runner_->NowTicks());
   EXPECT_EQ(initial_time_ticks_,
             auto_advancing_time_domain_->CreateLazyNow().Now());
   EXPECT_FALSE(task_run);
@@ -145,7 +147,7 @@
       base::BindOnce(DelayedTask, &count, &delayed_task_run_at_count),
       base::TimeDelta::FromMilliseconds(10));
 
-  mock_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1000, count);
   EXPECT_EQ(102, delayed_task_run_at_count);
@@ -164,7 +166,7 @@
       base::BindOnce(DelayedTask, &count, &delayed_task_run_at_count),
       base::TimeDelta::FromMilliseconds(10));
 
-  mock_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1000, count);
   // If the initial count had been higher, the delayed task could have been
@@ -206,13 +208,13 @@
   bool task_run = false;
   task_queue_->PostDelayedTask(FROM_HERE, base::BindOnce(NopTask, &task_run),
                                delay);
-  mock_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(base::Time::Now(), initial_time + delay);
 }
 
 TEST_F(AutoAdvancingVirtualTimeDomainTest, BaseTimeTicksOverriden) {
-  base::TimeTicks initial_time = clock_.NowTicks();
+  base::TimeTicks initial_time = test_task_runner_->NowTicks();
   EXPECT_EQ(base::TimeTicks::Now(), initial_time);
 
   // Make time advance.
@@ -220,14 +222,14 @@
   bool task_run = false;
   task_queue_->PostDelayedTask(FROM_HERE, base::BindOnce(NopTask, &task_run),
                                delay);
-  mock_task_runner_->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(base::TimeTicks::Now(), initial_time + delay);
 }
 
 TEST_F(AutoAdvancingVirtualTimeDomainTest,
        DelayTillNextTaskHandlesPastRunTime) {
-  base::TimeTicks initial_time = clock_.NowTicks();
+  base::TimeTicks initial_time = test_task_runner_->NowTicks();
 
   // Post a task for t+10ms.
   bool task_run = false;
diff --git a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc b/third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc
index bf720bd..f24c423 100644
--- a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc
@@ -17,14 +17,6 @@
 const char kTracingCategoryNameDebug[] =
     TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug");
 
-namespace {
-
-// No trace events should be created with this category.
-const char kTracingCategoryNameVerboseSnapshots[] =
-    TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.enable_verbose_snapshots");
-
-}  // namespace
-
 namespace internal {
 
 void ValidateTracingCategory(const char* category) {
@@ -40,19 +32,11 @@
 
 }  // namespace internal
 
-bool AreVerboseSnapshotsEnabled() {
-  bool result = false;
-  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTracingCategoryNameVerboseSnapshots,
-                                     &result);
-  return result;
-}
-
 void WarmupTracingCategories() {
   // No need to warm-up toplevel category here.
   TRACE_EVENT_WARMUP_CATEGORY(kTracingCategoryNameDefault);
   TRACE_EVENT_WARMUP_CATEGORY(kTracingCategoryNameInfo);
   TRACE_EVENT_WARMUP_CATEGORY(kTracingCategoryNameDebug);
-  TRACE_EVENT_WARMUP_CATEGORY(kTracingCategoryNameVerboseSnapshots);
 }
 
 std::string PointerToString(const void* pointer) {
diff --git a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.h b/third_party/blink/renderer/platform/scheduler/util/tracing_helper.h
index f9d4647..75e41431 100644
--- a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/util/tracing_helper.h
@@ -34,8 +34,6 @@
 
 PLATFORM_EXPORT void WarmupTracingCategories();
 
-PLATFORM_EXPORT bool AreVerboseSnapshotsEnabled();
-
 PLATFORM_EXPORT std::string PointerToString(const void* pointer);
 
 PLATFORM_EXPORT double TimeDeltaToMilliseconds(const base::TimeDelta& value);
diff --git a/third_party/blink/renderer/platform/scroll/scrollbar.cc b/third_party/blink/renderer/platform/scroll/scrollbar.cc
index ffca17f..8c24190 100644
--- a/third_party/blink/renderer/platform/scroll/scrollbar.cc
+++ b/third_party/blink/renderer/platform/scroll/scrollbar.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/public/platform/web_gesture_event.h"
 #include "third_party/blink/public/platform/web_mouse_event.h"
 #include "third_party/blink/public/platform/web_scrollbar.h"
+#include "third_party/blink/public/platform/web_scrollbar_overlay_color_theme.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
 #include "third_party/blink/renderer/platform/platform_chrome_client.h"
@@ -644,25 +645,6 @@
 STATIC_ASSERT_ENUM(WebScrollbar::kHorizontal, kHorizontalScrollbar);
 STATIC_ASSERT_ENUM(WebScrollbar::kVertical, kVerticalScrollbar);
 
-STATIC_ASSERT_ENUM(WebScrollbar::kScrollByLine, kScrollByLine);
-STATIC_ASSERT_ENUM(WebScrollbar::kScrollByPage, kScrollByPage);
-STATIC_ASSERT_ENUM(WebScrollbar::kScrollByDocument, kScrollByDocument);
-STATIC_ASSERT_ENUM(WebScrollbar::kScrollByPixel, kScrollByPixel);
-
-STATIC_ASSERT_ENUM(WebScrollbar::kRegularScrollbar, kRegularScrollbar);
-STATIC_ASSERT_ENUM(WebScrollbar::kSmallScrollbar, kSmallScrollbar);
-STATIC_ASSERT_ENUM(WebScrollbar::kNoPart, kNoPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kBackButtonStartPart, kBackButtonStartPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kForwardButtonStartPart,
-                   kForwardButtonStartPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kBackTrackPart, kBackTrackPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kThumbPart, kThumbPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kForwardTrackPart, kForwardTrackPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kBackButtonEndPart, kBackButtonEndPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kForwardButtonEndPart, kForwardButtonEndPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kScrollbarBGPart, kScrollbarBGPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kTrackBGPart, kTrackBGPart);
-STATIC_ASSERT_ENUM(WebScrollbar::kAllParts, kAllParts);
 STATIC_ASSERT_ENUM(kWebScrollbarOverlayColorThemeDark,
                    kScrollbarOverlayColorThemeDark);
 STATIC_ASSERT_ENUM(kWebScrollbarOverlayColorThemeLight,
diff --git a/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc b/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc
index f1a65fc..9f51af6e 100644
--- a/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc
+++ b/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc
@@ -7,22 +7,43 @@
 #include "third_party/blink/public/platform/web_point.h"
 #include "third_party/blink/public/platform/web_rect.h"
 #include "third_party/blink/public/platform/web_scrollbar.h"
-#include "third_party/blink/public/platform/web_scrollbar_theme_geometry.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
+#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
+#include "third_party/blink/renderer/platform/scroll/scrollbar.h"
+#include "third_party/blink/renderer/platform/scroll/scrollbar_theme.h"
+#include "ui/gfx/skia_util.h"
 
 namespace blink {
 
-ScrollbarLayerDelegate::ScrollbarLayerDelegate(
-    std::unique_ptr<WebScrollbar> scrollbar,
-    WebScrollbarThemePainter painter,
-    std::unique_ptr<WebScrollbarThemeGeometry> geometry)
-    : scrollbar_(std::move(scrollbar)),
-      painter_(painter),
-      geometry_(std::move(geometry)) {}
+namespace {
+
+class ScopedScrollbarPainter {
+ public:
+  ScopedScrollbarPainter(cc::PaintCanvas& canvas, float device_scale_factor)
+      : canvas_(canvas) {
+    builder_.Context().SetDeviceScaleFactor(device_scale_factor);
+  }
+  ~ScopedScrollbarPainter() { canvas_.drawPicture(builder_.EndRecording()); }
+
+  GraphicsContext& Context() { return builder_.Context(); }
+
+ private:
+  cc::PaintCanvas& canvas_;
+  PaintRecordBuilder builder_;
+};
+
+}  // namespace
+
+ScrollbarLayerDelegate::ScrollbarLayerDelegate(blink::Scrollbar& scrollbar,
+                                               float device_scale_factor)
+    : scrollbar_(&scrollbar),
+      theme_(scrollbar.GetTheme()),
+      device_scale_factor_(device_scale_factor) {}
 
 ScrollbarLayerDelegate::~ScrollbarLayerDelegate() = default;
 
 cc::ScrollbarOrientation ScrollbarLayerDelegate::Orientation() const {
-  if (scrollbar_->GetOrientation() == WebScrollbar::kHorizontal)
+  if (scrollbar_->Orientation() == kHorizontalScrollbar)
     return cc::HORIZONTAL;
   return cc::VERTICAL;
 }
@@ -32,109 +53,122 @@
 }
 
 bool ScrollbarLayerDelegate::HasThumb() const {
-  return geometry_->HasThumb(scrollbar_.get());
+  return theme_.HasThumb(*scrollbar_);
 }
 
 bool ScrollbarLayerDelegate::IsOverlay() const {
-  return scrollbar_->IsOverlay();
+  return scrollbar_->IsOverlayScrollbar();
 }
 
 gfx::Point ScrollbarLayerDelegate::Location() const {
-  return static_cast<gfx::Point>(scrollbar_->Location());
+  return scrollbar_->Location();
 }
 
 int ScrollbarLayerDelegate::ThumbThickness() const {
-  auto thumb_rect =
-      static_cast<gfx::Rect>(geometry_->ThumbRect(scrollbar_.get()));
-  if (scrollbar_->GetOrientation() == WebScrollbar::kHorizontal)
-    return thumb_rect.height();
-  return thumb_rect.width();
+  IntRect thumb_rect = theme_.ThumbRect(*scrollbar_);
+  if (scrollbar_->Orientation() == kHorizontalScrollbar)
+    return thumb_rect.Height();
+  return thumb_rect.Width();
 }
 
 int ScrollbarLayerDelegate::ThumbLength() const {
-  auto thumb_rect =
-      static_cast<gfx::Rect>(geometry_->ThumbRect(scrollbar_.get()));
-  if (scrollbar_->GetOrientation() == WebScrollbar::kHorizontal)
-    return thumb_rect.width();
-  return thumb_rect.height();
+  IntRect thumb_rect = theme_.ThumbRect(*scrollbar_);
+  if (scrollbar_->Orientation() == kHorizontalScrollbar)
+    return thumb_rect.Width();
+  return thumb_rect.Height();
 }
 
 gfx::Rect ScrollbarLayerDelegate::TrackRect() const {
-  return static_cast<gfx::Rect>(geometry_->TrackRect(scrollbar_.get()));
+  return theme_.TrackRect(*scrollbar_);
 }
 
 float ScrollbarLayerDelegate::ThumbOpacity() const {
-  return painter_.ThumbOpacity();
+  return theme_.ThumbOpacity(*scrollbar_);
 }
 
 bool ScrollbarLayerDelegate::NeedsPaintPart(cc::ScrollbarPart part) const {
   if (part == cc::THUMB)
-    return painter_.ThumbNeedsRepaint();
-  return painter_.TrackNeedsRepaint();
+    return scrollbar_->ThumbNeedsRepaint();
+  return scrollbar_->TrackNeedsRepaint();
 }
 
 bool ScrollbarLayerDelegate::UsesNinePatchThumbResource() const {
-  return painter_.UsesNinePatchThumbResource();
+  return theme_.UsesNinePatchThumbResource();
 }
 
 gfx::Size ScrollbarLayerDelegate::NinePatchThumbCanvasSize() const {
-  return static_cast<gfx::Size>(
-      geometry_->NinePatchThumbCanvasSize(scrollbar_.get()));
+  DCHECK(theme_.UsesNinePatchThumbResource());
+  return static_cast<gfx::Size>(theme_.NinePatchThumbCanvasSize(*scrollbar_));
 }
 
 gfx::Rect ScrollbarLayerDelegate::NinePatchThumbAperture() const {
-  return static_cast<gfx::Rect>(
-      geometry_->NinePatchThumbAperture(scrollbar_.get()));
+  DCHECK(theme_.UsesNinePatchThumbResource());
+  return theme_.NinePatchThumbAperture(*scrollbar_);
 }
 
 bool ScrollbarLayerDelegate::HasTickmarks() const {
-  return scrollbar_->HasTickmarks();
+  Vector<IntRect> tickmarks;
+  scrollbar_->GetTickmarks(tickmarks);
+  return !tickmarks.IsEmpty();
 }
 
 void ScrollbarLayerDelegate::PaintPart(cc::PaintCanvas* canvas,
                                        cc::ScrollbarPart part,
                                        const gfx::Rect& content_rect) {
+  PaintCanvasAutoRestore auto_restore(canvas, true);
+  blink::Scrollbar& scrollbar = *scrollbar_;
+
   if (part == cc::THUMB) {
-    painter_.PaintThumb(canvas, WebRect(content_rect));
+    ScopedScrollbarPainter painter(*canvas, device_scale_factor_);
+    theme_.PaintThumb(painter.Context(), scrollbar, IntRect(content_rect));
+    if (!theme_.ShouldRepaintAllPartsOnInvalidation())
+      scrollbar.ClearThumbNeedsRepaint();
     return;
   }
 
   if (part == cc::TICKMARKS) {
-    painter_.PaintTickmarks(canvas, WebRect(content_rect));
+    ScopedScrollbarPainter painter(*canvas, device_scale_factor_);
+    theme_.PaintTickmarks(painter.Context(), scrollbar, IntRect(content_rect));
     return;
   }
 
-  // The following is a simplification of ScrollbarThemeComposite::paint.
-  painter_.PaintScrollbarBackground(canvas, WebRect(content_rect));
+  canvas->clipRect(gfx::RectToSkRect(content_rect));
+  ScopedScrollbarPainter painter(*canvas, device_scale_factor_);
+  GraphicsContext& context = painter.Context();
 
-  if (geometry_->HasButtons(scrollbar_.get())) {
-    WebRect back_button_start_paint_rect =
-        geometry_->BackButtonStartRect(scrollbar_.get());
-    painter_.PaintBackButtonStart(canvas, back_button_start_paint_rect);
+  theme_.PaintScrollbarBackground(context, scrollbar);
 
-    WebRect back_button_end_paint_rect =
-        geometry_->BackButtonEndRect(scrollbar_.get());
-    painter_.PaintBackButtonEnd(canvas, back_button_end_paint_rect);
-
-    WebRect forward_button_start_paint_rect =
-        geometry_->ForwardButtonStartRect(scrollbar_.get());
-    painter_.PaintForwardButtonStart(canvas, forward_button_start_paint_rect);
-
-    WebRect forward_button_end_paint_rect =
-        geometry_->ForwardButtonEndRect(scrollbar_.get());
-    painter_.PaintForwardButtonEnd(canvas, forward_button_end_paint_rect);
+  if (theme_.HasButtons(scrollbar)) {
+    theme_.PaintButton(context, scrollbar,
+                       theme_.BackButtonRect(scrollbar, kBackButtonStartPart),
+                       kBackButtonStartPart);
+    theme_.PaintButton(context, scrollbar,
+                       theme_.BackButtonRect(scrollbar, kBackButtonEndPart),
+                       kBackButtonEndPart);
+    theme_.PaintButton(
+        context, scrollbar,
+        theme_.ForwardButtonRect(scrollbar, kForwardButtonStartPart),
+        kForwardButtonStartPart);
+    theme_.PaintButton(
+        context, scrollbar,
+        theme_.ForwardButtonRect(scrollbar, kForwardButtonEndPart),
+        kForwardButtonEndPart);
   }
 
-  WebRect track_paint_rect = geometry_->TrackRect(scrollbar_.get());
-  painter_.PaintTrackBackground(canvas, track_paint_rect);
+  IntRect track_paint_rect = theme_.TrackRect(scrollbar);
+  theme_.PaintTrackBackground(context, scrollbar, track_paint_rect);
 
-  bool thumb_present = geometry_->HasThumb(scrollbar_.get());
-  if (thumb_present) {
-    painter_.PaintForwardTrackPart(canvas, track_paint_rect);
-    painter_.PaintBackTrackPart(canvas, track_paint_rect);
+  if (theme_.HasThumb(scrollbar)) {
+    theme_.PaintTrackPiece(painter.Context(), scrollbar, track_paint_rect,
+                           kForwardTrackPart);
+    theme_.PaintTrackPiece(painter.Context(), scrollbar, track_paint_rect,
+                           kBackTrackPart);
   }
 
-  painter_.PaintTickmarks(canvas, track_paint_rect);
+  theme_.PaintTickmarks(painter.Context(), scrollbar, track_paint_rect);
+
+  if (!theme_.ShouldRepaintAllPartsOnInvalidation())
+    scrollbar.ClearTrackNeedsRepaint();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.h b/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.h
index e3a016b..819ce5bd 100644
--- a/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.h
+++ b/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.h
@@ -10,20 +10,20 @@
 #include "base/macros.h"
 #include "cc/input/scrollbar.h"
 #include "cc/paint/paint_canvas.h"
-#include "third_party/blink/public/platform/web_scrollbar_theme_painter.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
-class WebScrollbar;
-class WebScrollbarThemeGeometry;
+
+class Scrollbar;
+class ScrollbarTheme;
 
 // Implementation of cc::Scrollbar, providing a delegate to query about
 // scrollbar state and to paint the image in the scrollbar.
 class PLATFORM_EXPORT ScrollbarLayerDelegate : public cc::Scrollbar {
  public:
-  ScrollbarLayerDelegate(std::unique_ptr<WebScrollbar> scrollbar,
-                         WebScrollbarThemePainter painter,
-                         std::unique_ptr<WebScrollbarThemeGeometry> geometry);
+  ScrollbarLayerDelegate(blink::Scrollbar& scrollbar,
+                         float device_scale_factor);
   ~ScrollbarLayerDelegate() override;
 
   // cc::Scrollbar implementation.
@@ -47,9 +47,12 @@
   gfx::Rect NinePatchThumbAperture() const override;
 
  private:
-  std::unique_ptr<WebScrollbar> scrollbar_;
-  WebScrollbarThemePainter painter_;
-  std::unique_ptr<WebScrollbarThemeGeometry> geometry_;
+  // Accessed by main and compositor threads, e.g., the compositor thread
+  // checks |Orientation()|.
+  CrossThreadPersistent<blink::Scrollbar> scrollbar_;
+
+  ScrollbarTheme& theme_;
+  float device_scale_factor_;
 
   DISALLOW_COPY_AND_ASSIGN(ScrollbarLayerDelegate);
 };
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
index fdf8d3a0..e62fb94 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
@@ -104,7 +104,6 @@
 }
 
 void WebURLLoaderMock::LoadSynchronously(
-    WebURLLoaderClient* client,
     const WebURLRequest& request,
     WebURLResponse& response,
     base::Optional<WebURLError>& error,
@@ -120,7 +119,7 @@
   }
   AssertFallbackLoaderAvailability(request.Url(), default_loader_.get());
   using_default_loader_ = true;
-  default_loader_->LoadSynchronously(client, request, response, error, data,
+  default_loader_->LoadSynchronously(request, response, error, data,
                                      encoded_data_length, encoded_body_length,
                                      downloaded_file_length, downloaded_blob);
 }
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.h b/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
index 7d60dc4c..4907c05 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
@@ -45,8 +45,7 @@
                        const WebURLResponse& redirect_response);
 
   // WebURLLoader methods:
-  void LoadSynchronously(WebURLLoaderClient*,
-                         const WebURLRequest&,
+  void LoadSynchronously(const WebURLRequest&,
                          WebURLResponse&,
                          base::Optional<WebURLError>&,
                          WebData&,
diff --git a/third_party/fuchsia-sdk/fidl_library.gni b/third_party/fuchsia-sdk/fidl_library.gni
index 1dd93e0..2cdec6e 100644
--- a/third_party/fuchsia-sdk/fidl_library.gni
+++ b/third_party/fuchsia-sdk/fidl_library.gni
@@ -4,18 +4,6 @@
 
 assert(is_fuchsia)
 
-# Template for FIDL libraries. Following parameters can be passed when
-# instantiating these templates:
-#   sources   - List of .fidl files.
-#   name      - (optional) Name of the library. Must match the name specified
-#               in the .fidl files. target_name is used if name is not specified
-#               explicitly.
-#   deps      - (optional) List of other fild_library() targets that this FIDL
-#               library depends on.
-#   namespace - (optional) Namespace for generated code. All classes in the
-#               generated code are placed under <namespace>::<name>:: namespace.
-#               'fuchsia' namespace is used by default.
-#
 template("fidl_library") {
   pkg_name = target_name
 
@@ -24,16 +12,10 @@
     pkg_name = invoker.name
   }
 
-  namespace = "fuchsia"
-  if (defined(invoker.namespace)) {
-    namespace = invoker.namespace
-  }
-
   response_file = "$target_gen_dir/$target_name.rsp"
   json_representation = "$target_gen_dir/$pkg_name.fidl.json"
   output_gen_base = "$target_gen_dir/fidl"
   output_gen_dir = "$output_gen_base/fuchsia/cpp"
-  output_gen_dir_no_ns = "$output_gen_base/no_ns/fuchsia/cpp"
   tables_file = "$output_gen_base/$pkg_name.fidl-tables.cc"
 
   action("${target_name}_response_file") {
@@ -125,7 +107,7 @@
   }
 
   action("${target_name}_cpp_gen") {
-    visibility = [ ":${invoker.target_name}_update_namespace" ]
+    visibility = [ ":${invoker.target_name}" ]
 
     deps = [
       ":${invoker.target_name}_compile",
@@ -136,8 +118,8 @@
     ]
 
     outputs = [
-      "${output_gen_dir_no_ns}/${pkg_name}.h",
-      "${output_gen_dir_no_ns}/${pkg_name}.cc",
+      "$output_gen_dir/$pkg_name.h",
+      "$output_gen_dir/$pkg_name.cc",
     ]
 
     script = "//build/gn_run_binary.py"
@@ -149,37 +131,9 @@
       "-json",
       rebase_path("$json_representation"),
       "-include-base",
-      rebase_path("$output_gen_base/no_ns"),
+      rebase_path("$output_gen_base"),
       "-output-base",
-      rebase_path("${output_gen_dir_no_ns}/${pkg_name}"),
-    ]
-  }
-
-  # Move generated code to a different namespace to avoid conflicts with
-  # existing code in chromium.
-  # TODO(sergeyu): Remove this once FIDL-160 is resolved in Fuchsia.
-  action_foreach("${target_name}_update_namespace") {
-    visibility = [ ":${invoker.target_name}" ]
-
-    deps = [
-      ":${invoker.target_name}_cpp_gen",
-    ]
-
-    sources = [
-      "${output_gen_dir_no_ns}/${pkg_name}.cc",
-      "${output_gen_dir_no_ns}/${pkg_name}.h",
-    ]
-
-    outputs = [
-      "${output_gen_dir}/{{source_file_part}}",
-    ]
-
-    script = "//third_party/fuchsia-sdk/update_namespace.py"
-    args = [
-      namespace,
-      pkg_name,
-      "{{source}}",
-      rebase_path("${output_gen_dir}/{{source_file_part}}"),
+      rebase_path("$output_gen_dir/$pkg_name"),
     ]
   }
 
@@ -208,7 +162,7 @@
     }
     deps += [
       ":${invoker.target_name}_compile",
-      ":${invoker.target_name}_update_namespace",
+      ":${invoker.target_name}_cpp_gen",
     ]
 
     if (!defined(public_deps)) {
diff --git a/third_party/fuchsia-sdk/update_namespace.py b/third_party/fuchsia-sdk/update_namespace.py
deleted file mode 100755
index 8af1300..0000000
--- a/third_party/fuchsia-sdk/update_namespace.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Helper script used to update namespace in C++ files generated by fidlgen. This
-# is necessary to avoid naming conflicts with existing code in chromium. For
-# example ui::Event FIDL interface collides with ui::Event class in chromium.
-# This script moves it to fuchsia::ui::Event.
-#
-# TODO(sergeyu): Remove this script once FIDL files in fuchsia are updated to
-# use fuchsia namespace.
-
-import sys
-import re
-
-def main(namespace, libname, input_file, output_file):
-  with open(input_file) as f:
-    text = f.read()
-
-  text = re.sub(r'^namespace\ %s\ \{$' % libname,
-                r'namespace %s {\nnamespace %s {' %
-                    (namespace, libname),
-                text, flags=re.MULTILINE)
-
-  text = re.sub(r'}\ \ // namespace\ %s$' % libname,
-                r'}  // namespace %s\n}  // namespace %s'
-                    % (libname, namespace),
-                text, flags=re.MULTILINE)
-
-  text = re.sub(r'(?<![a-z0-9_])%s::' % libname,
-                r'%s::%s::' % (namespace, libname),
-                text)
-
-  with open(output_file, "w") as f:
-    f.write(text)
-
-if __name__ == "__main__":
-  sys.exit(main(*sys.argv[1:]))
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json
index ca3c042..856ef054 100644
--- a/third_party/polymer/v1_0/bower.json
+++ b/third_party/polymer/v1_0/bower.json
@@ -49,7 +49,6 @@
     "paper-spinner": "PolymerElements/paper-spinner#2.0.0",
     "paper-styles": "PolymerElements/paper-styles#2.1.0",
     "paper-tabs": "PolymerElements/paper-tabs#2.0.0",
-    "paper-toggle-button": "PolymerElements/paper-toggle-button#2.0.0",
     "paper-tooltip": "PolymerElements/paper-tooltip#2.0.0",
     "polymer": "Polymer/polymer#1.11.2",
     "web-animations-js": "web-animations/web-animations-js#2.2.2"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/BUILD.gn
deleted file mode 100644
index 27e126e..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/BUILD.gn
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# NOTE: Created with generate_gn.py, please do not edit.
-
-import("//third_party/closure_compiler/compile_js.gni")
-
-js_library("paper-toggle-button-extracted") {
-  deps = [
-    "../paper-behaviors:paper-checked-element-behavior-extracted",
-  ]
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json
deleted file mode 100644
index ec1aad1..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/bower.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
-  "name": "paper-toggle-button",
-  "version": "2.0.0",
-  "description": "A material design toggle button control",
-  "authors": [
-    "The Polymer Authors"
-  ],
-  "keywords": [
-    "web-components",
-    "polymer",
-    "toggle",
-    "control"
-  ],
-  "private": true,
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/PolymerElements/paper-toggle-button"
-  },
-  "license": "http://polymer.github.io/LICENSE.txt",
-  "homepage": "https://github.com/PolymerElements/paper-toggle-button",
-  "main": "paper-toggle-button.html",
-  "ignore": [],
-  "dependencies": {
-    "polymer": "Polymer/polymer#1.9 - 2",
-    "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#1 - 2",
-    "paper-behaviors": "PolymerElements/paper-behaviors#1 - 2",
-    "paper-styles": "PolymerElements/paper-styles#1 - 2"
-  },
-  "devDependencies": {
-    "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
-    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#1 - 2",
-    "iron-flex-layout": "PolymerElements/iron-flex-layout#1 - 2",
-    "iron-test-helpers": "PolymerElements/iron-test-helpers#1 - 2",
-    "web-component-tester": "^6.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
-  },
-  "variants": {
-    "1.x": {
-      "dependencies": {
-        "polymer": "Polymer/polymer#^1.9",
-        "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#^1.0.0",
-        "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0",
-        "paper-styles": "PolymerElements/paper-styles#^1.1.0"
-      },
-      "devDependencies": {
-        "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
-        "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
-        "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
-        "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
-        "web-component-tester": "^4.0.0",
-        "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
-      },
-      "resolutions": {
-        "webcomponentsjs": "^0.7"
-      }
-    }
-  },
-  "resolutions": {
-    "webcomponentsjs": "^1.0.0"
-  }
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp
deleted file mode 100644
index a383b61..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/compiled_resources2.gyp
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# NOTE: Created with generate_compiled_resources_gyp.py, please do not edit.
-{
-  'targets': [
-    {
-      'target_name': 'paper-toggle-button-extracted',
-      'dependencies': [
-        '../paper-behaviors/compiled_resources2.gyp:paper-checked-element-behavior-extracted',
-      ],
-      'includes': ['../../../../closure_compiler/compile_js2.gypi'],
-    },
-  ],
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button-extracted.js
deleted file mode 100644
index c36b2f8..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button-extracted.js
+++ /dev/null
@@ -1,81 +0,0 @@
-Polymer({
-      is: 'paper-toggle-button',
-
-      behaviors: [
-        Polymer.PaperCheckedElementBehavior
-      ],
-
-      hostAttributes: {
-        role: 'button',
-        'aria-pressed': 'false',
-        tabindex: 0
-      },
-
-      properties: {
-        /**
-         * Fired when the checked state changes due to user interaction.
-         *
-         * @event change
-         */
-        /**
-         * Fired when the checked state changes.
-         *
-         * @event iron-change
-         */
-      },
-
-      listeners: {
-        track: '_ontrack'
-      },
-
-      attached: function() {
-        Polymer.RenderStatus.afterNextRender(this, function() {
-          Polymer.Gestures.setTouchAction(this, 'pan-y');
-        });
-      },
-
-      _ontrack: function(event) {
-        var track = event.detail;
-        if (track.state === 'start') {
-          this._trackStart(track);
-        } else if (track.state === 'track') {
-          this._trackMove(track);
-        } else if (track.state === 'end') {
-          this._trackEnd(track);
-        }
-      },
-
-      _trackStart: function(track) {
-        this._width = this.$.toggleBar.offsetWidth / 2;
-        /*
-         * keep an track-only check state to keep the dragging behavior smooth
-         * while toggling activations
-         */
-        this._trackChecked = this.checked;
-        this.$.toggleButton.classList.add('dragging');
-      },
-
-      _trackMove: function(track) {
-        var dx = track.dx;
-        this._x = Math.min(this._width,
-            Math.max(0, this._trackChecked ? this._width + dx : dx));
-        this.translate3d(this._x + 'px', 0, 0, this.$.toggleButton);
-        this._userActivate(this._x > (this._width / 2));
-      },
-
-      _trackEnd: function(track) {
-        this.$.toggleButton.classList.remove('dragging');
-        this.transform('', this.$.toggleButton);
-      },
-
-      // customize the element's ripple
-      _createRipple: function() {
-        this._rippleContainer = this.$.toggleButton;
-        var ripple = Polymer.PaperRippleBehavior._createRipple();
-        ripple.id = 'ink';
-        ripple.setAttribute('recenters', '');
-        ripple.classList.add('circle', 'toggle-ink');
-        return ripple;
-      }
-
-    });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html b/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html
deleted file mode 100644
index 496e6c14..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html
+++ /dev/null
@@ -1,200 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
-<link rel="import" href="../paper-styles/color.html">
-<link rel="import" href="../paper-styles/default-theme.html">
-<link rel="import" href="../paper-behaviors/paper-checked-element-behavior.html">
-
-<!--
-Material design: [Switch](https://www.google.com/design/spec/components/selection-controls.html#selection-controls-switch)
-
-`paper-toggle-button` provides a ON/OFF switch that user can toggle the state
-by tapping or by dragging the switch.
-
-Example:
-
-    <paper-toggle-button></paper-toggle-button>
-
-### Styling
-
-The following custom properties and mixins are available for styling:
-
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-toggle-button-unchecked-bar-color` | Slider color when the input is not checked | `#000000`
-`--paper-toggle-button-unchecked-button-color` | Button color when the input is not checked | `--paper-grey-50`
-`--paper-toggle-button-unchecked-ink-color` | Selected/focus ripple color when the input is not checked | `--dark-primary-color`
-`--paper-toggle-button-checked-bar-color` | Slider button color when the input is checked | `--primary-color`
-`--paper-toggle-button-checked-button-color` | Button color when the input is checked | `--primary-color`
-`--paper-toggle-button-checked-ink-color` | Selected/focus ripple color when the input is checked | `--primary-color`
-`--paper-toggle-button-invalid-bar-color` | Slider button color when the input is invalid | `--error-color`
-`--paper-toggle-button-invalid-button-color` | Button color when the input is invalid | `--error-color`
-`--paper-toggle-button-invalid-ink-color` | Selected/focus ripple color when the input is invalid | `--error-color`
-`--paper-toggle-button-unchecked-bar` | Mixin applied to the slider when the input is not checked | `{}`
-`--paper-toggle-button-unchecked-button` | Mixin applied to the slider button when the input is not checked | `{}`
-`--paper-toggle-button-unchecked-ink` | Mixin applied to the ripple when the input is not checked | `{}`
-`--paper-toggle-button-checked-bar` | Mixin applied to the slider when the input is checked | `{}`
-`--paper-toggle-button-checked-button` | Mixin applied to the slider button when the input is checked | `{}`
-`--paper-toggle-button-checked-ink` | Mixin applied to the ripple when the input is checked | `{}`
-`--paper-toggle-button-label-color` | Label color | `--primary-text-color`
-`--paper-toggle-button-label-spacing` | Spacing between the label and the button | `8px`
-
-This element applies the mixin `--paper-font-common-base` but does not import `paper-styles/typography.html`.
-In order to apply the `Roboto` font to this element, make sure you've imported `paper-styles/typography.html`.
-
-@group Paper Elements
-@element paper-toggle-button
-@hero hero.svg
-@demo demo/index.html
--->
-
-</head><body><dom-module id="paper-toggle-button">
-  <template strip-whitespace="">
-
-    <style>
-      :host {
-        display: inline-block;
-        @apply --layout-horizontal;
-        @apply --layout-center;
-        @apply --paper-font-common-base;
-      }
-
-      :host([disabled]) {
-        pointer-events: none;
-      }
-
-      :host(:focus) {
-        outline:none;
-      }
-
-      .toggle-bar {
-        position: absolute;
-        height: 100%;
-        width: 100%;
-        border-radius: 8px;
-        pointer-events: none;
-        opacity: 0.4;
-        transition: background-color linear .08s;
-        background-color: var(--paper-toggle-button-unchecked-bar-color, #000000);
-
-        @apply --paper-toggle-button-unchecked-bar;
-      }
-
-      .toggle-button {
-        position: absolute;
-        top: -3px;
-        left: 0;
-        height: 20px;
-        width: 20px;
-        border-radius: 50%;
-        box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.6);
-        transition: transform linear .08s, background-color linear .08s;
-        will-change: transform;
-        background-color: var(--paper-toggle-button-unchecked-button-color, var(--paper-grey-50));
-
-        @apply --paper-toggle-button-unchecked-button;
-      }
-
-      .toggle-button.dragging {
-        transition: none;
-      }
-
-      :host([checked]:not([disabled])) .toggle-bar {
-        opacity: 0.5;
-        background-color: var(--paper-toggle-button-checked-bar-color, var(--primary-color));
-
-        @apply --paper-toggle-button-checked-bar;
-      }
-
-      :host([disabled]) .toggle-bar {
-        background-color: #000;
-        opacity: 0.12;
-      }
-
-      :host([checked]) .toggle-button {
-        transform: translate(16px, 0);
-      }
-
-      :host([checked]:not([disabled])) .toggle-button {
-        background-color: var(--paper-toggle-button-checked-button-color, var(--primary-color));
-
-        @apply --paper-toggle-button-checked-button;
-      }
-
-      :host([disabled]) .toggle-button {
-        background-color: #bdbdbd;
-        opacity: 1;
-      }
-
-      .toggle-ink {
-        position: absolute;
-        top: -14px;
-        left: -14px;
-        right: auto;
-        bottom: auto;
-        width: 48px;
-        height: 48px;
-        opacity: 0.5;
-        pointer-events: none;
-        color: var(--paper-toggle-button-unchecked-ink-color, var(--primary-text-color));
-
-        @apply --paper-toggle-button-unchecked-ink;
-      }
-
-      :host([checked]) .toggle-ink {
-        color: var(--paper-toggle-button-checked-ink-color, var(--primary-color));
-
-        @apply --paper-toggle-button-checked-ink;
-      }
-
-      .toggle-container {
-        display: inline-block;
-        position: relative;
-        width: 36px;
-        height: 14px;
-        /* The toggle button has an absolute position of -3px; The extra 1px
-        /* accounts for the toggle button shadow box. */
-        margin: 4px 1px;
-      }
-
-      .toggle-label {
-        position: relative;
-        display: inline-block;
-        vertical-align: middle;
-        padding-left: var(--paper-toggle-button-label-spacing, 8px);
-        pointer-events: none;
-        color: var(--paper-toggle-button-label-color, var(--primary-text-color));
-      }
-
-      /* invalid state */
-      :host([invalid]) .toggle-bar {
-        background-color: var(--paper-toggle-button-invalid-bar-color, var(--error-color));
-      }
-
-      :host([invalid]) .toggle-button {
-        background-color: var(--paper-toggle-button-invalid-button-color, var(--error-color));
-      }
-
-      :host([invalid]) .toggle-ink {
-        color: var(--paper-toggle-button-invalid-ink-color, var(--error-color));
-      }
-    </style>
-
-    <div class="toggle-container">
-      <div id="toggleBar" class="toggle-bar"></div>
-      <div id="toggleButton" class="toggle-button"></div>
-    </div>
-
-    <div class="toggle-label"><slot></slot></div>
-
-  </template>
-
-  </dom-module>
-<script src="paper-toggle-button-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/tools/check_grd_for_unused_strings.py b/tools/check_grd_for_unused_strings.py
index 2defb2f..d997db6 100755
--- a/tools/check_grd_for_unused_strings.py
+++ b/tools/check_grd_for_unused_strings.py
@@ -137,6 +137,7 @@
     ui_chromeos_dir = os.path.join(ui_dir, 'chromeos')
     grd_files = [
       os.path.join(ash_base_dir, 'ash_strings.grd'),
+      os.path.join(ash_base_dir, 'resources', 'ash_resources.grd'),
       os.path.join(ash_components_dir, 'ash_components_strings.grd'),
       os.path.join(ash_components_dir, 'resources',
                    'ash_components_resources.grd'),
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index 71957a1..d95a129 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -207,16 +207,18 @@
 
     self._table_entries = []
     self._total_entry = {}
-    template_dir = os.path.join(
-        os.path.dirname(os.path.realpath(__file__)), 'html_templates')
+
+    source_dir = os.path.dirname(os.path.realpath(__file__))
+    template_dir = os.path.join(source_dir, 'html_templates')
 
     jinja_env = jinja2.Environment(
         loader=jinja2.FileSystemLoader(template_dir), trim_blocks=True)
     self._header_template = jinja_env.get_template('header.html')
     self._table_template = jinja_env.get_template('table.html')
     self._footer_template = jinja_env.get_template('footer.html')
+
     self._style_overrides = open(
-        os.path.join(template_dir, 'style_overrides.css')).read()
+        os.path.join(source_dir, 'static', 'css', 'style.css')).read()
 
   def AddLinkToAnotherReport(self, html_report_path, name, summary):
     """Adds a link to another html report in this report.
diff --git a/tools/code_coverage/html_templates/style_overrides.css b/tools/code_coverage/static/css/style.css
similarity index 100%
rename from tools/code_coverage/html_templates/style_overrides.css
rename to tools/code_coverage/static/css/style.css
diff --git a/tools/code_coverage/test_suite.txt b/tools/code_coverage/test_suite.txt
new file mode 100644
index 0000000..1aac6a0
--- /dev/null
+++ b/tools/code_coverage/test_suite.txt
@@ -0,0 +1,81 @@
+accessibility_unittests
+angle_unittests
+app_shell_unittests
+audio_unittests
+aura_unittests
+base_unittests
+battor_agent_unittests
+blink_common_unittests
+blink_heap_unittests
+blink_platform_unittests
+boringssl_crypto_tests
+boringssl_ssl_tests
+breakpad_unittests
+browser_tests
+cacheinvalidation_unittests
+capture_unittests
+cast_unittests
+cc_blink_unittests
+cc_unittests
+chrome_app_unittests
+components_browsertests
+components_unittests
+compositor_unittests
+content_browsertests
+content_unittests
+courgette_unittests
+crypto_unittests
+dbus_unittests
+device_unittests
+display_unittests
+events_unittests
+extensions_browsertests
+filesystem_service_unittests
+gcm_unit_tests
+gfx_unittests
+gin_unittests
+gl_unittests
+gn_unittests
+google_apis_unittests
+gpu_unittests
+headless_browsertests
+headless_unittests
+interactive_ui_tests
+ipc_tests
+jingle_unittests
+keyboard_unittests
+leveldb_service_unittests
+libjingle_xmpp_unittests
+media_blink_unittests
+media_mojo_unittests
+media_service_unittests
+media_unittests
+midi_unittests
+nacl_loader_unittests
+native_theme_unittests
+net_unittests
+pdf_unittests
+pdfium_unittests
+ppapi_unittests
+printing_unittests
+remoting_unittests
+sandbox_linux_unittests
+service_manager_unittests
+services_unittests
+skia_unittests
+snapshot_unittests
+sql_unittests
+storage_unittests
+swiftshader_unittests
+sync_integration_tests
+traffic_annotation_auditor_unittests
+ui_base_unittests
+ui_touch_selection_unittests
+unit_tests
+url_unittests
+views_unittests
+viz_unittests
+vr_common_unittests
+webkit_unit_tests
+wm_unittests
+wtf_unittests
\ No newline at end of file
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index fc16a42e..7e838ac9 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -293,6 +293,9 @@
   "ash/public/cpp/resources/ash_public_unscaled_resources.grd": {
     "includes": [24260],
   },
+  "ash/resources/ash_resources.grd": {
+    "structures": [24280],
+  },
   "ash/shell/ash_shell_resources.grd": {
     "includes": [24290],
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 37116dc..963817fd 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -12270,6 +12270,22 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="MobileStackViewIncognitoMode">
+  <owner>rlanday@chromium.org</owner>
+  <description>
+    User in the Android tab switcher switches from normal mode to incognito
+    mode.
+  </description>
+</action>
+
+<action name="MobileStackViewNormalMode">
+  <owner>rlanday@chromium.org</owner>
+  <description>
+    User in the Android tab switcher switches from incognito mode to normal
+    mode.
+  </description>
+</action>
+
 <action name="MobileStackViewSwipeCloseTab">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
@@ -12480,6 +12496,13 @@
   <description>User pressed the stop icon in the toolbar.</description>
 </action>
 
+<action name="MobileToolbarSwipeOpenStackView">
+  <owner>rlanday@chromium.org</owner>
+  <description>
+    User entered the Android tab switcher by swiping down on the toolbar.
+  </description>
+</action>
+
 <action name="MobileToolbarToggleBookmark">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5666630c..f36b47c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26464,6 +26464,7 @@
       label="OverlayScrollbarFlashAfterAnyScrollUpdate:enabled"/>
   <int value="-1907565048" label="HtmlBaseUsernameDetector:disabled"/>
   <int value="-1907342706" label="ReadItLaterInMenu:disabled"/>
+  <int value="-1895719323" label="VrBrowsingTabsView:enabled"/>
   <int value="-1892555086" label="disable-compositor-animation-timelines"/>
   <int value="-1892000374" label="SeccompSandboxAndroid:enabled"/>
   <int value="-1888273969" label="tab-capture-upscale-quality"/>
@@ -26824,6 +26825,7 @@
   <int value="-1158993534" label="PrintScaling:enabled"/>
   <int value="-1156179600" label="OmniboxRichEntitySuggestions:enabled"/>
   <int value="-1155543191" label="CopylessPaste:disabled"/>
+  <int value="-1154343236" label="VrBrowsingTabsView:disabled"/>
   <int value="-1151766565" label="enable-fullscreen-tab-detaching"/>
   <int value="-1145702446" label="ChromeHomeInactivitySheetExpansion:enabled"/>
   <int value="-1145246849" label="ThirdPartyDoodles:enabled"/>
@@ -29165,6 +29167,7 @@
   <int value="590" label="scroll-customization"/>
   <int value="591" label="row-gap"/>
   <int value="592" label="gap"/>
+  <int value="593" label="viewport-fit"/>
 </enum>
 
 <enum name="MappedEditingCommands">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b21cc1d..992647e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6134,6 +6134,26 @@
   </summary>
 </histogram>
 
+<histogram name="Autofill.InvalidProfileData.UsedForMetrics" enum="Boolean">
+  <owner>rogerm@chromium.org</owner>
+  <summary>
+    Tracks whether or not autofill suppressed sending votes or calculating
+    quality metrics because the profile data was marked as invalid. Logged
+    during field-type validation if/when a field marked as invalid is found to
+    match the submitted data.
+  </summary>
+</histogram>
+
+<histogram name="Autofill.InvalidProfileData.UsedForSuggestion" enum="Boolean">
+  <owner>rogerm@chromium.org</owner>
+  <summary>
+    Tracks whether or not autofill suppressed offering an autofill suggestion
+    because the profile data was marked as invalid. Logged during autofill
+    suggestion generation when a suggestion is about to generated based on a
+    field marked as invalid.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.IsEnabled.PageLoad" enum="BooleanEnabled">
   <owner>isherman@chromium.org</owner>
   <summary>
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn
index 2e50671..cb26ff8 100644
--- a/tools/perf/chrome_telemetry_build/BUILD.gn
+++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -22,6 +22,7 @@
       data_deps += [
         "//android_webview:system_webview_apk",
         "//android_webview/tools/system_webview_shell:system_webview_shell_apk",
+        "//chrome/android:monochrome_public_apk",
       ]
     }
   } else {
diff --git a/tools/perf/core/results_dashboard.py b/tools/perf/core/results_dashboard.py
index 078bed9..458604d 100755
--- a/tools/perf/core/results_dashboard.py
+++ b/tools/perf/core/results_dashboard.py
@@ -130,7 +130,6 @@
     line = line.strip()
     if not line:
       continue
-    print 'Sending result %d of %d to dashboard.' % (index + 1, total_results)
     # We need to check whether we're trying to upload histograms. If the JSON
     # is invalid, we should not try to send this data or re-try it later.
     # Instead, we'll print an error.
@@ -141,6 +140,8 @@
       continue
 
     data_type = ('histogram' if is_histogramset else 'chartjson')
+    print 'Sending %s result %d of %d to dashboard.' % (
+        data_type, index + 1, total_results)
 
     try:
       if is_histogramset:
@@ -490,7 +491,7 @@
       # If the remote app rejects the JSON, it's probably malformed,
       # so we don't want to retry it.
       raise SendResultsFatalException('Discarding JSON, error:\n%s' % error)
-    raise SendResultsRetryException()
+    raise SendResultsRetryException(error)
 
 def _Httplib2Request(url, data, oauth_token):
   data = zlib.compress(data)
diff --git a/tools/resources/find_unused_resources.py b/tools/resources/find_unused_resources.py
index eab5ba3..d6e52c8 100755
--- a/tools/resources/find_unused_resources.py
+++ b/tools/resources/find_unused_resources.py
@@ -12,7 +12,7 @@
 
 Example:
   cd /work/chrome/src
-  tools/resources/find_unused_resouces.py chrome/browser/browser_resources.grd
+  tools/resources/find_unused_resouces.py ash/resources/ash_resources.grd
 """
 
 __author__ = 'jamescook@chromium.org (James Cook)'
diff --git a/ui/base/mojo/clipboard_struct_traits.h b/ui/base/mojo/clipboard_struct_traits.h
index fb3f501..0024521 100644
--- a/ui/base/mojo/clipboard_struct_traits.h
+++ b/ui/base/mojo/clipboard_struct_traits.h
@@ -12,10 +12,11 @@
 
 template <>
 struct EnumTraits<blink::mojom::ClipboardBuffer, ui::ClipboardType> {
-  static blink::mojom::ClipboardBuffer ToMojom(ui::ClipboardType) {
-    // We never intend on converting from ui::Clipboardtype to
-    // blink::mojom::ClipboardBuffer.
-    NOTREACHED();
+  static blink::mojom::ClipboardBuffer ToMojom(
+      ui::ClipboardType clipboard_type) {
+    // We only convert ui::Clipboardtype to blink::mojom::ClipboardBuffer
+    // in tests, and they use ui::CLIPBOARD_TYPE_COPY_PASTE.
+    DCHECK(clipboard_type == ui::CLIPBOARD_TYPE_COPY_PASTE);
     return blink::mojom::ClipboardBuffer::kStandard;
   }
 
diff --git a/ui/compositor/test/in_process_context_provider.cc b/ui/compositor/test/in_process_context_provider.cc
index 0477487..7bd39cb2 100644
--- a/ui/compositor/test/in_process_context_provider.cc
+++ b/ui/compositor/test/in_process_context_provider.cc
@@ -116,7 +116,7 @@
       "gpu_toplevel", unique_context_name.c_str());
 
   raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>(
-      context_->GetImplementation(), context_->GetImplementation(),
+      context_->GetImplementation(),
       context_->GetImplementation()->command_buffer(),
       context_->GetImplementation()->capabilities());
 
diff --git a/ui/gl/gl_surface_osmesa.cc b/ui/gl/gl_surface_osmesa.cc
index 0a20986..3894f05 100644
--- a/ui/gl/gl_surface_osmesa.cc
+++ b/ui/gl/gl_surface_osmesa.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/numerics/safe_math.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "third_party/mesa/src/include/GL/osmesa.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
@@ -109,8 +110,10 @@
 
 gfx::SwapResult GLSurfaceOSMesaHeadless::SwapBuffers(
     const PresentationCallback& callback) {
-  callback.Run(gfx::PresentationFeedback(base::TimeTicks::Now(),
-                                         base::TimeDelta(), 0 /* flags */));
+  gfx::PresentationFeedback feedback(base::TimeTicks::Now(), base::TimeDelta(),
+                                     0 /* flags */);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, feedback));
   return gfx::SwapResult::SWAP_ACK;
 }
 
diff --git a/ui/gl/gl_surface_osmesa_win.cc b/ui/gl/gl_surface_osmesa_win.cc
index 6f54b4e..4730ae5 100644
--- a/ui/gl/gl_surface_osmesa_win.cc
+++ b/ui/gl/gl_surface_osmesa_win.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/win/windows_version.h"
 #include "ui/gl/gl_bindings.h"
@@ -113,10 +114,12 @@
 
   constexpr int64_t kRefreshIntervalInMicroseconds =
       base::Time::kMicrosecondsPerSecond / 60;
-  callback.Run(gfx::PresentationFeedback(
+  gfx::PresentationFeedback feedback(
       base::TimeTicks::Now(),
       base::TimeDelta::FromMicroseconds(kRefreshIntervalInMicroseconds),
-      0 /* flags */));
+      0 /* flags */);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, feedback));
   return gfx::SwapResult::SWAP_ACK;
 }
 
diff --git a/ui/gl/gl_surface_presentation_helper.cc b/ui/gl/gl_surface_presentation_helper.cc
index e9ecc50..1ff7bd1d 100644
--- a/ui/gl/gl_surface_presentation_helper.cc
+++ b/ui/gl/gl_surface_presentation_helper.cc
@@ -99,8 +99,7 @@
   DCHECK(!pending_frames_.empty());
   auto& frame = pending_frames_.back();
   frame.result = result;
-  if (!waiting_for_vsync_parameters_)
-    CheckPendingFrames();
+  ScheduleCheckPendingFrames(false /* align_with_next_vsync */);
 }
 
 void GLSurfacePresentationHelper::CheckPendingFrames() {
@@ -230,13 +229,41 @@
     }
   }
 
-  if (waiting_for_vsync_parameters_)
-    return;
-
   if (pending_frames_.empty() && !need_update_vsync)
     return;
+  ScheduleCheckPendingFrames(true /* align_with_next_vsync */);
+}
 
-  waiting_for_vsync_parameters_ = true;
+void GLSurfacePresentationHelper::CheckPendingFramesCallback() {
+  DCHECK(check_pending_frame_scheduled_);
+  check_pending_frame_scheduled_ = false;
+  CheckPendingFrames();
+}
+
+void GLSurfacePresentationHelper::UpdateVSyncCallback(
+    const base::TimeTicks timebase,
+    const base::TimeDelta interval) {
+  DCHECK(check_pending_frame_scheduled_);
+  check_pending_frame_scheduled_ = false;
+  vsync_timebase_ = timebase;
+  vsync_interval_ = interval;
+  CheckPendingFrames();
+}
+
+void GLSurfacePresentationHelper::ScheduleCheckPendingFrames(
+    bool align_with_next_vsync) {
+  if (check_pending_frame_scheduled_)
+    return;
+  check_pending_frame_scheduled_ = true;
+
+  if (!align_with_next_vsync) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&GLSurfacePresentationHelper::CheckPendingFramesCallback,
+                       weak_ptr_factory_.GetWeakPtr()));
+    return;
+  }
+
   if (vsync_provider_ &&
       !vsync_provider_->SupportGetVSyncParametersIfAvailable()) {
     // In this case, the |vsync_provider_| will call the callback when the next
@@ -262,20 +289,4 @@
       next_vsync - now);
 }
 
-void GLSurfacePresentationHelper::CheckPendingFramesCallback() {
-  DCHECK(waiting_for_vsync_parameters_);
-  waiting_for_vsync_parameters_ = false;
-  CheckPendingFrames();
-}
-
-void GLSurfacePresentationHelper::UpdateVSyncCallback(
-    const base::TimeTicks timebase,
-    const base::TimeDelta interval) {
-  DCHECK(waiting_for_vsync_parameters_);
-  waiting_for_vsync_parameters_ = false;
-  vsync_timebase_ = timebase;
-  vsync_interval_ = interval;
-  CheckPendingFrames();
-}
-
 }  // namespace gl
diff --git a/ui/gl/gl_surface_presentation_helper.h b/ui/gl/gl_surface_presentation_helper.h
index a1563c9..de7e0ccd 100644
--- a/ui/gl/gl_surface_presentation_helper.h
+++ b/ui/gl/gl_surface_presentation_helper.h
@@ -75,6 +75,8 @@
   void UpdateVSyncCallback(const base::TimeTicks timebase,
                            const base::TimeDelta interval);
 
+  void ScheduleCheckPendingFrames(bool align_with_next_vsync);
+
   gfx::VSyncProvider* const vsync_provider_;
   scoped_refptr<GLContext> gl_context_;
   GLSurface* surface_ = nullptr;
@@ -82,7 +84,7 @@
   base::circular_deque<Frame> pending_frames_;
   base::TimeTicks vsync_timebase_;
   base::TimeDelta vsync_interval_;
-  bool waiting_for_vsync_parameters_ = false;
+  bool check_pending_frame_scheduled_ = false;
 
   base::WeakPtrFactory<GLSurfacePresentationHelper> weak_ptr_factory_;
 
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 46f529a..3c30cbc0 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -816,14 +816,6 @@
              file="../../../third_party/polymer/v1_0/components-chromium/paper-tabs/paper-tabs.html"
              type="chrome_html"
              compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_TOGGLE_BUTTON_PAPER_TOGGLE_BUTTON_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button-extracted.js"
-             type="chrome_html"
-             compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_TOGGLE_BUTTON_PAPER_TOGGLE_BUTTON_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-toggle-button/paper-toggle-button.html"
-             type="chrome_html"
-             compress="gzip" />
   <structure name="IDR_POLYMER_1_0_PAPER_TOOLTIP_PAPER_TOOLTIP_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-tooltip/paper-tooltip-extracted.js"
              type="chrome_html"