diff --git a/DEPS b/DEPS
index 8cfa494..24f84df 100644
--- a/DEPS
+++ b/DEPS
@@ -83,7 +83,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': '6dd620dd5c9ee4e1744d5127821ca5a64d66ba44',
+  'v8_revision': 'f2df44f0b255dea0c96aa099807b891fabccfad4',
   # 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.
@@ -103,7 +103,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': '95bb9748c9292d282e2425d4500f15f5c48c2b34',
+  'pdfium_revision': '594b3eeeaa61a2c0a6d84df3e17ea587f3b15c23',
   # 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.
@@ -135,7 +135,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': 'aaaa5510da3e1a9ce62b7731caab65f0a83e3cf6',
+  'catapult_revision': 'd4706cb285d8caaa8e7c0334e0528efe7b9a26ff',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -248,7 +248,7 @@
   },
 
   'src/media/cdm/api':
-    Var('chromium_git') + '/chromium/cdm.git' + '@' + '2312db4e43f8b9a73373641dc5b73b0bf2117645',
+    Var('chromium_git') + '/chromium/cdm.git' + '@' + 'ca7130aa8fe6dd6c0664b52768d1957af31ae91b',
 
   'src/native_client': {
       'url': Var('chromium_git') + '/native_client/src/native_client.git' + '@' + Var('nacl_revision'),
@@ -328,7 +328,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'dbc809fcd3be3d9a39b77af038bbcdcc3db25e2f',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1edda746d22f903ee18f662d8463b707bd55febd',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1217,6 +1217,7 @@
     'action': ['src/build/cipd/cipd_wrapper.py',
                '--chromium-root', 'src',
                '--ensure-file', 'src/build/cipd/android/android.ensure',
+               '--ensure-file', 'src/chrome/android/android.ensure',
     ],
   },
   {
@@ -1334,7 +1335,7 @@
     'action': [
       'vpython',
       'src/build/fuchsia/update_sdk.py',
-      '16f4a04b24e5affe5e3e4a43016f667894a54e63',
+      '6b4cb32d100d2ecfaaa9642adfb0de451c5b9a69',
     ],
   },
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
index 21490116..eccfbe1c 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
@@ -2312,13 +2312,6 @@
         }
 
         @Override
-        public boolean awakenScrollBars() {
-            mWebViewPrivate.awakenScrollBars(0);
-            // TODO: modify the WebView.PrivateAccess to provide a return value.
-            return true;
-        }
-
-        @Override
         public boolean super_awakenScrollBars(int arg0, boolean arg1) {
             return false;
         }
diff --git a/android_webview/java/src/org/chromium/android_webview/FullScreenView.java b/android_webview/java/src/org/chromium/android_webview/FullScreenView.java
index 45afd9ce..287cbad 100644
--- a/android_webview/java/src/org/chromium/android_webview/FullScreenView.java
+++ b/android_webview/java/src/org/chromium/android_webview/FullScreenView.java
@@ -239,11 +239,6 @@
         }
 
         @Override
-        public boolean awakenScrollBars() {
-            return FullScreenView.this.awakenScrollBars(0);
-        }
-
-        @Override
         public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
             return FullScreenView.super.awakenScrollBars(startDelay, invalidate);
         }
diff --git a/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java b/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java
index 3baedcab..e24fc0d 100644
--- a/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java
+++ b/android_webview/java/src/org/chromium/android_webview/PopupTouchHandleDrawable.java
@@ -150,8 +150,9 @@
         mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
         mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
 
-        mAlpha = 1.f;
-        mVisible = getVisibility() == VISIBLE;
+        mAlpha = 0.f;
+        mVisible = false;
+        setVisibility(INVISIBLE);
         mFocused = mContentViewCore.getContainerView().hasWindowFocus();
 
         mParentPositionObserver = new ViewPositionObserver(mContentViewCore.getContainerView());
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
index 3b98546..5ef7bb9 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
@@ -550,11 +550,6 @@
         }
 
         @Override
-        public boolean awakenScrollBars() {
-            return AwTestContainerView.super.awakenScrollBars();
-        }
-
-        @Override
         public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
             return AwTestContainerView.super.awakenScrollBars(startDelay, invalidate);
         }
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index cbb37bd..1f50072 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -104,6 +104,8 @@
     "display/display_color_manager_chromeos.h",
     "display/display_configuration_controller.cc",
     "display/display_configuration_controller.h",
+    "display/display_configuration_observer.cc",
+    "display/display_configuration_observer.h",
     "display/display_error_observer_chromeos.cc",
     "display/display_error_observer_chromeos.h",
     "display/display_move_window_util.cc",
@@ -1354,6 +1356,7 @@
     "display/display_error_observer_chromeos_unittest.cc",
     "display/display_manager_unittest.cc",
     "display/display_move_window_util_unittest.cc",
+    "display/display_prefs_unittest.cc",
     "display/display_util_unittest.cc",
     "display/extended_mouse_warp_controller_unittest.cc",
     "display/mirror_window_controller_unittest.cc",
diff --git a/chrome/browser/chromeos/display/display_configuration_observer.cc b/ash/display/display_configuration_observer.cc
similarity index 91%
rename from chrome/browser/chromeos/display/display_configuration_observer.cc
rename to ash/display/display_configuration_observer.cc
index d3271912..bb2f8053 100644
--- a/chrome/browser/chromeos/display/display_configuration_observer.cc
+++ b/ash/display/display_configuration_observer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/display/display_configuration_observer.h"
+#include "ash/display/display_configuration_observer.h"
 
 #include "ash/display/display_prefs.h"
 #include "ash/display/window_tree_host_manager.h"
@@ -13,7 +13,7 @@
 #include "ui/display/manager/display_layout_store.h"
 #include "ui/display/manager/display_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 DisplayConfigurationObserver::DisplayConfigurationObserver() {
   ash::Shell::Get()->window_tree_host_manager()->AddObserver(this);
@@ -40,6 +40,8 @@
 }
 
 void DisplayConfigurationObserver::OnTabletModeStarted() {
+  if (disable_tablet_mirror_mode_for_test_)
+    return;
   // TODO(oshima): Tablet mode defaults to mirror mode until we figure out
   // how to handle this scenario, and we shouldn't save this state.
   // http://crbug.com/733092.
@@ -53,6 +55,8 @@
 }
 
 void DisplayConfigurationObserver::OnTabletModeEnded() {
+  if (disable_tablet_mirror_mode_for_test_)
+    return;
   if (!was_in_mirror_mode_)
     ash::Shell::Get()->display_manager()->SetMirrorMode(false);
   display::DisplayManager* display_manager =
@@ -61,4 +65,4 @@
   save_preference_ = true;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/chromeos/display/display_configuration_observer.h b/ash/display/display_configuration_observer.h
similarity index 62%
rename from chrome/browser/chromeos/display/display_configuration_observer.h
rename to ash/display/display_configuration_observer.h
index f1c0c2f2e..f1408114 100644
--- a/chrome/browser/chromeos/display/display_configuration_observer.h
+++ b/ash/display/display_configuration_observer.h
@@ -2,26 +2,35 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_CONFIGURATION_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_CONFIGURATION_OBSERVER_H_
+#ifndef ASH_DISPLAY_DISPLAY_CONFIGURATION_OBSERVER_H_
+#define ASH_DISPLAY_DISPLAY_CONFIGURATION_OBSERVER_H_
 
+#include "ash/ash_export.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/wm/tablet_mode/tablet_mode_observer.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 
-namespace chromeos {
+namespace ash {
+
+class AshTestHelper;
 
 // DisplayConfigurationObserver observes and saves
 // the change of display configurations.
-class DisplayConfigurationObserver
-    : public ash::WindowTreeHostManager::Observer,
-      public ash::TabletModeObserver {
+class ASH_EXPORT DisplayConfigurationObserver
+    : public WindowTreeHostManager::Observer,
+      public TabletModeObserver {
  public:
   DisplayConfigurationObserver();
   ~DisplayConfigurationObserver() override;
 
  protected:
+  friend class AshTestHelper;
+
+  void set_disable_tablet_mirror_mode_for_test(bool disable) {
+    disable_tablet_mirror_mode_for_test_ = disable;
+  }
+
   // ash::WindowTreeHostManager::Observer:
   void OnDisplaysInitialized() override;
   void OnDisplayConfigurationChanged() override;
@@ -36,9 +45,11 @@
   // tablet mode.
   bool was_in_mirror_mode_ = false;
 
+  bool disable_tablet_mirror_mode_for_test_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(DisplayConfigurationObserver);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-#endif  // CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_CONFIGURATION_OBSERVER_H_
+#endif  // ASH_DISPLAY_DISPLAY_CONFIGURATION_OBSERVER_H_
diff --git a/chrome/browser/chromeos/display/display_prefs_unittest.cc b/ash/display/display_prefs_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/display/display_prefs_unittest.cc
rename to ash/display/display_prefs_unittest.cc
index 24b1afcc..a51272c0 100644
--- a/chrome/browser/chromeos/display/display_prefs_unittest.cc
+++ b/ash/display/display_prefs_unittest.cc
@@ -25,7 +25,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/display/display_configuration_observer.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/user_manager/user_type.h"
@@ -104,13 +103,6 @@
     AshTestBase::SetUp();
     // AshTestBase::SetUp() initializes local state.
     ASSERT_TRUE(local_state());
-    observer_ = std::make_unique<chromeos::DisplayConfigurationObserver>();
-    observer_->OnDisplaysInitialized();
-  }
-
-  void TearDown() override {
-    observer_.reset();
-    AshTestBase::TearDown();
   }
 
   void LoggedInAsUser() { SimulateUserLogin("user1@test.com"); }
@@ -224,8 +216,6 @@
   DisplayPrefs* display_prefs() { return ash::Shell::Get()->display_prefs(); }
 
  private:
-  std::unique_ptr<WindowTreeHostManager::Observer> observer_;
-
   DISALLOW_COPY_AND_ASSIGN(DisplayPrefsTest);
 };
 
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc
index 70c909a..0f08255 100644
--- a/ash/frame/caption_buttons/frame_caption_button.cc
+++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -22,6 +22,9 @@
 // animation as a ratio of |kSwapImagesAnimationDurationMs|.
 const float kFadeOutRatio = 0.5f;
 
+// The ratio applied to the button's alpha when the button is disabled.
+const float kDisabledButtonAlphaRatio = 0.5f;
+
 // The colors and alpha values used for the button background hovered and
 // pressed states.
 // TODO(tdanderson|estade): Request these colors from ThemeProvider.
@@ -175,11 +178,15 @@
 }
 
 int FrameCaptionButton::GetAlphaForIcon(int base_alpha) const {
+  if (!enabled())
+    return base_alpha * kDisabledButtonAlphaRatio;
+
   if (paint_as_active_)
     return base_alpha;
 
   // Paint icons as active when they are hovered over or pressed.
   double inactive_alpha = kInactiveFrameButtonIconAlphaRatio;
+
   if (hover_animation().is_animating()) {
     inactive_alpha =
         hover_animation().CurrentValueBetween(inactive_alpha, 1.0f);
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
index 24b4a4c..4e19769 100644
--- a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
@@ -117,7 +117,6 @@
   void TearDown() override {
     AshTestBase::TearDown();
     power_manager_observer_.reset();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   bool LaunchTimeoutRunning() {
diff --git a/ash/shell.cc b/ash/shell.cc
index 6571273..63509251 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -24,6 +24,7 @@
 #include "ash/display/cursor_window_controller.h"
 #include "ash/display/display_color_manager_chromeos.h"
 #include "ash/display/display_configuration_controller.h"
+#include "ash/display/display_configuration_observer.h"
 #include "ash/display/display_error_observer_chromeos.h"
 #include "ash/display/display_prefs.h"
 #include "ash/display/display_shutdown_observer.h"
@@ -449,8 +450,8 @@
 }
 
 bool Shell::ShouldSaveDisplaySettings() {
-  // This function is only called from Chrome, hence the DCHECK for not-MASH.
-  DCHECK(GetAshConfig() != Config::MASH);
+  if (GetAshConfig() == Config::MASH)
+    return false;  // Only occurs in tests.
   return !(
       screen_orientation_controller_->ignore_display_configuration_updates() ||
       resolution_notification_controller_->DoesNotificationTimeout());
@@ -660,7 +661,7 @@
 
   user_metrics_recorder_->OnShellShuttingDown();
 
-  shell_delegate_->PreShutdown();
+  display_configuration_observer_.reset();
   display_prefs_.reset();
 
   // Remove the focus from any window. This will prevent overhead and side
@@ -914,9 +915,13 @@
   // is available and store requests will be queued in the meanwhile.
   display_prefs_ = std::make_unique<DisplayPrefs>();
 
-  // TODO(stevenjb): Move DisplayConfigurationObserver to Ash also.
   shell_delegate_->PreInit();
 
+  // Set the observer now so that we can save the initial state in
+  // InitializeDisplayManager().
+  display_configuration_observer_ =
+      std::make_unique<DisplayConfigurationObserver>();
+
   InitializeDisplayManager();
 
   if (config == Config::CLASSIC) {
diff --git a/ash/shell.h b/ash/shell.h
index c9df906..9888332 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -93,6 +93,7 @@
 class CastConfigController;
 class DisplayColorManager;
 class DisplayConfigurationController;
+class DisplayConfigurationObserver;
 class DisplayErrorObserver;
 class DisplayPrefs;
 class DisplayShutdownObserver;
@@ -722,6 +723,7 @@
   std::unique_ptr<DisplayPrefs> display_prefs_;
   std::unique_ptr<DisplayConfigurationController>
       display_configuration_controller_;
+  std::unique_ptr<DisplayConfigurationObserver> display_configuration_observer_;
 
   std::unique_ptr<ScreenPinningController> screen_pinning_controller_;
 
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 65e5edd..1a454058 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -48,8 +48,6 @@
 
 void ShellDelegateImpl::PreInit() {}
 
-void ShellDelegateImpl::PreShutdown() {}
-
 std::unique_ptr<keyboard::KeyboardUI> ShellDelegateImpl::CreateKeyboardUI() {
   return std::make_unique<TestKeyboardUI>();
 }
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index 14b8ea3..37a0d42 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -29,7 +29,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   bool IsForceMaximizeOnFirstRun() const override;
   void PreInit() override;
-  void PreShutdown() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index a77cace..92d77ea 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -62,10 +62,6 @@
   // can perform tasks necessary before the shell is initialized.
   virtual void PreInit() = 0;
 
-  // Called at the beginninig of Shell destructor so that
-  // delegate can use Shell instance to perform cleanup tasks.
-  virtual void PreShutdown() = 0;
-
   // Create a shell-specific keyboard::KeyboardUI.
   virtual std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() = 0;
 
diff --git a/ash/shell_delegate_mus.cc b/ash/shell_delegate_mus.cc
index ba8959a3..2ef3046c 100644
--- a/ash/shell_delegate_mus.cc
+++ b/ash/shell_delegate_mus.cc
@@ -71,10 +71,6 @@
   NOTIMPLEMENTED_LOG_ONCE();
 }
 
-void ShellDelegateMus::PreShutdown() {
-  NOTIMPLEMENTED_LOG_ONCE();
-}
-
 std::unique_ptr<keyboard::KeyboardUI> ShellDelegateMus::CreateKeyboardUI() {
   NOTIMPLEMENTED_LOG_ONCE();
   return nullptr;
diff --git a/ash/shell_delegate_mus.h b/ash/shell_delegate_mus.h
index 6869a8e..95da8f47 100644
--- a/ash/shell_delegate_mus.h
+++ b/ash/shell_delegate_mus.h
@@ -27,7 +27,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   bool IsForceMaximizeOnFirstRun() const override;
   void PreInit() override;
-  void PreShutdown() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
diff --git a/ash/system/network/tray_network_unittest.cc b/ash/system/network/tray_network_unittest.cc
index 3fbca09..ef8ea70d 100644
--- a/ash/system/network/tray_network_unittest.cc
+++ b/ash/system/network/tray_network_unittest.cc
@@ -50,7 +50,6 @@
     }
     AshTestBase::TearDown();
     chromeos::NetworkHandler::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
  private:
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc
index 342f856..3e6eacf 100644
--- a/ash/system/overview/overview_button_tray_unittest.cc
+++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -45,6 +45,8 @@
 }
 
 OverviewButtonTray* GetSecondaryTray() {
+  if (!StatusAreaWidgetTestHelper::GetSecondaryStatusAreaWidget())
+    return nullptr;
   return StatusAreaWidgetTestHelper::GetSecondaryStatusAreaWidget()
       ->overview_button_tray();
 }
@@ -87,6 +89,11 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       ::switches::kUseFirstDisplayAsInternal);
   AshTestBase::SetUp();
+  // TODO(jonross@/oshima@): Tablet mode tests are incorrect when
+  // DisplayConfigurationObserver exists (see
+  // DisplayConfigurationObserver::OnTabletModeStarted(). Disable auto
+  // mirrorring in tablet mode for now. http://crbug.com/798857
+  ash_test_helper()->DisableTabletMirrorModeForTest();
 }
 
 void OverviewButtonTrayTest::NotifySessionStateChanged() {
@@ -197,9 +204,11 @@
 TEST_F(OverviewButtonTrayTest, DisplaysOnBothDisplays) {
   UpdateDisplay("400x400,200x200");
   EXPECT_FALSE(GetTray()->visible());
+  ASSERT_TRUE(GetSecondaryTray());
   EXPECT_FALSE(GetSecondaryTray()->visible());
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   EXPECT_TRUE(GetTray()->visible());
+  ASSERT_TRUE(GetSecondaryTray());
   EXPECT_TRUE(GetSecondaryTray()->visible());
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
 }
@@ -209,6 +218,7 @@
 TEST_F(OverviewButtonTrayTest, SecondaryTrayCreatedVisible) {
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   UpdateDisplay("400x400,200x200");
+  ASSERT_TRUE(GetSecondaryTray());
   EXPECT_TRUE(GetSecondaryTray()->visible());
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
 }
diff --git a/ash/system/power/backlights_forced_off_setter_unittest.cc b/ash/system/power/backlights_forced_off_setter_unittest.cc
index f49d8806..69dc1c5 100644
--- a/ash/system/power/backlights_forced_off_setter_unittest.cc
+++ b/ash/system/power/backlights_forced_off_setter_unittest.cc
@@ -79,7 +79,6 @@
     backlights_forced_off_observer_.reset();
     backlights_forced_off_setter_.reset();
     AshTestBase::TearDown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   void ResetBacklightsForcedOffSetter() {
diff --git a/ash/system/power/power_button_test_base.cc b/ash/system/power/power_button_test_base.cc
index 88ea6ad0..7a786866 100644
--- a/ash/system/power/power_button_test_base.cc
+++ b/ash/system/power/power_button_test_base.cc
@@ -5,7 +5,6 @@
 #include "ash/system/power/power_button_test_base.h"
 
 #include "ash/public/cpp/ash_switches.h"
-#include "ash/public/cpp/config.h"
 #include "ash/session/session_controller.h"
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
@@ -56,14 +55,6 @@
       std::make_unique<LockStateControllerTestApi>(lock_state_controller_);
 }
 
-void PowerButtonTestBase::TearDown() {
-  const Config config = Shell::GetAshConfig();
-  AshTestBase::TearDown();
-  // Mash/mus shuts down dbus after each test.
-  if (config == Config::CLASSIC)
-    chromeos::DBusThreadManager::Shutdown();
-}
-
 void PowerButtonTestBase::ResetPowerButtonController() {
   ShellTestApi().ResetPowerButtonControllerForTest();
   InitPowerButtonControllerMembers(false /* send_accelerometer_update */);
diff --git a/ash/system/power/power_button_test_base.h b/ash/system/power/power_button_test_base.h
index 37cc60c..0930f61 100644
--- a/ash/system/power/power_button_test_base.h
+++ b/ash/system/power/power_button_test_base.h
@@ -55,7 +55,6 @@
 
   // AshTestBase:
   void SetUp() override;
-  void TearDown() override;
 
  protected:
   // Resets the PowerButtonController and associated members.
diff --git a/ash/system/rotation/tray_rotation_lock_unittest.cc b/ash/system/rotation/tray_rotation_lock_unittest.cc
index d414777..512f017 100644
--- a/ash/system/rotation/tray_rotation_lock_unittest.cc
+++ b/ash/system/rotation/tray_rotation_lock_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/command_line.h"
 #include "base/time/time.h"
@@ -99,6 +100,7 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       ::switches::kUseFirstDisplayAsInternal);
   AshTestBase::SetUp();
+  ash_test_helper()->DisableTabletMirrorModeForTest();
   SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget());
 }
 
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 0c14304..6a6f19c 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "ash/display/display_configuration_controller_test_api.h"
+#include "ash/display/display_configuration_observer.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/config.h"
 #include "ash/shell.h"
@@ -278,6 +279,12 @@
   return Shell::Get()->display_manager()->GetSecondaryDisplay();
 }
 
+void AshTestHelper::DisableTabletMirrorModeForTest() {
+  ash::Shell::Get()
+      ->display_configuration_observer_
+      ->set_disable_tablet_mirror_mode_for_test(true);
+}
+
 void AshTestHelper::CreateMashWindowManager() {
   CHECK(config_ != Config::CLASSIC);
   const bool show_primary_root_on_connect = false;
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index e745c2d..5cc8e9e 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -100,6 +100,10 @@
 
   display::Display GetSecondaryDisplay();
 
+  // Disables the auto mirror feature in tablet mode in
+  // Shell::display_configuration_observer_ for testing. Call after SetUp().
+  void DisableTabletMirrorModeForTest();
+
   // Null in classic ash.
   WindowManagerService* window_manager_service() {
     return window_manager_service_.get();
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index d8a3f86..c418db0 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -36,8 +36,6 @@
 
 void TestShellDelegate::PreInit() {}
 
-void TestShellDelegate::PreShutdown() {}
-
 std::unique_ptr<keyboard::KeyboardUI> TestShellDelegate::CreateKeyboardUI() {
   return std::make_unique<TestKeyboardUI>();
 }
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index 04e980f4..d78f76b1 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -23,7 +23,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   bool IsForceMaximizeOnFirstRun() const override;
   void PreInit() override;
-  void PreShutdown() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 72c18b0..65eeef3 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -21,6 +21,7 @@
 #include "ash/shell_test_api.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
 #include "ash/wm/overview/overview_window_drag_controller.h"
 #include "ash/wm/overview/window_grid.h"
 #include "ash/wm/overview/window_selector.h"
@@ -1938,6 +1939,7 @@
 
   void SetUp() override {
     WindowSelectorTest::SetUp();
+    ash_test_helper()->DisableTabletMirrorModeForTest();
     Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index 40935ce9..e5103f54 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "base/command_line.h"
 #include "base/run_loop.h"
@@ -75,6 +76,8 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kAshEnableTabletMode);
     AshTestBase::SetUp();
+    ash_test_helper()->DisableTabletMirrorModeForTest();
+
     chromeos::AccelerometerReader::GetInstance()->RemoveObserver(
         tablet_mode_controller());
 
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 998bab6..8f65bf2 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -1894,17 +1894,29 @@
 
     generic_allocator.root()->Free(ptr2);
   }
+  // kSystemPageSize is 16384 byte on Loongson platform.
+  // Test purge discardable memory requirements need to
+  // be modified as follows:
   {
+#if defined(_MIPS_ARCH_LOONGSON)
+    size_t requestedSize = 36864;
+#else
+    size_t requestedSize = 9216;
+#endif
     char* ptr1 = reinterpret_cast<char*>(
-        generic_allocator.root()->Alloc(9216 - kExtraAllocSize, type_name));
+        generic_allocator.root()->Alloc(requestedSize - kExtraAllocSize,
+                                        type_name));
     void* ptr2 =
-        generic_allocator.root()->Alloc(9216 - kExtraAllocSize, type_name);
+        generic_allocator.root()->Alloc(requestedSize - kExtraAllocSize,
+                                        type_name);
     void* ptr3 =
-        generic_allocator.root()->Alloc(9216 - kExtraAllocSize, type_name);
+        generic_allocator.root()->Alloc(requestedSize - kExtraAllocSize,
+                                        type_name);
     void* ptr4 =
-        generic_allocator.root()->Alloc(9216 - kExtraAllocSize, type_name);
-    memset(ptr1, 'A', 9216 - kExtraAllocSize);
-    memset(ptr2, 'A', 9216 - kExtraAllocSize);
+        generic_allocator.root()->Alloc(requestedSize - kExtraAllocSize,
+                                        type_name);
+    memset(ptr1, 'A', requestedSize - kExtraAllocSize);
+    memset(ptr2, 'A', requestedSize - kExtraAllocSize);
     generic_allocator.root()->Free(ptr2);
     generic_allocator.root()->Free(ptr1);
     {
@@ -1913,12 +1925,13 @@
                                           false /* detailed dump */, &dumper);
       EXPECT_TRUE(dumper.IsMemoryAllocationRecorded());
 
-      const PartitionBucketMemoryStats* stats = dumper.GetBucketStats(9216);
+      const PartitionBucketMemoryStats* stats =
+          dumper.GetBucketStats(requestedSize);
       EXPECT_TRUE(stats);
       EXPECT_TRUE(stats->is_valid);
       EXPECT_EQ(0u, stats->decommittable_bytes);
       EXPECT_EQ(2 * kSystemPageSize, stats->discardable_bytes);
-      EXPECT_EQ(9216u * 2, stats->active_bytes);
+      EXPECT_EQ(requestedSize * 2, stats->active_bytes);
       EXPECT_EQ(9 * kSystemPageSize, stats->resident_bytes);
     }
     CHECK_PAGE_IN_CORE(ptr1 - kPointerOffset, true);
@@ -1937,6 +1950,47 @@
     generic_allocator.root()->Free(ptr3);
     generic_allocator.root()->Free(ptr4);
   }
+  // kSystemPageSize is 16384 byte on Loongson platform.
+  // 64*kSystemPageSize is 2G and exceeded maximum application
+  // value that partitionalloc, so must be reduce the application
+  // value.
+  // On Loongson, 64*kSystemPageSize was changed to 32*kSystemPageSize.
+#if defined(_MIPS_ARCH_LOONGSON)
+  {
+    char* ptr1 = reinterpret_cast<char*>(PartitionAllocGeneric(
+        generic_allocator.root(), (32 * kSystemPageSize) - kExtraAllocSize,
+        type_name));
+    memset(ptr1, 'A', (32 * kSystemPageSize) - kExtraAllocSize);
+    PartitionFreeGeneric(generic_allocator.root(), ptr1);
+    ptr1 = reinterpret_cast<char*>(PartitionAllocGeneric(
+        generic_allocator.root(), (31 * kSystemPageSize) - kExtraAllocSize,
+        type_name));
+    {
+      MockPartitionStatsDumper dumper;
+      PartitionDumpStatsGeneric(generic_allocator.root(),
+                                "mock_generic_allocator",
+                                false /* detailed dump */, &dumper);
+      EXPECT_TRUE(dumper.IsMemoryAllocationRecorded());
+
+      const PartitionBucketMemoryStats* stats =
+          dumper.GetBucketStats(32 * kSystemPageSize);
+      EXPECT_TRUE(stats);
+      EXPECT_TRUE(stats->is_valid);
+      EXPECT_EQ(0u, stats->decommittable_bytes);
+      EXPECT_EQ(kSystemPageSize, stats->discardable_bytes);
+      EXPECT_EQ(31 * kSystemPageSize, stats->active_bytes);
+      EXPECT_EQ(32 * kSystemPageSize, stats->resident_bytes);
+    }
+    CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 30), true);
+    CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 31), true);
+    PartitionPurgeMemoryGeneric(generic_allocator.root(),
+                                PartitionPurgeDiscardUnusedSystemPages);
+    CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 30), true);
+    CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 31), false);
+
+    PartitionFreeGeneric(generic_allocator.root(), ptr1);
+  }
+#else
   {
     char* ptr1 = reinterpret_cast<char*>(generic_allocator.root()->Alloc(
         (64 * kSystemPageSize) - kExtraAllocSize, type_name));
@@ -1972,6 +2026,7 @@
 
     generic_allocator.root()->Free(ptr1);
   }
+#endif
   // This sub-test tests truncation of the provisioned slots in a trickier
   // case where the freelist is rewritten.
   generic_allocator.root()->PurgeMemory(PartitionPurgeDecommitEmptyPages);
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 941cbd8..f84b326 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -85,11 +85,6 @@
   return PostPendingTask(&pending_task);
 }
 
-bool IncomingTaskQueue::IsIdleForTesting() {
-  AutoLock lock(incoming_queue_lock_);
-  return incoming_queue_.empty();
-}
-
 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
   {
     AutoLock auto_lock(incoming_queue_lock_);
@@ -181,6 +176,7 @@
 }
 
 void IncomingTaskQueue::TriageQueue::ReloadFromIncomingQueueIfEmpty() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(outer_->sequence_checker_);
   if (queue_.empty()) {
     // TODO(robliao): Since these high resolution tasks aren't yet in the
     // delayed queue, they technically shouldn't trigger high resolution timers
@@ -351,6 +347,8 @@
 }
 
 int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // Make sure no tasks are lost.
   DCHECK(work_queue->empty());
 
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 861f0fc..0a476365 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -77,9 +77,6 @@
                           TimeDelta delay,
                           Nestable nestable);
 
-  // Returns true if the message loop is "idle". Provided for testing.
-  bool IsIdleForTesting();
-
   // Disconnects |this| from the parent message loop.
   void WillDestroyCurrentMessageLoop();
 
@@ -109,8 +106,9 @@
   // maintaining three queue queues to process tasks:
   //
   // TriageQueue
-  // The first queue to receive all tasks for the processing sequence. Tasks are
-  // generally either dispatched immediately or sent to the queues below.
+  // The first queue to receive all tasks for the processing sequence (when
+  // reloading from the thread-safe |incoming_queue_|). Tasks are generally
+  // either dispatched immediately or sent to the queues below.
   //
   // DelayedQueue
   // The queue for holding tasks that should be run later and sorted by expected
@@ -242,7 +240,7 @@
 
   // An incoming queue of tasks that are acquired under a mutex for processing
   // on this instance's thread. These tasks have not yet been been pushed to
-  // |message_loop_|.
+  // |triage_tasks_|.
   TaskQueue incoming_queue_;
 
   // True if new tasks should be accepted.
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 41c58bf..a51db8b 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -258,9 +258,17 @@
 }
 
 bool MessageLoop::IsIdleForTesting() {
-  // We only check the incoming queue, since we don't want to lock the work
-  // queue.
-  return incoming_task_queue_->IsIdleForTesting();
+  // Have unprocessed tasks? (this reloads the work queue if necessary)
+  if (incoming_task_queue_->triage_tasks().HasTasks())
+    return false;
+
+  // Have unprocessed deferred tasks which can be processed at this run-level?
+  if (incoming_task_queue_->deferred_tasks().HasTasks() &&
+      !RunLoop::IsNestedOnCurrentThread()) {
+    return false;
+  }
+
+  return true;
 }
 
 //------------------------------------------------------------------------------
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 46c7ab9..27ee7fe 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -266,7 +266,11 @@
   void AddTaskObserver(TaskObserver* task_observer);
   void RemoveTaskObserver(TaskObserver* task_observer);
 
-  // Returns true if the message loop is "idle". Provided for testing.
+  // Returns true if the message loop is idle (ignoring delayed tasks). This is
+  // the same condition which triggers DoWork() to return false: i.e.
+  // out of tasks which can be processed at the current run-level -- there might
+  // be deferred non-nestable tasks remaining if currently in a nested run
+  // level.
   bool IsIdleForTesting();
 
   // Runs the specified PendingTask.
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 1eb41e4e..5468528 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -448,8 +448,8 @@
   if (take_mdp_ownership_and_delete_async) {
     // The MDP will be deleted whenever the MDPInfo struct will, that is either:
     // - At the end of this function, if no dump is in progress.
-    // - Either in SetupNextMemoryDump() or InvokeOnMemoryDump() when MDPInfo is
-    //   removed from |pending_dump_providers|.
+    // - In ContinueAsyncProcessDump() when MDPInfo is removed from
+    //   |pending_dump_providers|.
     // - When the provider is removed from other clients (MemoryPeakDetector).
     DCHECK(!(*mdp_iter)->owned_dump_provider);
     (*mdp_iter)->owned_dump_provider = std::move(owned_mdp);
@@ -564,192 +564,164 @@
 
   // Start the process dump. This involves task runner hops as specified by the
   // MemoryDumpProvider(s) in RegisterDumpProvider()).
-  SetupNextMemoryDump(std::move(pmd_async_state));
+  ContinueAsyncProcessDump(pmd_async_state.release());
 }
 
-// PostTask InvokeOnMemoryDump() to the dump provider's sequenced task runner. A
-// PostTask is always required for a generic SequencedTaskRunner to ensure that
-// no other task is running on it concurrently. SetupNextMemoryDump() and
-// InvokeOnMemoryDump() are called alternatively which linearizes the dump
-// provider's OnMemoryDump invocations.
-// At most one of either SetupNextMemoryDump() or InvokeOnMemoryDump() can be
-// active at any time for a given PMD, regardless of status of the |lock_|.
-// |lock_| is used in these functions purely to ensure consistency w.r.t.
-// (un)registrations of |dump_providers_|.
-void MemoryDumpManager::SetupNextMemoryDump(
-    std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+// Invokes OnMemoryDump() on all MDPs that are next in the pending list and run
+// on the current sequenced task runner. If the next MDP does not run in current
+// sequenced task runner, then switches to that task runner and continues. All
+// OnMemoryDump() invocations are linearized. |lock_| is used in these functions
+// purely to ensure consistency w.r.t. (un)registrations of |dump_providers_|.
+void MemoryDumpManager::ContinueAsyncProcessDump(
+    ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
   HEAP_PROFILER_SCOPED_IGNORE;
   // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
   // in the PostTask below don't end up registering their own dump providers
   // (for discounting trace memory overhead) while holding the |lock_|.
   TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
 
-  if (pmd_async_state->pending_dump_providers.empty())
-    return FinishAsyncProcessDump(std::move(pmd_async_state));
+  // In theory |owned_pmd_async_state| should be a unique_ptr. The only reason
+  // why it isn't is because of the corner case logic of |did_post_task|
+  // above, which needs to take back the ownership of the |pmd_async_state| when
+  // the PostTask() fails.
+  // Unfortunately, PostTask() destroys the unique_ptr arguments upon failure
+  // to prevent accidental leaks. Using a unique_ptr would prevent us to to
+  // skip the hop and move on. Hence the manual naked -> unique ptr juggling.
+  auto pmd_async_state = WrapUnique(owned_pmd_async_state);
+  owned_pmd_async_state = nullptr;
 
-  // Read MemoryDumpProviderInfo thread safety considerations in
-  // memory_dump_manager.h when accessing |mdpinfo| fields.
-  MemoryDumpProviderInfo* mdpinfo =
-      pmd_async_state->pending_dump_providers.back().get();
+  while (!pmd_async_state->pending_dump_providers.empty()) {
+    // Read MemoryDumpProviderInfo thread safety considerations in
+    // memory_dump_manager.h when accessing |mdpinfo| fields.
+    MemoryDumpProviderInfo* mdpinfo =
+        pmd_async_state->pending_dump_providers.back().get();
 
+    if (!IsDumpProviderAllowedToDump(pmd_async_state->req_args, *mdpinfo)) {
+      pmd_async_state->pending_dump_providers.pop_back();
+      continue;
+    }
+
+    // If the dump provider did not specify a task runner affinity, dump on
+    // |dump_thread_|.
+    scoped_refptr<SequencedTaskRunner> task_runner = mdpinfo->task_runner;
+    if (!task_runner) {
+      DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner);
+      task_runner = pmd_async_state->dump_thread_task_runner;
+      DCHECK(task_runner);
+    }
+
+    // If |RunsTasksInCurrentSequence()| is true then no PostTask is
+    // required since we are on the right SequencedTaskRunner.
+    if (task_runner->RunsTasksInCurrentSequence()) {
+      InvokeOnMemoryDump(mdpinfo, pmd_async_state->process_memory_dump.get());
+      pmd_async_state->pending_dump_providers.pop_back();
+      continue;
+    }
+
+    bool did_post_task = task_runner->PostTask(
+        FROM_HERE,
+        BindOnce(&MemoryDumpManager::ContinueAsyncProcessDump, Unretained(this),
+                 Unretained(pmd_async_state.get())));
+
+    if (did_post_task) {
+      // Ownership is tranferred to the posted task.
+      ignore_result(pmd_async_state.release());
+      return;
+    }
+
+    // PostTask usually fails only if the process or thread is shut down. So,
+    // the dump provider is disabled here. But, don't disable unbound dump
+    // providers, since the |dump_thread_| is controlled by MDM.
+    if (mdpinfo->task_runner) {
+      // A locked access is required to R/W |disabled| (for the
+      // UnregisterAndDeleteDumpProviderSoon() case).
+      AutoLock lock(lock_);
+      mdpinfo->disabled = true;
+    }
+
+    // PostTask failed. Ignore the dump provider and continue.
+    pmd_async_state->pending_dump_providers.pop_back();
+  }
+
+  FinishAsyncProcessDump(std::move(pmd_async_state));
+}
+
+bool MemoryDumpManager::IsDumpProviderAllowedToDump(
+    const MemoryDumpRequestArgs& req_args,
+    const MemoryDumpProviderInfo& mdpinfo) const {
   // If we are in background tracing, we should invoke only the whitelisted
   // providers. Ignore other providers and continue.
-  if (pmd_async_state->req_args.level_of_detail ==
-      MemoryDumpLevelOfDetail::BACKGROUND) {
-    // TODO(ssid): This is a temporary hack to fix crashes
-    // https://crbug.com/797784. We could still cause stack overflow in a
-    // detailed mode dump or when there are lot of providers whitelisted.
-    while (!mdpinfo->whitelisted_for_background_mode) {
-      pmd_async_state->pending_dump_providers.pop_back();
-      if (pmd_async_state->pending_dump_providers.empty())
-        return FinishAsyncProcessDump(std::move(pmd_async_state));
-      mdpinfo = pmd_async_state->pending_dump_providers.back().get();
-    }
+  if (req_args.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND &&
+      !mdpinfo.whitelisted_for_background_mode) {
+    return false;
   }
 
   // If we are in summary mode, we only need to invoke the providers
   // whitelisted for summary mode.
-  if (pmd_async_state->req_args.dump_type == MemoryDumpType::SUMMARY_ONLY) {
-    // TODO(ssid): This is a temporary hack to fix crashes
-    // https://crbug.com/797784. We could still cause stack overflow in a
-    // detailed mode dump or when there are lot of providers whitelisted. It is
-    // assumed here that a provider whitelisted for summary mode is also
-    // whitelisted for background mode and skip the check.
-    while (!mdpinfo->whitelisted_for_summary_mode) {
-      pmd_async_state->pending_dump_providers.pop_back();
-      if (pmd_async_state->pending_dump_providers.empty())
-        return FinishAsyncProcessDump(std::move(pmd_async_state));
-      mdpinfo = pmd_async_state->pending_dump_providers.back().get();
-    }
+  if (req_args.dump_type == MemoryDumpType::SUMMARY_ONLY &&
+      !mdpinfo.whitelisted_for_summary_mode) {
+    return false;
   }
 
-  // If the dump provider did not specify a task runner affinity, dump on
-  // |dump_thread_|.
-  scoped_refptr<SequencedTaskRunner> task_runner = mdpinfo->task_runner;
-  if (!task_runner) {
-    DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner);
-    task_runner = pmd_async_state->dump_thread_task_runner;
-    DCHECK(task_runner);
-  }
-
-  if (mdpinfo->options.dumps_on_single_thread_task_runner &&
-      task_runner->RunsTasksInCurrentSequence()) {
-    // If |dumps_on_single_thread_task_runner| is true then no PostTask is
-    // required if we are on the right thread.
-    return InvokeOnMemoryDump(pmd_async_state.release());
-  }
-
-  bool did_post_task = task_runner->PostTask(
-      FROM_HERE, BindOnce(&MemoryDumpManager::InvokeOnMemoryDump,
-                          Unretained(this), Unretained(pmd_async_state.get())));
-
-  if (did_post_task) {
-    // Ownership is tranferred to InvokeOnMemoryDump().
-    ignore_result(pmd_async_state.release());
-    return;
-  }
-
-  // PostTask usually fails only if the process or thread is shut down. So, the
-  // dump provider is disabled here. But, don't disable unbound dump providers.
-  // The utility thread is normally shutdown when disabling the trace and
-  // getting here in this case is expected.
-  if (mdpinfo->task_runner) {
-    DLOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
-                << "\". Failed to post task on the task runner provided.";
-
-    // A locked access is required to R/W |disabled| (for the
-    // UnregisterAndDeleteDumpProviderSoon() case).
-    AutoLock lock(lock_);
-    mdpinfo->disabled = true;
-  }
-
-  // PostTask failed. Ignore the dump provider and continue.
-  pmd_async_state->pending_dump_providers.pop_back();
-  SetupNextMemoryDump(std::move(pmd_async_state));
+  return true;
 }
 
 // This function is called on the right task runner for current MDP. It is
 // either the task runner specified by MDP or |dump_thread_task_runner| if the
 // MDP did not specify task runner. Invokes the dump provider's OnMemoryDump()
 // (unless disabled).
-void MemoryDumpManager::InvokeOnMemoryDump(
-    ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
+void MemoryDumpManager::InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo,
+                                           ProcessMemoryDump* pmd) {
   HEAP_PROFILER_SCOPED_IGNORE;
-  // In theory |owned_pmd_async_state| should be a scoped_ptr. The only reason
-  // why it isn't is because of the corner case logic of |did_post_task|
-  // above, which needs to take back the ownership of the |pmd_async_state| when
-  // the PostTask() fails.
-  // Unfortunately, PostTask() destroys the scoped_ptr arguments upon failure
-  // to prevent accidental leaks. Using a scoped_ptr would prevent us to to
-  // skip the hop and move on. Hence the manual naked -> scoped ptr juggling.
-  auto pmd_async_state = WrapUnique(owned_pmd_async_state);
-  owned_pmd_async_state = nullptr;
-
-  // Read MemoryDumpProviderInfo thread safety considerations in
-  // memory_dump_manager.h when accessing |mdpinfo| fields.
-  MemoryDumpProviderInfo* mdpinfo =
-      pmd_async_state->pending_dump_providers.back().get();
-
   DCHECK(!mdpinfo->task_runner ||
          mdpinfo->task_runner->RunsTasksInCurrentSequence());
 
-  // Limit the scope of the TRACE_EVENT1 below to not include the
-  // SetupNextMemoryDump(). Don't replace with a BEGIN/END pair or change the
-  // event name, as the slow-reports pipeline relies on this event.
+  TRACE_EVENT1(kTraceCategory, "MemoryDumpManager::InvokeOnMemoryDump",
+               "dump_provider.name", mdpinfo->name);
+
+  // Do not add any other TRACE_EVENT macro (or function that might have them)
+  // below this point. Under some rare circunstances, they can re-initialize
+  // and invalide the current ThreadLocalEventBuffer MDP, making the
+  // |should_dump| check below susceptible to TOCTTOU bugs
+  // (https://crbug.com/763365).
+
+  bool is_thread_bound;
   {
-    TRACE_EVENT1(kTraceCategory, "MemoryDumpManager::InvokeOnMemoryDump",
-                 "dump_provider.name", mdpinfo->name);
+    // A locked access is required to R/W |disabled| (for the
+    // UnregisterAndDeleteDumpProviderSoon() case).
+    AutoLock lock(lock_);
 
-    // Do not add any other TRACE_EVENT macro (or function that might have them)
-    // below this point. Under some rare circunstances, they can re-initialize
-    // and invalide the current ThreadLocalEventBuffer MDP, making the
-    // |should_dump| check below susceptible to TOCTTOU bugs (crbug.com/763365).
-
-    bool should_dump;
-    bool is_thread_bound;
-    {
-      // A locked access is required to R/W |disabled| (for the
-      // UnregisterAndDeleteDumpProviderSoon() case).
-      AutoLock lock(lock_);
-
-      // Unregister the dump provider if it failed too many times consecutively.
-      if (!mdpinfo->disabled &&
-          mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
-        mdpinfo->disabled = true;
-        LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
-                   << "\". Dump failed multiple times consecutively.";
-      }
-      should_dump = !mdpinfo->disabled;
-      is_thread_bound = mdpinfo->task_runner != nullptr;
-    }  // AutoLock lock(lock_);
-
-    if (should_dump) {
-      // Invoke the dump provider.
-
-      // A stack allocated string with dump provider name is useful to debug
-      // crashes while invoking dump after a |dump_provider| is not unregistered
-      // in safe way.
-      // TODO(ssid): Remove this after fixing crbug.com/643438.
-      char provider_name_for_debugging[16];
-      strncpy(provider_name_for_debugging, mdpinfo->name,
-              sizeof(provider_name_for_debugging) - 1);
-      provider_name_for_debugging[sizeof(provider_name_for_debugging) - 1] =
-          '\0';
-      base::debug::Alias(provider_name_for_debugging);
-
-      ProcessMemoryDump* pmd = pmd_async_state->process_memory_dump.get();
-      ANNOTATE_BENIGN_RACE(&mdpinfo->disabled, "best-effort race detection");
-      CHECK(!is_thread_bound ||
-            !*(static_cast<volatile bool*>(&mdpinfo->disabled)));
-      bool dump_successful =
-          mdpinfo->dump_provider->OnMemoryDump(pmd->dump_args(), pmd);
-      mdpinfo->consecutive_failures =
-          dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
+    // Unregister the dump provider if it failed too many times consecutively.
+    if (!mdpinfo->disabled &&
+        mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+      mdpinfo->disabled = true;
+      DLOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
+                  << "\". Dump failed multiple times consecutively.";
     }
-  }
+    if (mdpinfo->disabled)
+      return;
 
-  pmd_async_state->pending_dump_providers.pop_back();
-  SetupNextMemoryDump(std::move(pmd_async_state));
+    is_thread_bound = mdpinfo->task_runner != nullptr;
+  }  // AutoLock lock(lock_);
+
+  // Invoke the dump provider.
+
+  // A stack allocated string with dump provider name is useful to debug
+  // crashes while invoking dump after a |dump_provider| is not unregistered
+  // in safe way.
+  char provider_name_for_debugging[16];
+  strncpy(provider_name_for_debugging, mdpinfo->name,
+          sizeof(provider_name_for_debugging) - 1);
+  provider_name_for_debugging[sizeof(provider_name_for_debugging) - 1] = '\0';
+  base::debug::Alias(provider_name_for_debugging);
+
+  ANNOTATE_BENIGN_RACE(&mdpinfo->disabled, "best-effort race detection");
+  CHECK(!is_thread_bound ||
+        !*(static_cast<volatile bool*>(&mdpinfo->disabled)));
+  bool dump_successful =
+      mdpinfo->dump_provider->OnMemoryDump(pmd->dump_args(), pmd);
+  mdpinfo->consecutive_failures =
+      dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
 }
 
 void MemoryDumpManager::FinishAsyncProcessDump(
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 8976982f..593bfe0 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -180,6 +180,8 @@
   friend std::default_delete<MemoryDumpManager>;  // For the testing instance.
   friend struct DefaultSingletonTraits<MemoryDumpManager>;
   friend class MemoryDumpManagerTest;
+  FRIEND_TEST_ALL_PREFIXES(MemoryDumpManagerTest,
+                           NoStackOverflowWithTooManyMDPs);
 
   // Holds the state of a process memory dump that needs to be carried over
   // across task runners in order to fulfill an asynchronous CreateProcessDump()
@@ -240,22 +242,27 @@
   static void SetInstanceForTesting(MemoryDumpManager* instance);
   static uint32_t GetDumpsSumKb(const std::string&, const ProcessMemoryDump*);
 
-  void FinishAsyncProcessDump(
-      std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
-
   // Lazily initializes dump_thread_ and returns its TaskRunner.
   scoped_refptr<base::SequencedTaskRunner> GetOrCreateBgTaskRunnerLocked();
 
-  // Calls InvokeOnMemoryDump() for the next MDP on the task runner specified by
-  // the MDP while registration. On failure to do so, skips and continues to
-  // next MDP.
-  void SetupNextMemoryDump(
-      std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+  // Calls InvokeOnMemoryDump() for the each MDP that belongs to the current
+  // task runner and switches to the task runner of the next MDP. Handles
+  // failures in MDP and thread hops, and always calls FinishAsyncProcessDump()
+  // at the end.
+  void ContinueAsyncProcessDump(
+      ProcessMemoryDumpAsyncState* owned_pmd_async_state);
 
-  // Invokes OnMemoryDump() of the next MDP and calls SetupNextMemoryDump() at
-  // the end to continue the ProcessMemoryDump. Should be called on the MDP task
+  // Returns true if the given dump type and mode allows the given MDP to dump.
+  bool IsDumpProviderAllowedToDump(const MemoryDumpRequestArgs& req_args,
+                                   const MemoryDumpProviderInfo& mdpinfo) const;
+
+  // Invokes OnMemoryDump() of the given MDP. Should be called on the MDP task
   // runner.
-  void InvokeOnMemoryDump(ProcessMemoryDumpAsyncState* owned_pmd_async_state);
+  void InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo,
+                          ProcessMemoryDump* pmd);
+
+  void FinishAsyncProcessDump(
+      std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
 
   // Helper for RegierDumpProvider* functions.
   void RegisterDumpProviderInternal(
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 22cee6d65..a7361de 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -527,16 +527,14 @@
   task_runner1->set_enabled(false);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                         MemoryDumpLevelOfDetail::DETAILED));
-  // Tasks should be individually posted even if |mdps[1]| and |mdps[2]| belong
-  // to same task runner.
   EXPECT_EQ(1u, task_runner1->no_of_post_tasks());
-  EXPECT_EQ(2u, task_runner2->no_of_post_tasks());
+  EXPECT_EQ(1u, task_runner2->no_of_post_tasks());
 
   task_runner1->set_enabled(true);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                                         MemoryDumpLevelOfDetail::DETAILED));
   EXPECT_EQ(2u, task_runner1->no_of_post_tasks());
-  EXPECT_EQ(4u, task_runner2->no_of_post_tasks());
+  EXPECT_EQ(2u, task_runner2->no_of_post_tasks());
   DisableTracing();
 }
 
@@ -1026,5 +1024,67 @@
 #endif  //  BUILDFLAG(USE_ALLOCATOR_SHIM) && !defined(OS_NACL)
 }
 
+// Mock MDP class that tests if the number of OnMemoryDump() calls are expected.
+// It is implemented without gmocks since EXPECT_CALL implementation is slow
+// when there are 1000s of instances, as required in
+// NoStackOverflowWithTooManyMDPs test.
+class SimpleMockMemoryDumpProvider : public MemoryDumpProvider {
+ public:
+  SimpleMockMemoryDumpProvider(int expected_num_dump_calls)
+      : expected_num_dump_calls_(expected_num_dump_calls), num_dump_calls_(0) {}
+
+  ~SimpleMockMemoryDumpProvider() override {
+    EXPECT_EQ(expected_num_dump_calls_, num_dump_calls_);
+  }
+
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override {
+    ++num_dump_calls_;
+    return true;
+  }
+
+ private:
+  int expected_num_dump_calls_;
+  int num_dump_calls_;
+};
+
+TEST_F(MemoryDumpManagerTest, NoStackOverflowWithTooManyMDPs) {
+  InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
+  SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
+  SetDumpProviderSummaryWhitelistForTesting(kTestMDPWhitelistForSummary);
+
+  int kMDPCount = 1000;
+  std::vector<std::unique_ptr<SimpleMockMemoryDumpProvider>> mdps;
+  for (int i = 0; i < kMDPCount; ++i) {
+    mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(1));
+    RegisterDumpProvider(mdps.back().get(), nullptr);
+  }
+  for (int i = 0; i < kMDPCount; ++i) {
+    mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(2));
+    RegisterDumpProvider(mdps.back().get(), nullptr, kDefaultOptions,
+                         kBackgroundButNotSummaryWhitelistedMDPName);
+  }
+  for (int i = 0; i < kMDPCount; ++i) {
+    mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(3));
+    RegisterDumpProvider(mdps.back().get(), nullptr, kDefaultOptions,
+                         kWhitelistedMDPName);
+  }
+  std::unique_ptr<Thread> stopped_thread(new Thread("test thread"));
+  stopped_thread->Start();
+  for (int i = 0; i < kMDPCount; ++i) {
+    mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(0));
+    RegisterDumpProvider(mdps.back().get(), stopped_thread->task_runner(),
+                         kDefaultOptions, kWhitelistedMDPName);
+  }
+  stopped_thread->Stop();
+
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::DETAILED));
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                                        MemoryDumpLevelOfDetail::BACKGROUND));
+  EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
+                                        MemoryDumpLevelOfDetail::BACKGROUND));
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/build/cipd/android/android.ensure b/build/cipd/android/android.ensure
index cee2bf1..9a2c705c 100644
--- a/build/cipd/android/android.ensure
+++ b/build/cipd/android/android.ensure
@@ -135,10 +135,3 @@
 @Subdir third_party/xstream
 chromium/third_party/xstream version:1.4.8-cr0
 
-# Three unchanging lines
-# avoid the horror that is
-# endless merge conflicts
-
-@Subdir chrome/android/profiles
-chromium/afdo/profiles/android version:3309
-
diff --git a/build/cipd/cipd_wrapper.py b/build/cipd/cipd_wrapper.py
index 630f9e6..73b1366 100755
--- a/build/cipd/cipd_wrapper.py
+++ b/build/cipd/cipd_wrapper.py
@@ -41,11 +41,24 @@
     return retcode
 
 
+def build_ensure_file(sub_files):
+  pieces = []
+  for sub in sub_files:
+    pieces.append('### Sourced from //%s' % os.path.relpath(sub, _SRC_ROOT))
+    with open(sub) as f:
+      pieces.append(f.read())
+  return '\n'.join(pieces)
+
+
 def main():
   parser = argparse.ArgumentParser(
       description='Updates CIPD-managed dependencies based on the given OS.')
 
   parser.add_argument(
+      '--keep-generated-file',
+      action='store_true',
+      help='Don\'t delete the generated ensure file, if any, on success.')
+  parser.add_argument(
       '--chromium-root',
       required=True,
       help='Root directory for dependency.')
@@ -55,12 +68,35 @@
       default='https://chrome-infra-packages.appspot.com')
   parser.add_argument(
       '--ensure-file',
+      action='append',
       type=os.path.realpath,
       required=True,
-      help='The path to the ensure file.')
+      help='The path to the ensure file. If given multiple times, this will '
+           'concatenate the given ensure files before passing them to cipd.')
   args = parser.parse_args()
-  return cipd_ensure(args.chromium_root, args.service_url, args.ensure_file)
 
+  build_own_ensure_file = len(args.ensure_file) > 1
+  if build_own_ensure_file:
+    ensure_file_contents = build_ensure_file(args.ensure_file)
+    with tempfile.NamedTemporaryFile(suffix='.ensure') as ensure_file:
+      ensure_file.write(ensure_file_contents)
+      ensure_file_name = ensure_file.name
+      ensure_file.delete = False
+  else:
+    ensure_file_name = args.ensure_file[0]
+
+  retcode = cipd_ensure(args.chromium_root, args.service_url, ensure_file_name)
+  if retcode:
+    if build_own_ensure_file:
+      print 'Ensure failed; generated input file is at', ensure_file_name
+    return retcode
+
+  if build_own_ensure_file:
+    if args.keep_generated_file:
+      print 'Leaving the generated .ensure file at', ensure_file_name
+    else:
+      os.unlink(ensure_file_name)
+  return 0
 
 if __name__ == '__main__':
   sys.exit(main())
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 2c6b988..6fddf3d0 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -108,6 +108,7 @@
   enable_frame_pointers = current_cpu != "arm"
 } else if (is_android) {
   enable_frame_pointers =
+      enable_profiling ||
       # Ensure that stacks from arm64 crash dumps are usable (crbug.com/391706).
       current_cpu == "arm64" ||
       # For x86 Android, unwind tables are huge without frame pointers
diff --git a/build/fuchsia/runner_v2/boot_image.py b/build/fuchsia/runner_v2/boot_image.py
new file mode 100644
index 0000000..0cc22b7
--- /dev/null
+++ b/build/fuchsia/runner_v2/boot_image.py
@@ -0,0 +1,99 @@
+# 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.
+
+"""Functions used to provision Fuchsia boot images."""
+
+import common
+import os
+import subprocess
+import tempfile
+
+_SSH_CONFIG_TEMPLATE = """
+Host *
+  CheckHostIP no
+  StrictHostKeyChecking no
+  ForwardAgent no
+  ForwardX11 no
+  GSSAPIDelegateCredentials no
+  UserKnownHostsFile {known_hosts}
+  User fuchsia
+  IdentitiesOnly yes
+  IdentityFile {identity}
+  ControlPersist yes
+  ControlMaster auto
+  ControlPath /tmp/fuchsia--%r@%h:%p
+  ServerAliveInterval 1
+  ServerAliveCountMax 1"""
+
+
+def _GetKernelPath(target_arch):
+  return os.path.join(_TargetCpuToSdkBinPath(target_arch), 'zircon.bin')
+
+
+def _TargetCpuToSdkBinPath(target_arch):
+  """Returns the path to the kernel & bootfs .bin files for |target_cpu|."""
+  return os.path.join(common.SDK_ROOT, 'target', target_arch)
+
+
+def _ProvisionSSH(output_dir):
+  """Provisions the key files used by the SSH daemon, and generates a
+  configuration file used by clients for connecting to SSH.
+
+  Returns a tuple with:
+  #0: the client configuration file
+  #1: a list of file path pairs: (<path in image>, <path on build filesystem>).
+  """
+
+  host_key_path = output_dir + '/ssh_key'
+  host_pubkey_path = host_key_path + '.pub'
+  id_key_path = output_dir + '/id_ed25519'
+  id_pubkey_path = id_key_path + '.pub'
+  known_hosts_path = output_dir + '/known_hosts'
+  ssh_config_path = output_dir + '/ssh_config'
+
+  if not os.path.isfile(host_key_path):
+    subprocess.check_call(['ssh-keygen', '-t', 'ed25519', '-h', '-f',
+                           host_key_path, '-P', '', '-N', ''],
+                          stdout=open(os.devnull))
+  if not os.path.isfile(id_key_path):
+    subprocess.check_call(['ssh-keygen', '-t', 'ed25519', '-f', id_key_path,
+                           '-P', '', '-N', ''], stdout=open(os.devnull))
+
+  with open(ssh_config_path, "w") as ssh_config:
+    ssh_config.write(
+        _SSH_CONFIG_TEMPLATE.format(identity=id_key_path,
+                                    known_hosts=known_hosts_path))
+
+  return (
+      ssh_config_path,
+      (('data/ssh/ssh_host_ed25519_key', host_key_path),
+       ('data/ssh/ssh_host_ed25519_key.pub', host_pubkey_path),
+       ('data/ssh/authorized_keys', id_pubkey_path))
+  )
+
+
+def CreateBootFS(output_dir, target_arch):
+  """Creates a bootfs image provisoned with the credentials necessary
+  for SSH remote access.
+
+  Returns a tuple with the path to SSH config and the path to the boot
+  image."""
+
+  boot_image = os.path.join(
+      _TargetCpuToSdkBinPath(target_arch), 'bootdata.bin')
+  ssh_manifest = tempfile.NamedTemporaryFile(delete=False)
+  ssh_config, ssh_data = _ProvisionSSH(output_dir)
+  for key, val in ssh_data:
+    ssh_manifest.write("%s=%s\n" % (key, val))
+  ssh_manifest.close()
+  mkbootfs_path = os.path.join(common.SDK_ROOT, 'tools', 'mkbootfs')
+  bootfs_name = output_dir + '/image.bootfs'
+  args = [mkbootfs_path, '-o', bootfs_name,
+          '--target=boot', boot_image,
+          '--target=system', ssh_manifest.name]
+
+  subprocess.check_call(args)
+  os.remove(ssh_manifest.name)
+
+  return ssh_config, bootfs_name
diff --git a/build/fuchsia/runner_v2/common.py b/build/fuchsia/runner_v2/common.py
new file mode 100644
index 0000000..c2a489ad
--- /dev/null
+++ b/build/fuchsia/runner_v2/common.py
@@ -0,0 +1,10 @@
+# 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 os
+
+DIR_SOURCE_ROOT = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
+SDK_ROOT = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'fuchsia-sdk')
+
diff --git a/build/fuchsia/runner_v2/qemu_target.py b/build/fuchsia/runner_v2/qemu_target.py
new file mode 100644
index 0000000..d5ffb44
--- /dev/null
+++ b/build/fuchsia/runner_v2/qemu_target.py
@@ -0,0 +1,127 @@
+# 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.
+
+"""Implements commands for running and interacting with Fuchsia on QEMU."""
+
+import boot_image
+import common
+import target
+import os
+import platform
+import socket
+import subprocess
+import time
+
+
+# Virtual networking configuration data for QEMU.
+GUEST_NET = '192.168.3.0/24'
+GUEST_IP_ADDRESS = '192.168.3.9'
+HOST_IP_ADDRESS = '192.168.3.2'
+GUEST_MAC_ADDRESS = '52:54:00:63:5e:7b'
+
+
+def _GetAvailableTcpPort():
+  """Finds a (probably) open port by opening and closing a listen socket."""
+  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+  sock.bind(("", 0))
+  port = sock.getsockname()[1]
+  sock.close()
+  return port
+
+
+class QemuTarget(target.Target):
+  def __init__(self, output_dir, target_cpu, verbose=True):
+    """output_dir: The directory which will contain the files that are
+                   generated to support the QEMU deployment.
+    target_cpu: The emulated target CPU architecture. Can be 'x64' or 'arm64'.
+    verbose: If true, emits extra non-error logging data for diagnostics."""
+    super(QemuTarget, self).__init__(output_dir, target_cpu, verbose)
+    self._qemu_process = None
+
+  def __enter__(self):
+    return self
+
+  # Used by the context manager to ensure that QEMU is killed when the Python
+  # process exits.
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    if self.IsStarted():
+      self.Shutdown()
+
+  def Start(self):
+    self._ssh_config_path, boot_image_path = boot_image.CreateBootFS(
+        self._output_dir, self._GetTargetSdkArch())
+    qemu_path = os.path.join(
+        common.SDK_ROOT, 'qemu', 'bin',
+        'qemu-system-' + self._GetTargetSdkArch())
+    kernel_args = ['devmgr.epoch=%d' % time.time()]
+
+    qemu_command = [qemu_path,
+        '-m', '2048',
+        '-nographic',
+        '-kernel', boot_image._GetKernelPath(self._GetTargetSdkArch()),
+        '-initrd', boot_image_path,
+        '-smp', '4',
+
+        # Use stdio for the guest OS only; don't attach the QEMU interactive
+        # monitor.
+        '-serial', 'stdio',
+        '-monitor', 'none',
+
+        # TERM=dumb tells the guest OS to not emit ANSI commands that trigger
+        # noisy ANSI spew from the user's terminal emulator.
+        '-append', 'TERM=dumb ' + ' '.join(kernel_args)
+      ]
+
+    # Configure the machine & CPU to emulate, based on the target architecture.
+    # Enable lightweight virtualization (KVM) if the host and guest OS run on
+    # the same architecture.
+    if self._target_cpu == 'arm64':
+      qemu_command.extend([
+          '-machine','virt',
+          '-cpu', 'cortex-a53',
+      ])
+      netdev_type = 'virtio-net-pci'
+      if platform.machine() == 'aarch64':
+        qemu_command.append('-enable-kvm')
+    else:
+      qemu_command.extend([
+          '-machine', 'q35',
+          '-cpu', 'host,migratable=no',
+      ])
+      netdev_type = 'e1000'
+      if platform.machine() == 'x86_64':
+        qemu_command.append('-enable-kvm')
+
+    # Configure virtual network. It is used in the tests to connect to
+    # testserver running on the host.
+    netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
+            (GUEST_NET, GUEST_IP_ADDRESS, HOST_IP_ADDRESS)
+
+    self._host_ssh_port = _GetAvailableTcpPort()
+    netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
+    qemu_command.extend([
+      '-netdev', netdev_config,
+      '-device', '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
+    ])
+
+    # We pass a separate stdin stream to qemu. Sharing stdin across processes
+    # leads to flakiness due to the OS prematurely killing the stream and the
+    # Python script panicking and aborting.
+    # The precise root cause is still nebulous, but this fix works.
+    # See crbug.com/741194.
+    self._qemu_process = subprocess.Popen(
+        qemu_command, stdout=subprocess.PIPE, stdin=open(os.devnull))
+
+    self._Attach();
+
+  def Shutdown(self):
+    self._qemu_process.kill()
+
+  def _GetEndpoint(self):
+    return ('127.0.0.1', self._host_ssh_port)
+
+  def _GetSshConfigPath(self):
+    return self._ssh_config_path
+
+
diff --git a/build/fuchsia/runner_v2/qemu_target_test.py b/build/fuchsia/runner_v2/qemu_target_test.py
new file mode 100755
index 0000000..ab287684
--- /dev/null
+++ b/build/fuchsia/runner_v2/qemu_target_test.py
@@ -0,0 +1,57 @@
+#!/usr/bin/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.
+
+import qemu_target
+import shutil
+import tempfile
+import time
+import unittest
+
+TEST_PAYLOAD = "Let's get this payload across the finish line!"
+
+tmpdir = tempfile.mkdtemp()
+
+# Register the target with the context manager so that it always gets
+# torn down on process exit. Otherwise there might be lingering QEMU instances
+# if Python crashes or is interrupted.
+with qemu_target.QemuTarget(tmpdir, 'x64') as target:
+  class TestQemuTarget(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls):
+      target.Start()
+
+    @classmethod
+    def tearDownClass(cls):
+      target.Shutdown()
+      shutil.rmtree(tmpdir)
+
+    def testCopyBidirectional(self):
+      tmp_path = tmpdir + "/payload"
+      with open(tmp_path, "w") as tmpfile:
+        tmpfile.write(TEST_PAYLOAD)
+      target.CopyTo(tmp_path, '/tmp/payload')
+
+      tmp_path_roundtrip = tmp_path + ".roundtrip"
+      target.CopyFrom('/tmp/payload', tmp_path_roundtrip)
+      with open(tmp_path_roundtrip) as roundtrip:
+        self.assertEqual(TEST_PAYLOAD, roundtrip.read())
+
+    def testRunCommand(self):
+      self.assertEqual(0, target.RunCommand(['true']))
+
+      # This is a known bug: https://fuchsia.atlassian.net/browse/NET-349
+      self.assertEqual(1, target.RunCommand(['false']))
+
+    def testRunCommandPiped(self):
+      proc = target.RunCommandPiped(['cat'])
+      proc.stdin.write(TEST_PAYLOAD)
+      proc.stdin.flush()
+      proc.stdin.close()
+      self.assertEqual(TEST_PAYLOAD, proc.stdout.readline())
+      proc.kill()
+
+
+  if __name__ == '__main__':
+      unittest.main()
diff --git a/build/fuchsia/runner_v2/remote_cmd.py b/build/fuchsia/runner_v2/remote_cmd.py
new file mode 100644
index 0000000..8d7ad3a
--- /dev/null
+++ b/build/fuchsia/runner_v2/remote_cmd.py
@@ -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.
+
+"""Helper functions for remotely executing and copying files over a SSH
+connection."""
+
+import os
+import subprocess
+
+_SSH = ['ssh']
+_SCP = ['scp']
+
+COPY_TO_TARGET = 0
+COPY_FROM_TARGET = 1
+
+
+def RunSsh(config_path, host, port, command, silent):
+  """Executes an SSH command on the remote host and blocks until completion.
+
+  config_path: Full path to SSH configuration.
+  host: The hostname or IP address of the remote host.
+  port: The port to connect to.
+  command: A list of strings containing the command and its arguments.
+  silent: If true, suppresses all output from 'ssh'.
+
+  Returns the exit code from the remote command."""
+
+  ssh_command = _SSH + ['-F', config_path,
+                        host,
+                        '-p', str(port)] + command
+  if silent:
+    devnull = open(os.devnull, 'w')
+    return subprocess.call(ssh_command, stderr=devnull, stdout=devnull)
+  else:
+    return subprocess.call(ssh_command)
+
+
+def RunPipedSsh(config_path, host, port, command):
+  """Executes an SSH command on the remote host and returns a process object
+  with access to the command's stdio streams. Does not block.
+
+  config_path: Full path to SSH configuration.
+  host: The hostname or IP address of the remote host.
+  port: The port to connect to.
+  command: A list of strings containing the command and its arguments.
+  silent: If true, suppresses all output from 'ssh'.
+
+  Returns a Popen object for the command."""
+
+  ssh_command = _SSH + ['-F', config_path,
+                        host,
+                        '-p', str(port)] + command
+  return subprocess.Popen(ssh_command,
+                          stdout=subprocess.PIPE,
+                          stderr=subprocess.PIPE,
+                          stdin=subprocess.PIPE)
+
+
+def RunScp(config_path, host, port, source, dest, direction):
+  """Copies a file to or from a remote host using SCP and blocks until
+  completion.
+
+  config_path: Full path to SSH configuration.
+  host: The hostname or IP address of the remote host.
+  port: The port to connect to.
+  source: The path of the file to be copied.
+  dest: The path that |source| will be copied to.
+  direction: Indicates whether the file should be copied to
+             or from the remote side.
+             Valid values are COPY_TO_TARGET or COPY_FROM_TARGET.
+
+  Function will raise an assertion if a failure occurred."""
+
+  if direction == COPY_TO_TARGET:
+    dest = "%s:%s" % (host, dest)
+  else:
+    source = "%s:%s" % (host, source)
+
+  scp_command = _SCP + ['-F', config_path,
+                        '-P', str(port),
+                        source,
+                        dest]
+  devnull = open('/dev/null', 'w')
+  subprocess.check_call(scp_command, stdout=devnull)
diff --git a/build/fuchsia/runner_v2/target.py b/build/fuchsia/runner_v2/target.py
new file mode 100644
index 0000000..05ee996
--- /dev/null
+++ b/build/fuchsia/runner_v2/target.py
@@ -0,0 +1,121 @@
+# 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 os
+import remote_cmd
+import subprocess
+import sys
+import tempfile
+import time
+
+_SHUTDOWN_CMD = ['dm', 'poweroff']
+_ATTACH_MAX_RETRIES = 10
+_ATTACH_RETRY_INTERVAL = 1
+
+
+class Target(object):
+  """Abstract base class representing a Fuchsia deployment target."""
+
+  def __init__(self, output_dir, target_cpu, verbose):
+    self._target_cpu = target_cpu
+    self._output_dir = output_dir
+    self._started = False
+    self._dry_run = False
+    self._vlogger = sys.stdout if verbose else open(os.devnull, 'w')
+
+  def Start(self):
+    """Handles the instantiation and connection process for the Fuchsia
+    target instance."""
+    pass
+
+  def IsStarted(self):
+    """Returns true if the Fuchsia target instance is ready to accept
+    commands."""
+    return self._started
+
+  def RunCommandPiped(self, command):
+    """Starts a remote command and immediately returns a Popen object for the
+    command. The caller may interact with the streams, inspect the status code,
+    wait on command termination, etc.
+
+    command: A list of strings representing the command and arguments.
+
+    Returns: a Popen object.
+
+    Note: method does not block."""
+
+    self._AssertStarted()
+    host, port = self._GetEndpoint()
+    return remote_cmd.RunPipedSsh(self._GetSshConfigPath(), host, port, command)
+
+  def RunCommand(self, command, silent=False):
+    """Executes a remote command and waits for it to finish executing.
+
+    Returns the exit code of the command."""
+
+    self._AssertStarted()
+    host, port = self._GetEndpoint()
+    return remote_cmd.RunSsh(self._GetSshConfigPath(), host, port, command,
+                             silent)
+
+  def CopyTo(self, source, dest):
+    """Copies a file from the local filesystem to the target filesystem.
+
+    source: The path of the file being copied.
+    dest: The path on the remote filesystem which will be copied to."""
+
+    self._AssertStarted()
+    host, port = self._GetEndpoint()
+    command = remote_cmd.RunScp(self._GetSshConfigPath(), host, port,
+                                source, dest, remote_cmd.COPY_TO_TARGET)
+
+  def CopyFrom(self, source, dest):
+    """Copies a file from the target filesystem to the local filesystem.
+
+    source: The path of the file being copied.
+    dest: The path on the local filesystem which will be copied to."""
+    self._AssertStarted()
+    host, port = self._GetEndpoint()
+    return remote_cmd.RunScp(self._GetSshConfigPath(), host, port,
+                             source, dest, remote_cmd.COPY_FROM_TARGET)
+
+  def Shutdown(self):
+    self.RunCommand(_SHUTDOWN_CMD)
+    self._started = False
+
+  def _GetEndpoint(self):
+    """Returns a (host, port) tuple for the SSH connection to the target."""
+    raise NotImplementedError
+
+  def _GetTargetSdkArch(self):
+    """Returns the Fuchsia SDK architecture name for the target CPU."""
+    if self._target_cpu == 'arm64':
+      return 'aarch64'
+    elif self._target_cpu == 'x64':
+      return 'x86_64'
+    raise Exception('Unknown target_cpu:' + self._target_cpu)
+
+  def _AssertStarted(self):
+    assert self.IsStarted()
+
+  def _Attach(self):
+    self._vlogger.write('Trying to connect over SSH...')
+    self._vlogger.flush()
+    for _ in xrange(_ATTACH_MAX_RETRIES):
+      host, port = self._GetEndpoint()
+      if remote_cmd.RunSsh(self._ssh_config_path, host, port, ['echo'],
+                           True) == 0:
+        self._vlogger.write(' connected!\n')
+        self._vlogger.flush()
+        self._started = True
+        return
+      self._vlogger.write('.')
+      self._vlogger.flush()
+      time.sleep(_ATTACH_RETRY_INTERVAL)
+    sys.stderr.write(' timeout limit reached.\n')
+    raise Exception('Couldn\'t connect to QEMU using SSH.')
+
+  def _GetSshConfigPath(self, path):
+    raise NotImplementedError
+
diff --git a/chrome/VERSION b/chrome/VERSION
index 9838309..1125028c 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=65
 MINOR=0
-BUILD=3317
+BUILD=3318
 PATCH=0
diff --git a/chrome/android/OWNERS b/chrome/android/OWNERS
index d798ab1..fc025754 100644
--- a/chrome/android/OWNERS
+++ b/chrome/android/OWNERS
@@ -5,6 +5,7 @@
 tedchoc@chromium.org
 yfriedman@chromium.org
 
+per-file android.ensure=*
 per-file static_initializers.gni=*
 per-file java_sources.gni=*
 per-file *.gn*=agrieve@chromium.org
diff --git a/chrome/android/android.ensure b/chrome/android/android.ensure
new file mode 100644
index 0000000..dc23627
--- /dev/null
+++ b/chrome/android/android.ensure
@@ -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.
+
+# Chromium-specific dependencies for Android target OS.
+
+# -crX indicates the chromium-specific revision of a package at a given version.
+
+@Subdir chrome/android/profiles
+chromium/afdo/profiles/android version:3309
+
+# Three unchanging lines
+# avoid the horror that is
+# endless merge conflicts
+
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 03edf2d..58fd3f5 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
@@ -328,8 +328,8 @@
     @Override
     public void setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager) {
         super.setTabModelSelector(modelSelector, manager);
-        mStacks[0].setTabModel(modelSelector.getModel(false));
-        mStacks[1].setTabModel(modelSelector.getModel(true));
+        mStacks[0].setTabList(modelSelector.getModel(false));
+        mStacks[1].setTabList(modelSelector.getModel(true));
         resetScrollData();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
index 8230bc21..e3718c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
@@ -22,7 +22,7 @@
 import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
 import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackAnimation.OverviewAnimationType;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
@@ -146,7 +146,7 @@
     private static final float LANDSCAPE_SWIPE_DRAG_TAB_OFFSET_DP = 40.f;
 
     // External References
-    private TabModel mTabModel;
+    private TabList mTabList;
 
     // True when the stack is still visible for animation but it is going to be empty.
     private boolean mIsDying;
@@ -240,7 +240,7 @@
     private float mBorderTopPadding;
     private float mBorderLeftPadding;
 
-    private boolean mIsStackForCurrentTabModel;
+    private boolean mIsStackForCurrentTabList;
 
     private final AnimatorListenerAdapter mViewAnimatorListener = new AnimatorListenerAdapter() {
         @Override
@@ -263,10 +263,10 @@
     }
 
     /**
-     * @param tabmodel The model to attach to this stack.
+     * @param tabList The list to attach to this stack.
      */
-    public void setTabModel(TabModel tabmodel) {
-        mTabModel = tabmodel;
+    public void setTabList(TabList tabList) {
+        mTabList = tabList;
     }
 
     /**
@@ -403,7 +403,7 @@
             finishAnimation(time);
         }
         startAnimation(time, OverviewAnimationType.NEW_TAB_OPENED,
-                TabModelUtils.getTabIndexById(mTabModel, id), TabModel.INVALID_TAB_INDEX, false);
+                TabModelUtils.getTabIndexById(mTabList, id), TabList.INVALID_TAB_INDEX, false);
     }
 
     /**
@@ -413,7 +413,7 @@
      * @param id   The id of the tab to select.
      */
     public void tabSelectingEffect(long time, int id) {
-        int index = TabModelUtils.getTabIndexById(mTabModel, id);
+        int index = TabModelUtils.getTabIndexById(mTabList, id);
         startAnimation(time, OverviewAnimationType.TAB_FOCUSED, index, -1, false);
     }
 
@@ -433,10 +433,10 @@
     }
 
     /**
-     * @return Whether or not the TabModel represented by this TabStackState should be displayed.
+     * @return Whether or not the TabList represented by this TabStackState should be displayed.
      */
     public boolean isDisplayable() {
-        return !mTabModel.isIncognito() || (!mIsDying && mTabModel.getCount() > 0);
+        return !mTabList.isIncognito() || (!mIsDying && mTabList.getCount() > 0);
     }
 
     private float getDefaultDiscardDirection() {
@@ -447,10 +447,10 @@
     /**
      * show is called to set up the initial variables, and must always be called before
      * displaying the stack.
-     * @param isStackForCurrentTabModel Whether this {@link Stack} is for the current tab model.
+     * @param isStackForCurrentTabList Whether this {@link Stack} is for the current tab list.
      */
-    public void show(boolean isStackForCurrentTabModel) {
-        mIsStackForCurrentTabModel = isStackForCurrentTabModel;
+    public void show(boolean isStackForCurrentTabList) {
+        mIsStackForCurrentTabList = isStackForCurrentTabList;
 
         mDiscardDirection = getDefaultDiscardDirection();
 
@@ -476,7 +476,7 @@
      * @param type The type of the animation to start.
      */
     private void startAnimation(long time, OverviewAnimationType type) {
-        startAnimation(time, type, TabModel.INVALID_TAB_INDEX, false);
+        startAnimation(time, type, TabList.INVALID_TAB_INDEX, false);
     }
 
     /**
@@ -487,7 +487,7 @@
      * @param finishImmediately Whether the animation jumps straight to the end.
      */
     private void startAnimation(long time, OverviewAnimationType type, boolean finishImmediately) {
-        startAnimation(time, type, TabModel.INVALID_TAB_INDEX, finishImmediately);
+        startAnimation(time, type, TabList.INVALID_TAB_INDEX, finishImmediately);
     }
 
     /**
@@ -500,7 +500,7 @@
      */
     private void startAnimation(
             long time, OverviewAnimationType type, int sourceIndex, boolean finishImmediately) {
-        startAnimation(time, type, mTabModel.index(), sourceIndex, finishImmediately);
+        startAnimation(time, type, mTabList.index(), sourceIndex, finishImmediately);
     }
 
     private void startAnimation(long time, OverviewAnimationType type, int focusIndex,
@@ -519,7 +519,7 @@
             // First try to build a View animation.  Then fallback to the compositor animation if
             // one isn't created.
             mViewAnimations = mViewAnimationFactory.createAnimatorForType(
-                    type, mStackTabs, mLayout.getViewContainer(), mTabModel, focusIndex);
+                    type, mStackTabs, mLayout.getViewContainer(), mTabList, focusIndex);
 
             if (mViewAnimations != null) {
                 mViewAnimations.addListener(mViewAnimatorListener);
@@ -569,7 +569,7 @@
                 // Nothing to do.
                 break;
             case DISCARD_ALL:
-                mLayout.uiDoneClosingAllTabs(mTabModel.isIncognito());
+                mLayout.uiDoneClosingAllTabs(mTabList.isIncognito());
                 cleanupStackTabState();
                 break;
             case UNDISCARD:
@@ -584,7 +584,7 @@
                         StackTab tab = mStackTabs[i];
                         if (tab.isDying()) {
                             mLayout.uiDoneClosingTab(
-                                    time, tab.getId(), true, mTabModel.isIncognito());
+                                    time, tab.getId(), true, mTabList.isIncognito());
                         }
                     }
                 }
@@ -836,8 +836,8 @@
             if (!mInSwipe) {
                 mDiscardingTab = getTabAtPositon(x, y);
             } else {
-                if (mTabModel.index() < 0) return;
-                mDiscardingTab = mStackTabs[mTabModel.index()];
+                if (mTabList.index() < 0) return;
+                mDiscardingTab = mStackTabs[mTabList.index()];
             }
 
             if (mDiscardingTab != null) {
@@ -905,7 +905,7 @@
         }
 
         if (mScrollingTab == null && mInSwipe && mStackTabs != null) {
-            int index = mTabModel.index();
+            int index = mTabList.index();
             if (index >= 0 && index <= mStackTabs.length) mScrollingTab = mStackTabs[index];
         }
 
@@ -1974,17 +1974,17 @@
      *                     we're calling this while the switcher is already visible.
      */
     private void createStackTabs(boolean restoreState) {
-        final int count = mTabModel.getCount();
+        final int count = mTabList.getCount();
         if (count == 0) {
             cleanupTabs();
         } else {
             StackTab[] oldTabs = mStackTabs;
             mStackTabs = new StackTab[count];
 
-            final boolean isIncognito = mTabModel.isIncognito();
+            final boolean isIncognito = mTabList.isIncognito();
             final boolean needTitle = !mLayout.isHiding();
             for (int i = 0; i < count; ++i) {
-                Tab tab = mTabModel.getTabAt(i);
+                Tab tab = mTabList.getTabAt(i);
                 int tabId = tab != null ? tab.getId() : Tab.INVALID_TAB_ID;
                 mStackTabs[i] = findTabById(oldTabs, tabId);
 
@@ -2001,8 +2001,7 @@
                 layoutTab.setInsetBorderVertical(true);
                 layoutTab.setShowToolbar(!FeatureUtilities.isChromeHomeEnabled());
                 layoutTab.setToolbarAlpha(0.f);
-                layoutTab.setAnonymizeToolbar(!mIsStackForCurrentTabModel
-                        || mTabModel.index() != i);
+                layoutTab.setAnonymizeToolbar(!mIsStackForCurrentTabList || mTabList.index() != i);
 
                 if (mStackTabs[i] == null) {
                     mStackTabs[i] = new StackTab(layoutTab);
@@ -2034,7 +2033,7 @@
      * @return   Whether the tab has successfully been created and added.
      */
     private boolean createTabHelper(int id) {
-        if (TabModelUtils.getTabById(mTabModel, id) == null) return false;
+        if (TabModelUtils.getTabById(mTabList, id) == null) return false;
 
         // Check to see if the tab already exists in our model.  This is
         // just to cover the case where stackEntered and then tabCreated()
@@ -2215,15 +2214,15 @@
     }
 
     private void resetAllScrollOffset() {
-        if (mTabModel == null) return;
+        if (mTabList == null) return;
         // Reset the scroll position to put the important {@link StackTab} into focus.
         // This does not scroll the {@link StackTab}s there but rather moves everything
         // there immediately.
         // The selected tab is supposed to show at the center of the screen.
         float maxTabsPerPage = getScrollDimensionSize() / mSpacing;
         float centerOffsetIndex = maxTabsPerPage / 2.0f - 0.5f;
-        final int count = mTabModel.getCount();
-        final int index = mTabModel.index();
+        final int count = mTabList.getCount();
+        final int index = mTabList.index();
         if (index < centerOffsetIndex || count <= maxTabsPerPage) {
             mScrollOffset = 0;
         } else if (index == count - 1 && Math.ceil(maxTabsPerPage) < count) {
@@ -2407,7 +2406,7 @@
         startAnimation(time, OverviewAnimationType.ENTER_STACK);
 
         // Update the scroll offset to put the focused tab at the top.
-        final int index = mTabModel.index();
+        final int index = mTabList.index();
 
         if (mCurrentMode == Orientation.PORTRAIT) {
             mScrollOffset = -index * mSpacing;
@@ -2448,7 +2447,7 @@
         if (ty > toolbarSize) mSwipeCanScroll = true;
         if (!mSwipeCanScroll) return;
 
-        final int index = mTabModel.index();
+        final int index = mTabList.index();
 
         // Check to make sure the index is still valid.
         if (index < 0 || index >= mStackTabs.length) {
@@ -2536,7 +2535,7 @@
         mEvenOutProgress = 0.f;
 
         // Select the current tab so we exit the switcher.
-        Tab tab = TabModelUtils.getCurrentTab(mTabModel);
+        Tab tab = TabModelUtils.getCurrentTab(mTabList);
         mLayout.uiSelectingTab(time, tab != null ? tab.getId() : Tab.INVALID_TAB_ID);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackViewAnimation.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackViewAnimation.java
index ddc0db3..a329d3e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackViewAnimation.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackViewAnimation.java
@@ -14,7 +14,7 @@
 
 import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackAnimation.OverviewAnimationType;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
@@ -47,18 +47,18 @@
      *                   method is called.
      * @param tabs       The tabs that make up the current stack.
      * @param container  The {@link ViewGroup} that {@link View}s can be added to/removed from.
-     * @param model      The {@link TabModel} that this animation will influence.
+     * @param list       The {@link TabList} that this animation will influence.
      * @param focusIndex The index of the tab that is the focus of this animation.
      * @return           The resulting {@link Animator} that will animate the Android views.
      */
     public Animator createAnimatorForType(OverviewAnimationType type, StackTab[] tabs,
-            ViewGroup container, TabModel model, int focusIndex) {
+            ViewGroup container, TabList list, int focusIndex) {
         Animator animator = null;
 
-        if (model != null) {
+        if (list != null) {
             switch (type) {
                 case NEW_TAB_OPENED:
-                    animator = createNewTabOpenedAnimator(tabs, container, model, focusIndex);
+                    animator = createNewTabOpenedAnimator(tabs, container, list, focusIndex);
                     break;
                 default:
                     break;
@@ -69,8 +69,8 @@
     }
 
     private Animator createNewTabOpenedAnimator(
-            StackTab[] tabs, ViewGroup container, TabModel model, int focusIndex) {
-        Tab tab = model.getTabAt(focusIndex);
+            StackTab[] tabs, ViewGroup container, TabList list, int focusIndex) {
+        Tab tab = list.getTabAt(focusIndex);
         if (tab == null || !tab.isNativePage()) return null;
 
         View view = tab.getView();
@@ -105,4 +105,4 @@
         bgView.setPivotX(LocalizationUtils.isLayoutRtl() ? mWidthDp * mDpToPx - insetPx : insetPx);
         return animator;
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 77c5091..1c9bc319 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -407,7 +407,33 @@
      */
     public void savePageLater(final String url, final ClientId clientId, boolean userRequested,
             OfflinePageOrigin origin) {
-        nativeSavePageLater(mNativeOfflinePageBridge, url, clientId.getNamespace(),
+        savePageLater(url, clientId, userRequested, origin, null);
+    }
+
+    /**
+     * Save the given URL as an offline page when the network becomes available with the given
+     * origin. Callback with status when done.
+     *
+     * @param url The given URL to save for later.
+     * @param clientId the clientId for the offline page to be saved later.
+     * @param userRequested Whether this request should be prioritized because the user explicitly
+     *                      requested it.
+     * @param origin The app that initiated the request.
+     * @param callback Callback for whether the URL is successfully added to queue. Non-zero number
+     *                 represents a failure reason (See offline_pages::AddRequestResult enum). 0 is
+     * success.
+     */
+    public void savePageLater(final String url, final ClientId clientId, boolean userRequested,
+            OfflinePageOrigin origin, Callback<Integer> callback) {
+        Callback<Integer> wrapper = new Callback<Integer>() {
+            @Override
+            public void onResult(Integer i) {
+                if (callback != null) {
+                    callback.onResult(i);
+                }
+            }
+        };
+        nativeSavePageLater(mNativeOfflinePageBridge, wrapper, url, clientId.getNamespace(),
                 clientId.getId(), origin.encodeAsJsonString(), userRequested);
     }
 
@@ -436,8 +462,27 @@
      */
     public void savePageLater(final String url, final String namespace, boolean userRequested,
             OfflinePageOrigin origin) {
+        savePageLater(url, namespace, userRequested, origin, null);
+    }
+
+    /**
+     * Save the given URL as an offline page when the network becomes available with a randomly
+     * generated clientId in the given namespace and the given origin. Calls back with whether
+     * the URL has been successfully added to queue.
+     *
+     * @param url The given URL to save for later
+     * @param namespace The namespace for the offline page to be saved later.
+     * @param userRequested Whether this request should be prioritized because the user explicitly
+     *                      requested it.
+     * @param origin The app that initiated the request.
+     * @param callback Callback to call whether the URL is successfully added to the queue. Non-zero
+     *                 number represents failure reason (see offline_pages::AddRequestResult enum).
+     * 0 is success.
+     */
+    public void savePageLater(final String url, final String namespace, boolean userRequested,
+            OfflinePageOrigin origin, Callback<Integer> callback) {
         ClientId clientId = ClientId.createGuidClientIdForNamespace(namespace);
-        savePageLater(url, clientId, userRequested, origin);
+        savePageLater(url, clientId, userRequested, origin, callback);
     }
 
     /**
@@ -734,8 +779,9 @@
             Callback<OfflinePageItem> callback);
     private native void nativeSavePage(long nativeOfflinePageBridge, SavePageCallback callback,
             WebContents webContents, String clientNamespace, String clientId, String origin);
-    private native void nativeSavePageLater(long nativeOfflinePageBridge, String url,
-            String clientNamespace, String clientId, String origin, boolean userRequested);
+    private native void nativeSavePageLater(long nativeOfflinePageBridge,
+            Callback<Integer> callback, String url, String clientNamespace, String clientId,
+            String origin, boolean userRequested);
     private native String nativeGetOfflinePageHeaderForReload(
             long nativeOfflinePageBridge, WebContents webContents);
     private native boolean nativeIsShowingOfflinePreview(
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 f484d54..e966222 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
@@ -1054,8 +1054,9 @@
                 : mDefaultToolbarView;
         if (newToolbar != oldToolbar) {
             // For the toolbar transition, make sure we don't detach the default toolbar view.
-            animators.add(getViewTransitionAnimator(
-                    newToolbar, oldToolbar, mToolbarHolder, mDefaultToolbarView != oldToolbar));
+            Animator transitionAnimator = getViewTransitionAnimator(
+                    newToolbar, oldToolbar, mToolbarHolder, mDefaultToolbarView != oldToolbar);
+            if (transitionAnimator != null) animators.add(transitionAnimator);
         }
 
         // Add an animator for the content transition if needed.
@@ -1064,8 +1065,9 @@
             if (oldContent != null) mBottomSheetContentContainer.removeView(oldContent);
         } else {
             View contentView = content.getContentView();
-            animators.add(getViewTransitionAnimator(
-                    contentView, oldContent, mBottomSheetContentContainer, true));
+            Animator transitionAnimator = getViewTransitionAnimator(
+                    contentView, oldContent, mBottomSheetContentContainer, true);
+            if (transitionAnimator != null) animators.add(transitionAnimator);
         }
 
         // Temporarily make the background of the toolbar holder a solid color so the transition
@@ -1123,9 +1125,11 @@
      * before the new view is faded in. There is an option to detach the old view or not.
      * @param newView The new view to transition to.
      * @param oldView The old view to transition from.
+     * @param parent The parent for newView and oldView.
      * @param detachOldView Whether or not to detach the old view once faded out.
-     * @return An animator that runs the specified animation.
+     * @return An animator that runs the specified animation or null if no animation should be run.
      */
+    @Nullable
     private Animator getViewTransitionAnimator(final View newView, final View oldView,
             final ViewGroup parent, final boolean detachOldView) {
         if (newView == oldView) return null;
@@ -1135,6 +1139,21 @@
 
         newView.setVisibility(View.VISIBLE);
 
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+                && !ValueAnimator.areAnimatorsEnabled()) {
+            if (oldView != null) {
+                // Post a runnable to remove the old view to prevent issues related to the keyboard
+                // showing while swapping contents. See https://crbug.com/799252.
+                post(() -> { swapViews(newView, oldView, parent, detachOldView); });
+            } else {
+                if (parent != newView.getParent()) parent.addView(newView);
+            }
+
+            newView.setAlpha(1);
+
+            return null;
+        }
+
         // Fade out the old view.
         if (oldView != null) {
             ValueAnimator fadeOutAnimator = ObjectAnimator.ofFloat(oldView, View.ALPHA, 0);
@@ -1142,12 +1161,7 @@
             fadeOutAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    if (detachOldView && oldView.getParent() != null) {
-                        parent.removeView(oldView);
-                    } else {
-                        oldView.setVisibility(View.INVISIBLE);
-                    }
-                    if (parent != newView.getParent()) parent.addView(newView);
+                    swapViews(newView, oldView, parent, detachOldView);
                 }
             });
             animators.add(fadeOutAnimator);
@@ -1169,6 +1183,23 @@
     }
 
     /**
+     * Removes the oldView (or sets it to invisible) and adds the new view to the specified parent.
+     * @param newView The new view to transition to.
+     * @param oldView The old view to transition from.
+     * @param parent The parent for newView and oldView.
+     * @param detachOldView Whether or not to detach the old view once faded out.
+     */
+    private void swapViews(final View newView, final View oldView, final ViewGroup parent,
+            final boolean detachOldView) {
+        if (detachOldView && oldView.getParent() != null) {
+            parent.removeView(oldView);
+        } else {
+            oldView.setVisibility(View.INVISIBLE);
+        }
+        if (parent != newView.getParent()) parent.addView(newView);
+    }
+
+    /**
      * A notification that the sheet is exiting the peek state into one that shows content.
      * @param reason The reason the sheet was opened, if any.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java
index 48f466328..e560b5d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/textbubble/TextBubble.java
@@ -7,6 +7,7 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Handler;
 import android.support.annotation.StringRes;
 import android.view.Gravity;
@@ -187,17 +188,7 @@
         createContentView();
         updateBubbleLayout();
         mPopupWindow.showAtLocation(mRootView, Gravity.TOP | Gravity.START, mX, mY);
-
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (!mPopupWindow.isShowing() || mPopupWindow.getContentView() == null) return;
-
-                mPopupWindow.getContentView().announceForAccessibility(
-                        mContext.getString(mAccessibilityStringId));
-            }
-        });
-
+        announceForAccessibility();
         sBubbles.add(this);
     }
 
@@ -417,6 +408,29 @@
                 new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
     }
 
+    /**
+     * Announce an accessibility event about the bubble text.
+     */
+    private void announceForAccessibility() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (!mPopupWindow.isShowing() || mPopupWindow.getContentView() == null) return;
+
+                View view = null;
+                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+                    view = mPopupWindow.getContentView();
+                } else {
+                    // For Android J and K, send the accessibility event from root view.
+                    // See https://crbug.com/773387.
+                    view = mRootView;
+                }
+                if (view == null) return;
+                view.announceForAccessibility(mContext.getString(mAccessibilityStringId));
+            }
+        });
+    }
+
     // OnTouchListener implementation.
     @SuppressLint("ClickableViewAccessibility")
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
index d8723ff..8cef5f4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -28,6 +28,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.offlinepages.DeletePageResult;
 import org.chromium.components.offlinepages.SavePageResult;
+import org.chromium.components.offlinepages.background.UpdateRequestResult;
 import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.net.test.EmbeddedTestServer;
 
@@ -237,10 +238,7 @@
         List<OfflinePageBridge.RequestRemovedResult> removed =
                 removeRequestsFromQueue(requestsToRemove);
         Assert.assertEquals(requests[1].getRequestId(), removed.get(0).getRequestId());
-        Assert.assertEquals(
-                org.chromium.components.offlinepages.background.UpdateRequestResult.SUCCESS,
-                removed.get(0).getUpdateRequestResult());
-
+        Assert.assertEquals(UpdateRequestResult.SUCCESS, removed.get(0).getUpdateRequestResult());
         SavePageRequest[] remaining = getRequestsInQueue();
         Assert.assertEquals(1, remaining.length);
 
@@ -586,12 +584,22 @@
 
     private void savePageLater(final String url, final String namespace)
             throws InterruptedException {
+        final Semaphore semaphore = new Semaphore(0);
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mOfflinePageBridge.savePageLater(url, namespace, true /* userRequested */);
+                mOfflinePageBridge.savePageLater(url, namespace, true /* userRequested */,
+                        new OfflinePageOrigin(), new Callback<Integer>() {
+                            @Override
+                            public void onResult(Integer i) {
+                                Assert.assertEquals("SavePageLater did not succeed", new Integer(0),
+                                        i); // 0 is SUCCESS
+                                semaphore.release();
+                            }
+                        });
             }
         });
+        Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     private SavePageRequest[] getRequestsInQueue() throws InterruptedException {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1b36b60d..3bdb909 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10988,6 +10988,18 @@
       Chrome is being controlled by automated test software.
     </message>
 
+    <!-- Security Key permission -->
+    <message name="IDS_SECURITY_KEY_ATTESTATION_PERMISSION_FRAGMENT" desc="Permission request shown when a site requests attestation information from a Security Key. This follows a prompt: 'This site would like to:'">
+      See the serial number of your security key
+    </message>
+    <if expr="is_android">
+      <message name="IDS_SECURITY_KEY_ATTESTATION_INFOBAR_QUESTION" desc="Wording of an info bar prompt when a site requests attestation information from a Security Key.">
+        <ph name="URL">
+          $1<ex>maps.google.com</ex>
+        </ph> wants to see the serial number of your security key
+      </message>
+    </if>
+
     <!-- Media capture notification strings -->
     <if expr="is_android or enable_vr">
       <message name="IDS_VIDEO_CALL_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when a WebRTC video call is in progress." formatter_data="android_java">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 7748728..c930003 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1162,25 +1162,25 @@
       Searching...
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_ERROR_MESSAGE" desc="The message shown when a new printer is not set up successfully.">
-      Error adding printer
+      Can&#x2019;t add printer. Restart your computer and try again.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_FATAL_ERROR_MESSAGE" desc="The message shown when a fatal error occurs while trying to add a new printer.">
-      Can't add printer. Restart and try again.
+      Can&#x2019;t add printer. Restart your computer and try again.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PRINTER_UNREACHABLE_MESSAGE" desc="The message shown when the printer that is to be added is unreachable for configuration.">
-      Can't connect printer. Check that the printer is turned on and is connected to your Chromebook by Wi-Fi or USB.
+      Can&#x2019;t connect to printer. Check that the printer is turned on and is connected to your Chromebook by Wi-Fi or USB.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_TOO_LARGE_MESSAGE" desc="The message shown when the PPD provided while trying to add new printer is too large.">
-      Can't load large PPD. Maximum size is 250kB.
+      Can&#x2019;t load large PPD. Maximum size is 250 kB.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_INVALID_PPD_MESSAGE" desc="The message shown when the PPD provided while trying to add a new printer is invalid.">
-      Provided PPD is invalid.
+      File is the wrong format. Check the PPD file and try again.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_NOT_FOUND" desc="The message shown when the PPD provided while trying to add a new printer cannot be found.">
-      Can't find PPD. Check that your Chromebook is online and try again.
+      Can&#x2019;t find PPD. Make sure your Chromebook is online and try again.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_ADDED_PRINTER_PPD_UNRETRIEVABLE" desc="The message shown when the PPD provided while trying to add a new printer is unretrievable.">
-      Can't find PPD. Check that your Chromebook is online and try again.
+      Can&#x2019;t find PPD. Make sure your Chromebook is online and try again.
     </message>
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_REQUIRE_INTERNET_MESSAGE" desc="The message shown when there is no internet access to set up a printer.">
       Connect to the internet to add a printer
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index e9a38b5..f8ce92d 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -95,6 +95,7 @@
     "tablet.icon",
     "translate.icon",
     "trash_can.icon",
+    "usb_security_key.icon",
     "user_account_avatar.icon",
     "warning_badge.icon",
     "web.icon",
diff --git a/chrome/app/vector_icons/usb_security_key.icon b/chrome/app/vector_icons/usb_security_key.icon
new file mode 100644
index 0000000..de8dcf0c
--- /dev/null
+++ b/chrome/app/vector_icons/usb_security_key.icon
@@ -0,0 +1,16 @@
+// 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.
+
+CANVAS_DIMENSIONS, 45,
+ROUND_RECT, 0.23f, 14.75f, 31.56f, 15.01f, 0,
+ROUND_RECT, 31.05f, 16.79f, 13.63f, 10.94f, 0,
+ROUND_RECT, 34.31f, 17.75f, 9.69f, 1.92f, 0,
+ROUND_RECT, 34.31f, 24.95f, 9.79f, 1.92f, 0,
+ROUND_RECT, 34.31f, 20.15f, 8.45f, 1.92f, 0,
+ROUND_RECT, 34.31f, 22.55f, 8.45f, 1.92f, 0,
+MOVE_TO, 19.72f, 22.07f,
+R_ARC_TO, 3.94f, 3.94f, 0, 1, 1, -7.87f, 0,
+R_ARC_TO, 3.94f, 3.94f, 0, 0, 1, 7.87f, 0,
+CLOSE,
+END
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index f0bf608..1eab1808 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -46,7 +46,6 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tab_helpers.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
-#include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
@@ -71,7 +70,6 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/browser_controls_state.h"
 #include "content/public/common/resource_request_body.h"
 #include "jni/Tab_jni.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -720,19 +718,22 @@
       static_cast<content::BrowserControlsState>(constraints);
   content::BrowserControlsState current_state =
       static_cast<content::BrowserControlsState>(current);
-  content::RenderViewHost* sender = web_contents()->GetRenderViewHost();
-  sender->Send(new ChromeViewMsg_UpdateBrowserControlsState(
-      sender->GetRoutingID(), constraints_state, current_state, animate));
+
+  chrome::mojom::ChromeRenderFrameAssociatedPtr renderer;
+  web_contents()->GetMainFrame()->GetRemoteAssociatedInterfaces()->GetInterface(
+      &renderer);
+  renderer->UpdateBrowserControlsState(constraints_state, current_state,
+                                       animate);
 
   if (web_contents()->ShowingInterstitialPage()) {
-    content::RenderViewHost* interstitial_view_host =
-        web_contents()
-            ->GetInterstitialPage()
-            ->GetMainFrame()
-            ->GetRenderViewHost();
-    interstitial_view_host->Send(new ChromeViewMsg_UpdateBrowserControlsState(
-        interstitial_view_host->GetRoutingID(), constraints_state,
-        current_state, animate));
+    chrome::mojom::ChromeRenderFrameAssociatedPtr interstitial_renderer;
+    web_contents()
+        ->GetInterstitialPage()
+        ->GetMainFrame()
+        ->GetRemoteAssociatedInterfaces()
+        ->GetInterface(&interstitial_renderer);
+    interstitial_renderer->UpdateBrowserControlsState(constraints_state,
+                                                      current_state, animate);
   }
 }
 
diff --git a/chrome/browser/autofill/risk_util.cc b/chrome/browser/autofill/risk_util.cc
index 3fee1881..5d11839 100644
--- a/chrome/browser/autofill/risk_util.cc
+++ b/chrome/browser/autofill/risk_util.cc
@@ -69,8 +69,7 @@
 void LoadRiskData(
     uint64_t obfuscated_gaia_id,
     content::WebContents* web_contents,
-    const base::RepeatingCallback<void(const std::string&)>& callback,
-    service_manager::Connector* connector) {
+    const base::RepeatingCallback<void(const std::string&)>& callback) {
   // No easy way to get window bounds on Android, and that signal isn't very
   // useful anyway (given that we're also including the bounds of the web
   // contents).
@@ -90,10 +89,8 @@
 
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(content::ServiceManagerConnection::GetForProcess());
-  if (!connector) {
-    connector =
-        content::ServiceManagerConnection::GetForProcess()->GetConnector();
-  }
+  service_manager::Connector* connector =
+      content::ServiceManagerConnection::GetForProcess()->GetConnector();
 
   risk::GetFingerprint(
       obfuscated_gaia_id, window_bounds, web_contents,
diff --git a/chrome/browser/autofill/risk_util.h b/chrome/browser/autofill/risk_util.h
index 7788e57..32d38c0 100644
--- a/chrome/browser/autofill/risk_util.h
+++ b/chrome/browser/autofill/risk_util.h
@@ -15,24 +15,17 @@
 class WebContents;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 namespace autofill {
 
 // Loads risk data for the client, getting the device's risk fingerprint before
 // calling |callback|. |obfuscated_gaia_id| is used in the fingerprinting
 // process if provided. |web_contents| is used during fingerprinting as well,
 // when retrieving user prefs, and in determining window bounds when not on
-// Android. |connector| is an optional parameter that, if set, is used instead
-// of content::ServiceManagerConnection::GetForProcess()->GetConnector() (for
-// testing purposes).
+// Android.
 void LoadRiskData(
     uint64_t obfuscated_gaia_id,
     content::WebContents* web_contents,
-    const base::RepeatingCallback<void(const std::string&)>& callback,
-    service_manager::Connector* connector = nullptr);
+    const base::RepeatingCallback<void(const std::string&)>& callback);
 
 }  // namespace autofill
 
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 048d4438..da3ff40 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -2764,8 +2764,6 @@
       // TODO(710873): Make sure that these get fixed:
       // Not deleted but should be deleted with history?
       CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO,
-      // Deprecated and should be removed after M60.
-      CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
       // Is cleared in PasswordProtectionService::CleanUpExpiredVerdicts()
       // but not when CBD is executed.
       CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 418ebe55..614490f 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -508,8 +508,6 @@
     "dbus/kiosk_info_service_provider.h",
     "dbus/screen_lock_service_provider.cc",
     "dbus/screen_lock_service_provider.h",
-    "display/display_configuration_observer.cc",
-    "display/display_configuration_observer.h",
     "display/output_protection_controller_ash.cc",
     "display/output_protection_controller_ash.h",
     "display/output_protection_controller_mus.cc",
@@ -1774,7 +1772,6 @@
     "base/file_flusher_unittest.cc",
     "certificate_provider/certificate_provider_service_unittest.cc",
     "customization/customization_document_unittest.cc",
-    "display/display_prefs_unittest.cc",
     "drive/download_handler_unittest.cc",
     "drive/drive_file_stream_reader_unittest.cc",
     "drive/drive_integration_service_unittest.cc",
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/watcher_manager.cc b/chrome/browser/chromeos/file_system_provider/fileapi/watcher_manager.cc
index c479bcb..0c28e40 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/watcher_manager.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/watcher_manager.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file.h"
 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "content/public/browser/browser_thread.h"
 #include "storage/browser/fileapi/file_system_url.h"
@@ -47,6 +48,11 @@
     return;
   }
 
+  if (!parser.file_system()->GetFileSystemInfo().watchable()) {
+    callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
+    return;
+  }
+
   parser.file_system()->AddWatcher(url.origin(),
                                    parser.file_path(),
                                    recursive,
@@ -66,6 +72,11 @@
     return;
   }
 
+  if (!parser.file_system()->GetFileSystemInfo().watchable()) {
+    callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
+    return;
+  }
+
   parser.file_system()->RemoveWatcher(
       url.origin(), parser.file_path(), recursive, callback);
 }
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 7a7957f..f5b3aaa 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -398,6 +398,10 @@
   web_view()->web_contents()->FocusThroughTabTraversal(reverse);
   GetWidget()->Activate();
   web_view()->web_contents()->Focus();
+
+  content::WebUI* web_ui = GetWebUI();
+  if (web_ui)
+    web_ui->CallJavascriptFunctionUnsafe("cr.ui.Oobe.focusReturned");
 }
 
 void WebUILoginView::Observe(int type,
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
index 5d8ca42..61a0bf3 100644
--- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
+++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
@@ -168,6 +168,7 @@
   d->RegisterHandlerWithCallback("setIsDocked",
                                  &Delegate::SetIsDocked, delegate);
   d->RegisterHandler("openInNewTab", &Delegate::OpenInNewTab, delegate);
+  d->RegisterHandler("showItemInFolder", &Delegate::ShowItemInFolder, delegate);
   d->RegisterHandler("save", &Delegate::SaveToFile, delegate);
   d->RegisterHandler("append", &Delegate::AppendToFile, delegate);
   d->RegisterHandler("requestFileSystems",
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h
index c78aa62..a23ba54 100644
--- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h
+++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h
@@ -41,6 +41,7 @@
     virtual void SetIsDocked(const DispatchCallback& callback,
                              bool is_docked) = 0;
     virtual void OpenInNewTab(const std::string& url) = 0;
+    virtual void ShowItemInFolder(const std::string& file_system_path) = 0;
     virtual void SaveToFile(const std::string& url,
                             const std::string& content,
                             bool save_as) = 0;
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index c9d21ab..6e848f3 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/devtools/devtools_file_watcher.h"
 #include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/common/pref_names.h"
@@ -423,6 +422,24 @@
   return file_systems_paths_value->HasKey(file_system_path);
 }
 
+void DevToolsFileHelper::OnOpenItemComplete(
+    const base::FilePath& path,
+    platform_util::OpenOperationResult result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (result == platform_util::OPEN_FAILED_INVALID_TYPE)
+    platform_util::ShowItemInFolder(profile_, path);
+}
+
+void DevToolsFileHelper::ShowItemInFolder(const std::string& file_system_path) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (file_system_path.empty())
+    return;
+  base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
+  platform_util::OpenItem(profile_, path, platform_util::OPEN_FOLDER,
+                          base::Bind(&DevToolsFileHelper::OnOpenItemComplete,
+                                     weak_factory_.GetWeakPtr(), path));
+}
+
 void DevToolsFileHelper::FileSystemPathsSettingChanged() {
   PathToType remaining;
   remaining.swap(file_system_paths_);
diff --git a/chrome/browser/devtools/devtools_file_helper.h b/chrome/browser/devtools/devtools_file_helper.h
index 645ef74..9b86959 100644
--- a/chrome/browser/devtools/devtools_file_helper.h
+++ b/chrome/browser/devtools/devtools_file_helper.h
@@ -17,6 +17,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/devtools/devtools_file_watcher.h"
+#include "chrome/browser/platform_util.h"
 #include "components/prefs/pref_change_registrar.h"
 
 class Profile;
@@ -121,7 +122,12 @@
   // granted.
   bool IsFileSystemAdded(const std::string& file_system_path);
 
+  // Opens and reveals file in OS's default file manager.
+  void ShowItemInFolder(const std::string& file_system_path);
+
  private:
+  void OnOpenItemComplete(const base::FilePath& path,
+                          platform_util::OpenOperationResult result);
   void SaveAsFileSelected(const std::string& url,
                           const std::string& content,
                           const SaveCallback& callback,
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 335c8a92..fc517ad 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -699,6 +699,11 @@
   delegate_->OpenInNewTab(url);
 }
 
+void DevToolsUIBindings::ShowItemInFolder(const std::string& file_system_path) {
+  CHECK(IsValidFrontendURL(web_contents_->GetURL()) && frontend_host_);
+  file_helper_->ShowItemInFolder(file_system_path);
+}
+
 void DevToolsUIBindings::SaveToFile(const std::string& url,
                                     const std::string& content,
                                     bool save_as) {
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h
index d90d2210..35e58b6 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.h
+++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -110,6 +110,7 @@
                            int stream_id) override;
   void SetIsDocked(const DispatchCallback& callback, bool is_docked) override;
   void OpenInNewTab(const std::string& url) override;
+  void ShowItemInFolder(const std::string& file_system_path) override;
   void SaveToFile(const std::string& url,
                   const std::string& content,
                   bool save_as) override;
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index f74226a2..59e6124 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -390,8 +390,9 @@
 
 base::string16 DownloadItemModel::GetTooltipText(const gfx::FontList& font_list,
                                                  int max_width) const {
-  base::string16 tooltip = gfx::ElideFilename(
-      download_->GetFileNameToReportUser(), font_list, max_width);
+  base::string16 tooltip =
+      gfx::ElideFilename(download_->GetFileNameToReportUser(), font_list,
+                         max_width, gfx::Typesetter::TOOLTIPS);
   content::DownloadInterruptReason reason = download_->GetLastReason();
   if (download_->GetState() == DownloadItem::INTERRUPTED &&
       reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
@@ -408,7 +409,7 @@
   DCHECK(IsDangerous());
   base::string16 elided_filename =
       gfx::ElideFilename(download_->GetFileNameToReportUser(), font_list,
-                        base_width);
+                         base_width, gfx::Typesetter::PLATFORM);
   switch (download_->GetDangerType()) {
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
       return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 3948216..c732c6e 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h"
 #include "chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h"
 #include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h"
+#include "chrome/browser/ui/webui/devtools_ui.h"
 #include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "content/public/browser/browser_context.h"
@@ -103,6 +104,11 @@
                                          signin::kDiceResponseHeader) == 0));
 }
 
+bool ChromeExtensionsAPIClient::ShouldHideBrowserNetworkRequest(
+    const GURL& url) const {
+  return DevToolsUI::IsFrontendResourceURL(url);
+}
+
 AppViewGuestDelegate* ChromeExtensionsAPIClient::CreateAppViewGuestDelegate()
     const {
   return new ChromeAppViewGuestDelegate();
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index bf32204..dbe7a3e7b 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -32,6 +32,7 @@
       override;
   bool ShouldHideResponseHeader(const GURL& url,
                                 const std::string& header_name) const override;
+  bool ShouldHideBrowserNetworkRequest(const GURL& url) const override;
   AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
   ExtensionOptionsGuestDelegate* CreateExtensionOptionsGuestDelegate(
       ExtensionOptionsGuest* guest) const override;
diff --git a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc
index bc8703f..6e99d23 100644
--- a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc
+++ b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc
@@ -6,14 +6,24 @@
 
 #include <stddef.h>
 
+#include "base/callback.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/permissions/permission_request.h"
+#include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/grit/generated_resources.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "crypto/sha2.h"
 #include "extensions/common/error_utils.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace {
 
@@ -47,9 +57,56 @@
   return false;
 }
 
+// AttestationPermissionRequest is a delegate class that provides information
+// and callbacks to the PermissionRequestManager.
+//
+// PermissionRequestManager has a reference to this object and so this object
+// must outlive it. Since attestation requests are never canceled,
+// PermissionRequestManager guarentees that |RequestFinished| will always,
+// eventually, be called. This object uses that fact to delete itself during
+// |RequestFinished| and thus owns itself.
+class AttestationPermissionRequest : public PermissionRequest {
+ public:
+  AttestationPermissionRequest(const GURL& app_id,
+                               base::OnceCallback<void(bool)> callback)
+      : app_id_(app_id), callback_(std::move(callback)) {}
+
+  PermissionRequest::IconId GetIconId() const override {
+    return kUsbSecurityKeyIcon;
+  }
+
+  base::string16 GetMessageTextFragment() const override {
+    return l10n_util::GetStringUTF16(
+        IDS_SECURITY_KEY_ATTESTATION_PERMISSION_FRAGMENT);
+  }
+  GURL GetOrigin() const override { return app_id_; }
+  void PermissionGranted() override { std::move(callback_).Run(true); }
+  void PermissionDenied() override { std::move(callback_).Run(false); }
+  void Cancelled() override { std::move(callback_).Run(false); }
+
+  void RequestFinished() override {
+    if (callback_)
+      std::move(callback_).Run(false);
+    delete this;
+  }
+
+  PermissionRequestType GetPermissionRequestType() const override {
+    return PermissionRequestType::PERMISSION_SECURITY_KEY_ATTESTATION;
+  }
+
+ private:
+  ~AttestationPermissionRequest() override = default;
+
+  const GURL app_id_;
+  base::OnceCallback<void(bool)> callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(AttestationPermissionRequest);
+};
+
 }  // namespace
 
 namespace extensions {
+
 namespace api {
 
 void CryptotokenRegisterProfilePrefs(
@@ -58,9 +115,7 @@
 }
 
 CryptotokenPrivateCanOriginAssertAppIdFunction::
-    CryptotokenPrivateCanOriginAssertAppIdFunction()
-    : chrome_details_(this) {
-}
+    CryptotokenPrivateCanOriginAssertAppIdFunction() = default;
 
 ExtensionFunction::ResponseAction
 CryptotokenPrivateCanOriginAssertAppIdFunction::Run() {
@@ -80,7 +135,7 @@
   }
 
   if (origin_url == app_id_url) {
-    return RespondNow(OneArgument(base::MakeUnique<base::Value>(true)));
+    return RespondNow(OneArgument(std::make_unique<base::Value>(true)));
   }
 
   // Fetch the eTLD+1 of both.
@@ -101,7 +156,7 @@
         "Could not find an eTLD for appId *", params->app_id_url)));
   }
   if (origin_etldp1 == app_id_etldp1) {
-    return RespondNow(OneArgument(base::MakeUnique<base::Value>(true)));
+    return RespondNow(OneArgument(std::make_unique<base::Value>(true)));
   }
   // For legacy purposes, allow google.com origins to assert certain
   // gstatic.com appIds.
@@ -109,15 +164,14 @@
   if (origin_etldp1 == kGoogleDotCom) {
     for (const char* id : kGoogleGstaticAppIds) {
       if (params->app_id_url == id)
-        return RespondNow(OneArgument(base::MakeUnique<base::Value>(true)));
+        return RespondNow(OneArgument(std::make_unique<base::Value>(true)));
     }
   }
-  return RespondNow(OneArgument(base::MakeUnique<base::Value>(false)));
+  return RespondNow(OneArgument(std::make_unique<base::Value>(false)));
 }
 
 CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction::
-    CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction()
-    : chrome_details_(this) {}
+    CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction() {}
 
 ExtensionFunction::ResponseAction
 CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction::Run() {
@@ -137,5 +191,66 @@
           ContainsAppIdByHash(*permit_attestation, params->app_id_hash))));
 }
 
+CryptotokenPrivateCanAppIdGetAttestationFunction::
+    CryptotokenPrivateCanAppIdGetAttestationFunction() {}
+
+ExtensionFunction::ResponseAction
+CryptotokenPrivateCanAppIdGetAttestationFunction::Run() {
+  std::unique_ptr<cryptotoken_private::CanAppIdGetAttestation::Params> params =
+      cryptotoken_private::CanAppIdGetAttestation::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params);
+  const std::string& app_id = params->options.app_id;
+
+  // If the appId is permitted by the enterprise policy then no permission
+  // prompt is shown.
+  Profile* const profile = Profile::FromBrowserContext(browser_context());
+  const PrefService* const prefs = profile->GetPrefs();
+  const base::ListValue* const permit_attestation =
+      prefs->GetList(prefs::kSecurityKeyPermitAttestation);
+
+  if (std::find_if(permit_attestation->begin(), permit_attestation->end(),
+                   [&app_id](const base::Value& v) -> bool {
+                     return v.GetString() == app_id;
+                   }) != permit_attestation->end()) {
+    return RespondNow(OneArgument(std::make_unique<base::Value>(true)));
+  }
+
+  // If prompting is disabled, allow attestation because that is the historical
+  // behavior.
+  if (!base::FeatureList::IsEnabled(features::kSecurityKeyAttestationPrompt)) {
+    return RespondNow(OneArgument(std::make_unique<base::Value>(true)));
+  }
+
+  // Otherwise, show a permission prompt and pass the user's decision back.
+  const GURL app_id_url(app_id);
+  EXTENSION_FUNCTION_VALIDATE(app_id_url.is_valid());
+
+  content::WebContents* web_contents = nullptr;
+  if (!ExtensionTabUtil::GetTabById(params->options.tab_id, browser_context(),
+                                    true /* include incognito windows */,
+                                    nullptr /* out_browser */,
+                                    nullptr /* out_tab_strip */, &web_contents,
+                                    nullptr /* out_tab_index */)) {
+    return RespondNow(Error("cannot find specified tab"));
+  }
+
+  PermissionRequestManager* permission_request_manager =
+      PermissionRequestManager::FromWebContents(web_contents);
+  if (!permission_request_manager) {
+    return RespondNow(Error("no PermissionRequestManager"));
+  }
+
+  // The created AttestationPermissionRequest deletes itself once complete.
+  permission_request_manager->AddRequest(new AttestationPermissionRequest(
+      app_id_url,
+      base::BindOnce(
+          &CryptotokenPrivateCanAppIdGetAttestationFunction::Complete, this)));
+  return RespondLater();
+}
+
+void CryptotokenPrivateCanAppIdGetAttestationFunction::Complete(bool result) {
+  Respond(OneArgument(std::make_unique<base::Value>(result)));
+}
+
 }  // namespace api
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h
index 2642284..7c92493 100644
--- a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h
+++ b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h
@@ -35,9 +35,6 @@
   protected:
     ~CryptotokenPrivateCanOriginAssertAppIdFunction() override {}
     ResponseAction Run() override;
-
-  private:
-    ChromeExtensionFunctionDetails chrome_details_;
 };
 
 class CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction
@@ -51,9 +48,19 @@
  protected:
   ~CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction() override {}
   ResponseAction Run() override;
+};
 
- private:
-  ChromeExtensionFunctionDetails chrome_details_;
+class CryptotokenPrivateCanAppIdGetAttestationFunction
+    : public UIThreadExtensionFunction {
+ public:
+  CryptotokenPrivateCanAppIdGetAttestationFunction();
+  DECLARE_EXTENSION_FUNCTION("cryptotokenPrivate.canAppIdGetAttestation",
+                             CRYPTOTOKENPRIVATE_CANAPPIDGETATTESTATION)
+
+ protected:
+  ~CryptotokenPrivateCanAppIdGetAttestationFunction() override {}
+  ResponseAction Run() override;
+  void Complete(bool result);
 };
 
 }  // namespace api
diff --git a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
index e198d041..a88874b 100644
--- a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
@@ -10,10 +10,17 @@
 #include <utility>
 #include <vector>
 
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/extensions/extension_api_unittest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/permissions/permission_request_manager.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
+#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "crypto/sha2.h"
+#include "extensions/browser/api_test_utils.h"
+#include "extensions/browser/extension_function_dispatcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using crypto::SHA256HashString;
@@ -24,40 +31,40 @@
 
 using namespace api::cryptotoken_private;
 
+bool GetSingleBooleanResult(UIThreadExtensionFunction* function, bool* result) {
+  const base::ListValue* result_list = function->GetResultList();
+  if (!result_list) {
+    ADD_FAILURE() << "Function has no result list.";
+    return false;
+  }
+
+  if (result_list->GetSize() != 1u) {
+    ADD_FAILURE() << "Invalid number of results.";
+    return false;
+  }
+
+  if (!result_list->GetBoolean(0, result)) {
+    ADD_FAILURE() << "Result is not boolean.";
+    return false;
+  }
+
+  return true;
+}
+
 class CryptoTokenPrivateApiTest : public extensions::ExtensionApiUnittest {
  public:
   CryptoTokenPrivateApiTest() {}
   ~CryptoTokenPrivateApiTest() override {}
 
  protected:
-  bool GetSingleBooleanResult(
-      UIThreadExtensionFunction* function, bool* result) {
-    const base::ListValue* result_list = function->GetResultList();
-    if (!result_list) {
-      ADD_FAILURE() << "Function has no result list.";
-      return false;
-    }
-
-    if (result_list->GetSize() != 1u) {
-      ADD_FAILURE() << "Invalid number of results.";
-      return false;
-    }
-
-    if (!result_list->GetBoolean(0, result)) {
-      ADD_FAILURE() << "Result is not boolean.";
-      return false;
-    }
-    return true;
-  }
-
   bool GetCanOriginAssertAppIdResult(const std::string& origin,
                                      const std::string& app_id,
-                                     bool *out_result) {
-    scoped_refptr<api::CryptotokenPrivateCanOriginAssertAppIdFunction> function(
-        new api::CryptotokenPrivateCanOriginAssertAppIdFunction());
+                                     bool* out_result) {
+    auto function = base::MakeRefCounted<
+        api::CryptotokenPrivateCanOriginAssertAppIdFunction>();
     function->set_has_callback(true);
 
-    std::unique_ptr<base::ListValue> args(new base::ListValue);
+    auto args = std::make_unique<base::ListValue>();
     args->AppendString(origin);
     args->AppendString(app_id);
 
@@ -72,10 +79,8 @@
 
   bool GetAppIdHashInEnterpriseContext(const std::string& app_id,
                                        bool* out_result) {
-    scoped_refptr<api::CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction>
-        function(
-            new api::
-                CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction());
+    auto function = base::MakeRefCounted<
+        api::CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction>();
     function->set_has_callback(true);
 
     auto args = std::make_unique<base::Value>(base::Value::Type::LIST);
@@ -156,4 +161,103 @@
 
 }  // namespace
 
+class CryptoTokenPermissionTest : public ExtensionApiUnittest {
+ public:
+  CryptoTokenPermissionTest() = default;
+  ~CryptoTokenPermissionTest() override = default;
+
+  void SetUp() override {
+    feature_list_.InitWithFeatures({features::kSecurityKeyAttestationPrompt},
+                                   {});
+
+    ExtensionApiUnittest::SetUp();
+    const GURL url("http://example.com");
+    AddTab(browser(), url);
+
+    content::WebContents* web_contents =
+        browser()->tab_strip_model()->GetWebContentsAt(0);
+    tab_id_ = SessionTabHelper::IdForTab(web_contents);
+    PermissionRequestManager::CreateForWebContents(web_contents);
+    prompt_factory_ = std::make_unique<MockPermissionPromptFactory>(
+        PermissionRequestManager::FromWebContents(web_contents));
+  }
+
+  void TearDown() override {
+    prompt_factory_.reset();
+    ExtensionApiUnittest::TearDown();
+  }
+
+ protected:
+  // CanAppIdGetAttestation calls the cryptotoken private API of the same name
+  // for |app_id| and sets |*out_result| to the result. If |bubble_action| is
+  // not |NONE| then it waits for the permissions prompt to be shown and
+  // performs the given action. Otherwise, the call is expected to be
+  // synchronous.
+  bool CanAppIdGetAttestation(
+      const std::string& app_id,
+      PermissionRequestManager::AutoResponseType bubble_action,
+      bool* out_result) {
+    if (bubble_action != PermissionRequestManager::NONE) {
+      prompt_factory_->set_response_type(bubble_action);
+      prompt_factory_->DocumentOnLoadCompletedInMainFrame();
+    }
+
+    auto function = base::MakeRefCounted<
+        api::CryptotokenPrivateCanAppIdGetAttestationFunction>();
+    function->set_has_callback(true);
+
+    base::Value::DictStorage dict;
+    dict.emplace("appId", std::make_unique<base::Value>(app_id));
+    dict.emplace("tabId", std::make_unique<base::Value>(tab_id_));
+    auto args = std::make_unique<base::Value>(base::Value::Type::LIST);
+    args->GetList().emplace_back(std::move(dict));
+    auto args_list = base::ListValue::From(std::move(args));
+
+    extension_function_test_utils::RunFunction(
+        function.get(), std::move(args_list), browser(),
+        extension_function_test_utils::NONE);
+
+    return GetSingleBooleanResult(function.get(), out_result);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  int tab_id_ = -1;
+  std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CryptoTokenPermissionTest);
+};
+
+TEST_F(CryptoTokenPermissionTest, Prompt) {
+  const std::vector<PermissionRequestManager::AutoResponseType> actions = {
+      PermissionRequestManager::ACCEPT_ALL, PermissionRequestManager::DENY_ALL,
+      PermissionRequestManager::DISMISS,
+  };
+
+  for (const auto& action : actions) {
+    SCOPED_TRACE(action);
+
+    bool result = false;
+    ASSERT_TRUE(CanAppIdGetAttestation("https://test.com", action, &result));
+    // The result should only be positive if the user accepted the permissions
+    // prompt.
+    EXPECT_EQ(action == PermissionRequestManager::ACCEPT_ALL, result);
+  }
+}
+
+TEST_F(CryptoTokenPermissionTest, PolicyOverridesPrompt) {
+  const std::string example_com("https://example.com");
+  base::Value::ListStorage permitted_list;
+  permitted_list.emplace_back(example_com);
+  profile()->GetPrefs()->Set(prefs::kSecurityKeyPermitAttestation,
+                             base::Value(permitted_list));
+
+  // If an appId is configured by enterprise policy then attestation requests
+  // should be permitted without showing a prompt.
+  bool result = false;
+  ASSERT_TRUE(CanAppIdGetAttestation(example_com,
+                                     PermissionRequestManager::NONE, &result));
+  EXPECT_TRUE(result);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index df74aeb..e0b875c 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/devtools/url_constants.h"
 #include "chrome/browser/extensions/active_tab_permission_granter.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -29,6 +30,7 @@
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/login/login_handler.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/search_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/login/scoped_test_public_session_login_state.h"
@@ -59,11 +61,14 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/test_data_directory.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 
 #if defined(OS_CHROMEOS)
@@ -209,6 +214,46 @@
   DISALLOW_COPY_AND_ASSIGN(TestURLFetcherDelegate);
 };
 
+// The DevTool's remote front-end is hardcoded to a URL with a fixed port.
+// Redirect all responses to a URL with port.
+class DevToolsFrontendInterceptor : public net::URLRequestInterceptor {
+ public:
+  DevToolsFrontendInterceptor(int port, const base::FilePath& root_dir)
+      : port_(port), test_root_dir_(root_dir) {}
+
+  net::URLRequestJob* MaybeInterceptRequest(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    // The DevTools front-end has a hard-coded scheme (and implicit port 443).
+    // We simulate a response for it.
+    // net::URLRequestRedirectJob cannot be used because DevToolsUIBindings
+    // rejects URLs whose base URL is not the hard-coded URL.
+    if (request->url().EffectiveIntPort() != port_) {
+      return new net::URLRequestMockHTTPJob(
+          request, network_delegate,
+          test_root_dir_.AppendASCII(request->url().path().substr(1)));
+    }
+    return nullptr;
+  }
+
+ private:
+  int port_;
+  base::FilePath test_root_dir_;
+};
+
+void SetUpDevToolsFrontendInterceptorOnIO(int port,
+                                          const base::FilePath& root_dir) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
+      "https", kRemoteFrontendDomain,
+      std::make_unique<DevToolsFrontendInterceptor>(port, root_dir));
+}
+
+void TearDownDevToolsFrontendInterceptorOnIO() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  net::URLRequestFilter::GetInstance()->ClearHandlers();
+}
+
 }  // namespace
 
 class ExtensionWebRequestApiTest : public ExtensionApiTest {
@@ -231,6 +276,50 @@
       const char* exptected_content_incognito_window);
 };
 
+class DevToolsFrontendInWebRequestApiTest : public ExtensionApiTest {
+ public:
+  void SetUpOnMainThread() override {
+    ExtensionApiTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+
+    int port = embedded_test_server()->port();
+    base::RunLoop run_loop;
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&SetUpDevToolsFrontendInterceptorOnIO, port,
+                       test_root_dir_),
+        run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  void TearDownOnMainThread() override {
+    base::RunLoop run_loop;
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&TearDownDevToolsFrontendInterceptorOnIO),
+        run_loop.QuitClosure());
+    run_loop.Run();
+    ExtensionApiTest::TearDownOnMainThread();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ExtensionApiTest::SetUpCommandLine(command_line);
+
+    test_root_dir_ = test_data_dir_.AppendASCII("webrequest");
+
+    embedded_test_server()->ServeFilesFromDirectory(test_root_dir_);
+    ASSERT_TRUE(StartEmbeddedTestServer());
+    command_line->AppendSwitchASCII(
+        switches::kCustomDevtoolsFrontend,
+        embedded_test_server()
+            ->GetURL("customfrontend.example.com", "/devtoolsfrontend/")
+            .spec());
+  }
+
+ private:
+  base::FilePath test_root_dir_;
+};
+
 IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestApi) {
   ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_api.html")) << message_;
@@ -1206,6 +1295,12 @@
   }
 }
 
+// Ensure that devtools frontend requests are hidden from the webRequest API.
+IN_PROC_BROWSER_TEST_F(DevToolsFrontendInWebRequestApiTest, HiddenRequests) {
+  ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_devtools.html"))
+      << message_;
+}
+
 // Tests that the webRequest events aren't dispatched when the request initiator
 // is protected by policy.
 IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
diff --git a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
index f48743c..818ac00 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
 #include "ash/touch/ash_touch_transform_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/command_line.h"
@@ -1638,6 +1639,7 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         ash::switches::kAshEnableTabletMode);
     DisplayInfoProviderChromeosTest::SetUp();
+    ash_test_helper()->DisableTabletMirrorModeForTest();
   }
 
  private:
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index c31e370..64c04a3 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -162,6 +162,12 @@
                           net::FilePathToFileURL(test_data_dir_).spec());
   test_config_->SetBoolean(kBrowserSideNavigationEnabled,
                            content::IsBrowserSideNavigationEnabled());
+  if (embedded_test_server()->Started()) {
+    // InitializeEmbeddedTestServer was called before |test_config_| was set.
+    // Set the missing port key.
+    test_config_->SetInteger(kEmbeddedTestServerPort,
+                             embedded_test_server()->port());
+  }
   extensions::TestGetConfigFunction::set_test_config_state(
       test_config_.get());
 }
@@ -415,8 +421,12 @@
   // Build a dictionary of values that tests can use to build URLs that
   // access the test server and local file system.  Tests can see these values
   // using the extension API function chrome.test.getConfig().
-  test_config_->SetInteger(kEmbeddedTestServerPort,
-                           embedded_test_server()->port());
+  if (test_config_) {
+    test_config_->SetInteger(kEmbeddedTestServerPort,
+                             embedded_test_server()->port());
+  }
+  // else SetUpOnMainThread has not been called yet. Possibly because the
+  // caller needs a valid port in an overridden SetUpCommandLine method.
 
   return true;
 }
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index e432bbdc..8605e84 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -17,46 +17,28 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
-#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar.h"
 #include "content/public/browser/notification_source.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/common/extension.h"
 #include "ui/base/l10n/l10n_util.h"
 
 // static
-void ThemeInstalledInfoBarDelegate::Create(
-    const extensions::Extension* new_theme,
-    Profile* profile,
-    const std::string& previous_theme_id,
-    bool previous_using_system_theme) {
-  DCHECK(new_theme);
-  if (!new_theme->is_theme())
-    return;
-
+void ThemeInstalledInfoBarDelegate::Create(InfoBarService* infobar_service,
+                                           ExtensionService* extension_service,
+                                           ThemeService* theme_service,
+                                           const std::string& theme_name,
+                                           const std::string& theme_id,
+                                           const std::string& previous_theme_id,
+                                           bool previous_using_system_theme) {
   // Create the new infobar.
-  // FindTabbedBrowser() is called with |match_original_profiles| true because a
-  // theme install in either a normal or incognito window for a profile affects
-  // all normal and incognito windows for that profile.
-  Browser* browser = chrome::FindTabbedBrowser(profile, true);
-  if (!browser)
-    return;
-  content::WebContents* web_contents =
-      browser->tab_strip_model()->GetActiveWebContents();
-  if (!web_contents)
-    return;
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents);
-  ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile);
   std::unique_ptr<infobars::InfoBar> new_infobar(
       infobar_service->CreateConfirmInfoBar(
-          std::unique_ptr<
-              ConfirmInfoBarDelegate>(new ThemeInstalledInfoBarDelegate(
-              extensions::ExtensionSystem::Get(profile)->extension_service(),
-              theme_service, new_theme, previous_theme_id,
-              previous_using_system_theme))));
+          std::unique_ptr<ConfirmInfoBarDelegate>(
+              new ThemeInstalledInfoBarDelegate(
+                  extension_service, theme_service, theme_name, theme_id,
+                  previous_theme_id, previous_using_system_theme))));
 
   // If there's a previous theme infobar, just replace that instead of adding a
   // new one.
@@ -68,7 +50,7 @@
       // If the user installed the same theme twice, ignore the second install
       // and keep the first install info bar, so that they can easily undo to
       // get back the previous theme.
-      if (theme_infobar->theme_id_ != new_theme->id()) {
+      if (theme_infobar->theme_id_ != theme_id) {
         infobar_service->ReplaceInfoBar(old_infobar, std::move(new_infobar));
         theme_service->OnInfobarDisplayed();
       }
@@ -84,14 +66,15 @@
 ThemeInstalledInfoBarDelegate::ThemeInstalledInfoBarDelegate(
     ExtensionService* extension_service,
     ThemeService* theme_service,
-    const extensions::Extension* new_theme,
+    const std::string& theme_name,
+    const std::string& theme_id,
     const std::string& previous_theme_id,
     bool previous_using_system_theme)
     : ConfirmInfoBarDelegate(),
       extension_service_(extension_service),
       theme_service_(theme_service),
-      name_(new_theme->name()),
-      theme_id_(new_theme->id()),
+      theme_name_(theme_name),
+      theme_id_(theme_id),
       previous_theme_id_(previous_theme_id),
       previous_using_system_theme_(previous_using_system_theme) {
   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
@@ -126,7 +109,7 @@
 
 base::string16 ThemeInstalledInfoBarDelegate::GetMessageText() const {
   return l10n_util::GetStringFUTF16(IDS_THEME_INSTALL_INFOBAR_LABEL,
-                                    base::UTF8ToUTF16(name_));
+                                    base::UTF8ToUTF16(theme_name_));
 }
 
 int ThemeInstalledInfoBarDelegate::GetButtons() const {
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index 46b82bf..61faab109 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -11,31 +11,32 @@
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/common/extension_id.h"
 
 class ExtensionService;
-class Profile;
+class InfoBarService;
 class ThemeService;
 
-namespace extensions {
-class Extension;
-}
-
 // When a user installs a theme, we display it immediately, but provide an
 // infobar allowing them to cancel.
 class ThemeInstalledInfoBarDelegate : public ConfirmInfoBarDelegate,
                                       public content::NotificationObserver {
  public:
-  // Creates a theme installed infobar and delegate and adds the infobar to the
-  // last active tab on |profile|.
-  static void Create(const extensions::Extension* new_theme,
-                     Profile* profile,
+  // Creates a theme installed infobar and delegate and adds the infobar to
+  // |infobar_service|, replacing any previous theme infobar.
+  static void Create(InfoBarService* infobar_service,
+                     ExtensionService* extension_service,
+                     ThemeService* theme_service,
+                     const std::string& theme_name,
+                     const std::string& theme_id,
                      const std::string& previous_theme_id,
                      bool previous_using_system_theme);
 
  private:
   ThemeInstalledInfoBarDelegate(ExtensionService* extension_service,
                                 ThemeService* theme_service,
-                                const extensions::Extension* new_theme,
+                                const std::string& theme_name,
+                                const std::string& theme_id,
                                 const std::string& previous_theme_id,
                                 bool previous_using_system_theme);
   ~ThemeInstalledInfoBarDelegate() override;
@@ -59,7 +60,7 @@
   ThemeService* theme_service_;
 
   // Name of theme that's just been installed.
-  std::string name_;
+  std::string theme_name_;
 
   // ID of theme that's just been installed.
   std::string theme_id_;
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index f409429..a69bf23 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/pepper_broker_infobar_delegate.h"
 #include "chrome/browser/plugins/hung_plugin_infobar_delegate.h"
@@ -224,6 +225,7 @@
       {"extension_dev_tools", IBD::EXTENSION_DEV_TOOLS_INFOBAR_DELEGATE},
       {"incognito_connectability",
        IBD::INCOGNITO_CONNECTABILITY_INFOBAR_DELEGATE},
+      {"theme_installed", IBD::THEME_INSTALLED_INFOBAR_DELEGATE},
       {"nacl", IBD::NACL_INFOBAR_DELEGATE},
       {"pepper_broker", IBD::PEPPER_BROKER_INFOBAR_DELEGATE},
       {"outdated_plugin", IBD::OUTDATED_PLUGIN_INFOBAR_DELEGATE},
@@ -284,6 +286,13 @@
       break;
     }
 
+    case IBD::THEME_INSTALLED_INFOBAR_DELEGATE:
+      ThemeInstalledInfoBarDelegate::Create(
+          GetInfoBarService(), nullptr,
+          ThemeServiceFactory::GetForProfile(browser()->profile()), "New Theme",
+          "id", ThemeService::kDefaultThemeID, true);
+      break;
+
     case IBD::NACL_INFOBAR_DELEGATE:
 #if BUILDFLAG(ENABLE_NACL)
       NaClInfoBarDelegate::Create(GetInfoBarService());
@@ -462,6 +471,10 @@
   ShowAndVerifyUi();
 }
 
+IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_theme_installed) {
+  ShowAndVerifyUi();
+}
+
 #if BUILDFLAG(ENABLE_NACL)
 IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_nacl) {
   ShowAndVerifyUi();
diff --git a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
index 51d501a0..075912f 100644
--- a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
@@ -105,6 +105,10 @@
   return tab->web_contents();
 }
 
+void SavePageLaterCallback(AddRequestResult result) {
+  // do nothing.
+}
+
 void SavePageIfNotNavigatedAway(const GURL& url,
                                 const GURL& original_url,
                                 const ScopedJavaGlobalRef<jobject>& j_tab_ref,
@@ -141,7 +145,8 @@
           RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER;
       params.original_url = original_url;
       params.request_origin = origin;
-      request_id = request_coordinator->SavePageLater(params);
+      request_id = request_coordinator->SavePageLater(
+          params, base::Bind(&SavePageLaterCallback));
     } else {
       DVLOG(1) << "SavePageIfNotNavigatedAway has no valid coordinator.";
     }
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc
index 2ed92e5..bd8d97bb 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.cc
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -264,6 +264,11 @@
                                         j_result_codes);
 }
 
+void SavePageLaterCallback(const ScopedJavaGlobalRef<jobject>& j_callback_obj,
+                           AddRequestResult value) {
+  base::android::RunCallbackAndroid(j_callback_obj, static_cast<int>(value));
+}
+
 }  // namespace
 
 static jboolean JNI_OfflinePageBridge_IsOfflineBookmarksEnabled(
@@ -566,13 +571,19 @@
       base::Bind(&SavePageCallback, j_callback_ref, save_page_params.url));
 }
 
-void OfflinePageBridge::SavePageLater(JNIEnv* env,
-                                      const JavaParamRef<jobject>& obj,
-                                      const JavaParamRef<jstring>& j_url,
-                                      const JavaParamRef<jstring>& j_namespace,
-                                      const JavaParamRef<jstring>& j_client_id,
-                                      const JavaParamRef<jstring>& j_origin,
-                                      jboolean user_requested) {
+void OfflinePageBridge::SavePageLater(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& j_callback_obj,
+    const JavaParamRef<jstring>& j_url,
+    const JavaParamRef<jstring>& j_namespace,
+    const JavaParamRef<jstring>& j_client_id,
+    const JavaParamRef<jstring>& j_origin,
+    jboolean user_requested) {
+  DCHECK(j_callback_obj);
+  ScopedJavaGlobalRef<jobject> j_callback_ref;
+  j_callback_ref.Reset(env, j_callback_obj);
+
   offline_pages::ClientId client_id;
   client_id.name_space = ConvertJavaStringToUTF8(env, j_namespace);
   client_id.id = ConvertJavaStringToUTF8(env, j_client_id);
@@ -588,7 +599,9 @@
   params.availability =
       RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER;
   params.request_origin = ConvertJavaStringToUTF8(env, j_origin);
-  coordinator->SavePageLater(params);
+
+  coordinator->SavePageLater(
+      params, base::Bind(&SavePageLaterCallback, j_callback_ref));
 }
 
 ScopedJavaLocalRef<jstring> OfflinePageBridge::GetOfflinePageHeaderForReload(
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h
index 42c84e4..9f0c12034 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.h
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -113,6 +113,7 @@
 
   void SavePageLater(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& obj,
+                     const base::android::JavaParamRef<jobject>& j_callback_obj,
                      const base::android::JavaParamRef<jstring>& url,
                      const base::android::JavaParamRef<jstring>& j_namespace,
                      const base::android::JavaParamRef<jstring>& j_client_id,
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper.cc b/chrome/browser/offline_pages/offline_page_tab_helper.cc
index 9482220..ed894de 100644
--- a/chrome/browser/offline_pages/offline_page_tab_helper.cc
+++ b/chrome/browser/offline_pages/offline_page_tab_helper.cc
@@ -41,6 +41,10 @@
 #endif
   return url.SchemeIsFile();
 }
+
+void SavePageLaterCallback(AddRequestResult result) {
+  // do nothing.
+}
 }  // namespace
 
 OfflinePageTabHelper::LoadedOfflinePageInfo::LoadedOfflinePageInfo()
@@ -379,7 +383,8 @@
   params.url = url;
   params.client_id = offline_pages::ClientId(name_space, base::GenerateGUID());
   params.request_origin = request_origin;
-  request_coordinator->SavePageLater(params);
+  request_coordinator->SavePageLater(params,
+                                     base::Bind(&SavePageLaterCallback));
 
   if (static_cast<int>(ui_action) &
       static_cast<int>(OfflinePageUtils::DownloadUIActionFlags::
diff --git a/chrome/browser/offline_pages/offline_page_utils_unittest.cc b/chrome/browser/offline_pages/offline_page_utils_unittest.cc
index 4b44c60..8487a614 100644
--- a/chrome/browser/offline_pages/offline_page_utils_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_utils_unittest.cc
@@ -68,6 +68,8 @@
   *out_requests = std::move(requests);
 }
 
+void SavePageLaterCallback(AddRequestResult ignored) {}
+
 }  // namespace
 
 class OfflinePageUtilsTest
@@ -215,7 +217,8 @@
   params.url = kTestPage3Url;
   params.client_id =
       offline_pages::ClientId(kDownloadNamespace, kTestPage3ClientId);
-  request_coordinator->SavePageLater(params);
+  request_coordinator->SavePageLater(params,
+                                     base::Bind(&SavePageLaterCallback));
   RunUntilIdle();
 }
 
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
index 2d0d21ee..66cdf001 100644
--- a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
+++ b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
@@ -17,7 +17,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/safe_browsing/db/test_database_manager.h"
 
 namespace {
@@ -144,14 +143,6 @@
 
   base::SimpleTestClock* clock() { return clock_; }
 
-  const char* GetDismissKey() {
-    return PermissionDecisionAutoBlocker::kPromptDismissCountKey;
-  }
-
-  const char* GetIgnoreKey() {
-    return PermissionDecisionAutoBlocker::kPromptIgnoreCountKey;
-  }
-
  private:
   PermissionDecisionAutoBlocker* autoblocker_;
   base::test::ScopedFeatureList feature_list_;
@@ -806,78 +797,6 @@
   EXPECT_EQ(PermissionStatusSource::SAFE_BROWSING_BLACKLIST, result.source);
 }
 
-// TODO(raymes): See crbug.com/681709. Remove after M60.
-TEST_F(PermissionDecisionAutoBlockerUnitTest,
-       MigrateNoDecisionCountToPermissionAutoBlockerData) {
-  GURL url("https://www.google.com");
-  auto* map = HostContentSettingsMapFactory::GetForProfile(profile());
-
-  // Write to the old content setting.
-  base::DictionaryValue permissions_dict;
-  permissions_dict.SetInteger(GetDismissKey(), 100);
-  permissions_dict.SetInteger(GetIgnoreKey(), 50);
-
-  base::DictionaryValue origin_dict;
-  origin_dict.Set(
-      PermissionUtil::GetPermissionString(CONTENT_SETTINGS_TYPE_GEOLOCATION),
-      permissions_dict.CreateDeepCopy());
-  map->SetWebsiteSettingDefaultScope(
-      url, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
-      std::string(), origin_dict.CreateDeepCopy());
-
-  // Nothing should be migrated yet, so the current values should be 0.
-  EXPECT_EQ(0, autoblocker()->GetDismissCount(
-                   url, CONTENT_SETTINGS_TYPE_GEOLOCATION));
-  EXPECT_EQ(
-      0, autoblocker()->GetIgnoreCount(url, CONTENT_SETTINGS_TYPE_GEOLOCATION));
-
-  // Trigger pref migration which happens at the creation of the
-  // HostContentSettingsMap.
-  {
-    scoped_refptr<HostContentSettingsMap> temp_map(new HostContentSettingsMap(
-        profile()->GetPrefs(), false /* is_incognito_profile */,
-        false /* is_guest_profile */, false /* store_last_modified */));
-    temp_map->ShutdownOnUIThread();
-  }
-
-  // The values should now be migrated.
-  EXPECT_EQ(100, autoblocker()->GetDismissCount(
-                     url, CONTENT_SETTINGS_TYPE_GEOLOCATION));
-  EXPECT_EQ(50, autoblocker()->GetIgnoreCount(
-                    url, CONTENT_SETTINGS_TYPE_GEOLOCATION));
-
-  // The old pref should be deleted.
-  std::unique_ptr<base::DictionaryValue> old_dict =
-      base::DictionaryValue::From(map->GetWebsiteSetting(
-          url, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
-          std::string(), nullptr));
-  EXPECT_EQ(nullptr, old_dict);
-
-  // Write to the old content setting again, but with different numbers.
-  permissions_dict.SetInteger(GetDismissKey(), 99);
-  permissions_dict.SetInteger(GetIgnoreKey(), 99);
-
-  origin_dict.Set(
-      PermissionUtil::GetPermissionString(CONTENT_SETTINGS_TYPE_GEOLOCATION),
-      permissions_dict.CreateDeepCopy());
-  map->SetWebsiteSettingDefaultScope(
-      url, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
-      std::string(), origin_dict.CreateDeepCopy());
-
-  // Ensure that migrating again does nothing.
-  {
-    scoped_refptr<HostContentSettingsMap> temp_map(new HostContentSettingsMap(
-        profile()->GetPrefs(), false /* is_incognito_profile */,
-        false /* is_guest_profile */, false /* store_last_modified */));
-    temp_map->ShutdownOnUIThread();
-  }
-
-  EXPECT_EQ(100, autoblocker()->GetDismissCount(
-                     url, CONTENT_SETTINGS_TYPE_GEOLOCATION));
-  EXPECT_EQ(50, autoblocker()->GetIgnoreCount(
-                    url, CONTENT_SETTINGS_TYPE_GEOLOCATION));
-}
-
 // Test that a blacklisted permission should not be autoblocked if the database
 // manager is disabled.
 TEST_F(PermissionDecisionAutoBlockerUnitTest, TestDisabledDatabaseManager) {
diff --git a/chrome/browser/permissions/permission_request.h b/chrome/browser/permissions/permission_request.h
index f4473c3f..b093c8d 100644
--- a/chrome/browser/permissions/permission_request.h
+++ b/chrome/browser/permissions/permission_request.h
@@ -15,12 +15,16 @@
 }
 
 // Used for UMA to record the types of permission prompts shown.
-// This corresponds to the PermissionRequestType enum in
-// src/tools/metrics/histograms.xml. The usual rules of updating UMA values
-// applies to this enum:
+// When updating, you also need to update:
+//   1) The PermissionRequestType enum in tools/metrics/histograms/enums.xml.
+//   2) The PermissionRequestTypes suffix list in
+//      tools/metrics/histograms/histograms.xml.
+//   3) GetPermissionRequestString in
+//      chrome/browser/permissions/permission_uma_util.cc.
+//
+// The usual rules of updating UMA values applies to this enum:
 // - don't remove values
 // - only ever add values at the end
-// - keep the PermissionRequestType enum in sync with this definition.
 enum class PermissionRequestType {
   UNKNOWN = 0,
   MULTIPLE = 1,
@@ -39,6 +43,7 @@
   PERMISSION_MEDIASTREAM_CAMERA = 14,
   PERMISSION_ACCESSIBILITY_EVENTS = 15,
   PERMISSION_CLIPBOARD_READ = 16,
+  PERMISSION_SECURITY_KEY_ATTESTATION = 17,
   // NUM must be the last value in the enum.
   NUM
 };
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc
index 7c67292..962e035 100644
--- a/chrome/browser/permissions/permission_uma_util.cc
+++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -94,6 +94,8 @@
       return "VideoCapture";
     case PermissionRequestType::PERMISSION_CLIPBOARD_READ:
       return "ClipboardRead";
+    case PermissionRequestType::PERMISSION_SECURITY_KEY_ATTESTATION:
+      return "SecurityKeyAttestation";
     default:
       NOTREACHED();
       return "";
diff --git a/chrome/browser/resources/chromeos/login/login_shared.js b/chrome/browser/resources/chromeos/login/login_shared.js
index 222c12a..783ba693 100644
--- a/chrome/browser/resources/chromeos/login/login_shared.js
+++ b/chrome/browser/resources/chromeos/login/login_shared.js
@@ -52,6 +52,16 @@
   };
 
   /**
+   * Called when focus is returned from ash::SystemTray.
+   */
+  Oobe.focusReturned = function() {
+    if (Oobe.getInstance().currentScreen &&
+        Oobe.getInstance().currentScreen.onFocusReturned) {
+      Oobe.getInstance().currentScreen.onFocusReturned();
+    }
+  };
+
+  /**
    * Handle accelerators. These are passed from native code instead of a JS
    * event handler in order to make sure that embedded iframes cannot swallow
    * them.
diff --git a/chrome/browser/resources/chromeos/login/md_login_shared.js b/chrome/browser/resources/chromeos/login/md_login_shared.js
index 1725af7..d25a427 100644
--- a/chrome/browser/resources/chromeos/login/md_login_shared.js
+++ b/chrome/browser/resources/chromeos/login/md_login_shared.js
@@ -53,6 +53,16 @@
   };
 
   /**
+   * Called when focus is returned from ash::SystemTray.
+   */
+  Oobe.focusReturned = function() {
+    if (Oobe.getInstance().currentScreen &&
+        Oobe.getInstance().currentScreen.onFocusReturned) {
+      Oobe.getInstance().currentScreen.onFocusReturned();
+    }
+  };
+
+  /**
    * Handle accelerators. These are passed from native code instead of a JS
    * event handler in order to make sure that embedded iframes cannot swallow
    * them.
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
index 23c049b..1d616c99 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
@@ -347,5 +347,16 @@
           loadBundledEula);
       pendingLoad.start();
     },
+
+    /**
+     * Called when focus is returned.
+     */
+    onFocusReturned: function() {
+      if ($('oobe-eula') && !$('oobe-eula').hidden) {
+        $('oobe-eula').focus();
+      } else if ($('oobe-eula-md') && !$('oobe-eula-md').hidden) {
+        $('oobe-eula-md').focus();
+      }
+    },
   };
 });
diff --git a/chrome/browser/resources/cryptotoken/enroller.js b/chrome/browser/resources/cryptotoken/enroller.js
index 2df919f..9b13492 100644
--- a/chrome/browser/resources/cryptotoken/enroller.js
+++ b/chrome/browser/resources/cryptotoken/enroller.js
@@ -362,6 +362,29 @@
     sendResponseOnce(sentResponse, closeable, response, sendResponse);
   }
 
+  async function getRegistrationData(
+      appId, enrollChallenge, registrationData, opt_clientData) {
+    var isDirect = true;
+
+    if (conveyancePreference(enrollChallenge) == ConveyancePreference.NONE) {
+      isDirect = false;
+    } else if (chrome.cryptotokenPrivate != null) {
+      isDirect = await(new Promise((resolve, reject) => {
+        chrome.cryptotokenPrivate.canAppIdGetAttestation(
+            {'appId': appId, 'tabId': messageSender.tab.id}, resolve);
+      }));
+    }
+
+    if (isDirect) {
+      return registrationData;
+    }
+
+    const reg = new Registration(registrationData, appId, opt_clientData);
+    const keypair = await makeCertAndKey(reg.certificate);
+    const signature = await reg.sign(keypair.privateKey);
+    return reg.withReplacement(keypair.certDER, signature);
+  }
+
   /**
    * @param {string} u2fVersion
    * @param {string} registrationData Registration data, base64
@@ -381,31 +404,21 @@
       appId = enrollChallenge['appId'];
     }
 
-    var promise = Promise.resolve(registrationData);
-    switch (conveyancePreference(enrollChallenge)) {
-      case ConveyancePreference.NONE: {
-        console.log('randomizing attestation certificate');
-        promise = new Promise(async function(resolve, reject) {
-          const reg = new Registration(registrationData, appId, opt_clientData);
-          const keypair = await makeCertAndKey(reg.certificate);
-          const signature = await reg.sign(keypair.privateKey);
-          resolve(reg.withReplacement(keypair.certDER, signature));
-        });
-        break;
-      }
-    }
-
-    promise.then(
-        (registrationData) => {
-          var responseData = makeEnrollResponseData(
-              enrollChallenge, u2fVersion, registrationData, opt_clientData);
-          var response = makeU2fSuccessResponse(request, responseData);
-          sendResponseOnce(sentResponse, closeable, response, sendResponse);
-        },
-        (err) => {
-          console.warn('attestation certificate replacement failed: ' + err);
-          sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
-        });
+    getRegistrationData(
+        appId, enrollChallenge, registrationData, opt_clientData)
+        .then(
+            (registrationData) => {
+              var responseData = makeEnrollResponseData(
+                  enrollChallenge, u2fVersion, registrationData,
+                  opt_clientData);
+              var response = makeU2fSuccessResponse(request, responseData);
+              sendResponseOnce(sentResponse, closeable, response, sendResponse);
+            },
+            (err) => {
+              console.warn(
+                  'attestation certificate replacement failed: ' + err);
+              sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
+            });
   }
 
   function timeout() {
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js
index 87f53af..b6a7865 100644
--- a/chrome/browser/resources/interventions_internals/index.js
+++ b/chrome/browser/resources/interventions_internals/index.js
@@ -119,11 +119,12 @@
   let rows = $('message-logs-table').rows;
   for (let i = 1; i < rows.length; i++) {
     if (rows[i].className.includes('expansion-row')) {
-      rows[i].className = expand ? rows[i].className.replace('hide', 'show') :
-                                   rows[i].className.replace('show', 'hide');
+      rows[i].className = expanding ?
+          rows[i].className.replace('hide', 'show') :
+          rows[i].className.replace('show', 'hide');
       let arrowButton = rows[i - 1].querySelector('.arrow');
       if (arrowButton) {
-        arrowButton.className = expand ? 'arrow up' : 'arrow down';
+        arrowButton.className = expanding ? 'arrow up' : 'arrow down';
       }
     }
   }
@@ -278,6 +279,23 @@
 }
 
 /**
+ * Helper function to check if all keywords, case insensitive, are in the given
+ * text.
+ *
+ * @param {string[]} keywords The collection of keywords.
+ * @param {string} text The given text to search.
+ * @return True iff all keywords present in the given text.
+ */
+function checkTextContainsKeywords(keywords, text) {
+  for (let i = 0; i < keywords.length; i++) {
+    if (!text.toUpperCase().includes(keywords[i].toUpperCase())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
  * Initialize the navigation bar, and setup OnChange listeners for the tabs.
  */
 function setupTabControl() {
@@ -303,19 +321,21 @@
  */
 function setupLogSearch() {
   $('log-search-bar').addEventListener('keyup', () => {
-    let keyword = $('log-search-bar').value.toUpperCase();
+    let keys = $('log-search-bar').value.split(' ');
     let rows = $('message-logs-table').rows;
     logExpansionHelper(true /* expanding */);
 
     for (let i = 1; i < rows.length; i++) {
+      // Check the main row.
       rows[i].style.display =
-          rows[i].textContent.toUpperCase().includes(keyword) ? '' : 'none';
+          checkTextContainsKeywords(keys, rows[i].textContent) ? '' : 'none';
 
+      // Check expandable rows.
       let subtable = rows[i].querySelector('.expansion-logs-table');
       if (subtable) {
         for (let i = 0; i < subtable.rows.length; i++) {
           subtable.rows[i].style.display =
-              subtable.rows[i].textContent.toUpperCase().includes(keyword) ?
+              checkTextContainsKeywords(keys, subtable.rows[i].textContent) ?
               '' :
               'none';
         }
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index a917539..3678154 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -16,6 +16,17 @@
   --logo-margin-top: 56px; /* Expected OGB height, so logo doesn't overlap. */
   --logo-margin-bottom: 29px; /* Between logo and fakebox. */
 
+  /* Initial height determines the margin between the logo and the fakebox. If
+   * the iframe height exceeds the normal --logo-height, the difference is
+   * subtracted from the margin. The actual --logo-iframe-{width,height} can be
+   * changed later, but the initial height, and therefore the margin, remains
+   * the same.
+   */
+  --logo-iframe-initial-height: var(--logo-height);
+  --logo-iframe-height: var(--logo-iframe-initial-height);
+  --logo-iframe-resize-duration: 150ms;
+  --logo-iframe-width: 500px;
+
   --tile-height: 128px;
   --tile-margin: 16px;
   --tile-width: 154px;
@@ -180,9 +191,12 @@
 
 #logo-doodle-iframe {
   border: 0;
-  height: var(--logo-height);
-  margin: 0 auto var(--logo-margin-bottom) auto;
-  width: var(--content-width);
+  height: var(--logo-iframe-height);
+  margin: 0 auto calc(var(--logo-height) + var(--logo-margin-bottom)
+                      - var(--logo-iframe-initial-height)) auto;
+  transition: width var(--logo-iframe-resize-duration),
+              height var(--logo-iframe-resize-duration);
+  width: var(--logo-iframe-width);
 }
 
 #logo-doodle-notifier {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index d3c5726..70a48da 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -568,9 +568,9 @@
     let height = args.height || null;
     let duration = args.duration || '0s';
     let iframe = $(IDS.LOGO_DOODLE_IFRAME);
-    iframe.style.transition = 'width ' + duration + ', height ' + duration;
-    iframe.style.width = width;
-    iframe.style.height = height;
+    document.body.style.setProperty('--logo-iframe-height', height);
+    document.body.style.setProperty('--logo-iframe-width', width);
+    document.body.style.setProperty('--logo-iframe-resize-duration', duration);
   }
 }
 
@@ -974,6 +974,7 @@
   switch (metadata.type) {
     case LOGO_TYPE.SIMPLE:
       logoDoodleImage.title = metadata.altText;
+
       logoDoodleButton.onclick = function() {
         ntpApiHandle.logEvent(LOG_TYPE.NTP_STATIC_LOGO_CLICKED);
         window.location = metadata.onClickUrl;
@@ -982,6 +983,7 @@
 
     case LOGO_TYPE.ANIMATED:
       logoDoodleImage.title = metadata.altText;
+
       logoDoodleButton.onclick = function(e) {
         ntpApiHandle.logEvent(LOG_TYPE.NTP_CTA_LOGO_CLICKED);
         e.preventDefault();
@@ -996,6 +998,8 @@
     case LOGO_TYPE.INTERACTIVE:
       logoDoodleIframe.title = metadata.altText;
       logoDoodleIframe.src = metadata.fullPageUrl;
+      document.body.style.setProperty(
+          '--logo-iframe-initial-height', metadata.iframeHeightPx + 'px');
       break;
   }
 };
diff --git a/chrome/browser/resources/print_preview/data/cloud_parsers.js b/chrome/browser/resources/print_preview/data/cloud_parsers.js
index 8d8f043..56f16be2 100644
--- a/chrome/browser/resources/print_preview/data/cloud_parsers.js
+++ b/chrome/browser/resources/print_preview/data/cloud_parsers.js
@@ -33,6 +33,12 @@
   const OWNED_TAG = '^own';
 
   /**
+   * Tag that denotes whether the printer passes the 2018 certificate.
+   * @const {string}
+   */
+  const CERT_TAG = '__cp_printer_passes_2018_cert__=';
+
+  /**
    * Enumeration of cloud destination types that are supported by print preview.
    * @enum {string}
    */
@@ -61,6 +67,26 @@
   }
 
   /**
+   * @param {!Array<string>} tags The array of tag strings sent by GCP server.
+   * @return {!print_preview.DestinationCertificateStatus} The certificate
+   *     status indicated by the tag. Returns NONE if certificate tag is not
+   *     found.
+   */
+  function extractCertificateStatus(tags) {
+    const certTag = tags.find(tag => tag.startsWith(CERT_TAG));
+    if (!certTag)
+      return print_preview.DestinationCertificateStatus.NONE;
+    const value = /** @type {print_preview.DestinationCertificateStatus} */ (
+        certTag.substring(CERT_TAG.length));
+    // Only 2 valid values sent by GCP server.
+    assert(
+        value == print_preview.DestinationCertificateStatus.UNKNOWN ||
+        value == print_preview.DestinationCertificateStatus.YES ||
+        value == print_preview.DestinationCertificateStatus.NO);
+    return value;
+  }
+
+  /**
    * Parses a destination from JSON from a Google Cloud Print search or printer
    * response.
    * @param {!Object} json Object that represents a Google Cloud Print search or
@@ -88,7 +114,8 @@
       lastAccessTime:
           parseInt(json[CloudDestinationField.LAST_ACCESS], 10) || Date.now(),
       cloudID: id,
-      description: json[CloudDestinationField.DESCRIPTION]
+      description: json[CloudDestinationField.DESCRIPTION],
+      certificateStatus: extractCertificateStatus(tags),
     };
     const cloudDest = new print_preview.Destination(
         id, parseType(json[CloudDestinationField.TYPE]), origin,
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index f79772f5..46f97789 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -46,16 +46,31 @@
  * @enum {string}
  */
 print_preview.DestinationProvisionalType = {
-  /** Destination is not provisional. */
+  // Destination is not provisional.
   NONE: 'NONE',
-  /**
-   * User has to grant USB access for the destination to its provider.
-   * Used for destinations with extension origin.
-   */
+  // User has to grant USB access for the destination to its provider.
+  // Used for destinations with extension origin.
   NEEDS_USB_PERMISSION: 'NEEDS_USB_PERMISSION'
 };
 
 /**
+ * Enumeration specifying the status of a destination's 2018 certificate.
+ * Values UNKNOWN and YES are returned directly by the GCP server.
+ * @enum {string}
+ */
+print_preview.DestinationCertificateStatus = {
+  // Destination is not a cloud printer or no status was retrieved.
+  NONE: 'NONE',
+  // Printer does not have a valid 2018 certificate. Currently unused, to be
+  // sent by GCP server.
+  NO: 'NO',
+  // Printer may or may not have a valid certificate. Sent by GCP server.
+  UNKNOWN: 'UNKNOWN',
+  // Printer has a valid 2018 certificate. Sent by GCP server.
+  YES: 'YES'
+};
+
+/**
  * Capabilities of a print destination represented in a CDD.
  *
  * @typedef {{
@@ -171,7 +186,10 @@
      *              (print_preview.DestinationProvisionalType|undefined),
      *          extensionId: (string|undefined),
      *          extensionName: (string|undefined),
-     *          description: (string|undefined)}=} opt_params Optional
+     *          description: (string|undefined),
+     *          certificateStatus:
+     *              (print_preview.DestinationCertificateStatus|undefined)
+     *         }=} opt_params Optional
      *     parameters for the destination.
      */
     constructor(
@@ -294,6 +312,13 @@
       this.provisionalType_ = (opt_params && opt_params.provisionalType) ||
           print_preview.DestinationProvisionalType.NONE;
 
+      /**
+       * Printer 2018 certificate status
+       * @private {print_preview.DestinationCertificateStatus}
+       */
+      this.certificateStatus_ = opt_params && opt_params.certificateStatus ||
+          print_preview.DestinationCertificateStatus.NONE;
+
       assert(
           this.provisionalType_ !=
                   print_preview.DestinationProvisionalType
@@ -481,6 +506,26 @@
       this.connectionStatus_ = status;
     }
 
+    /**
+     * @return {boolean} Whether the destination has an invalid 2018
+     *     certificate.
+     */
+    get hasInvalidCertificate() {
+      return this.certificateStatus_ ==
+          print_preview.DestinationCertificateStatus.NO;
+    }
+
+    /**
+     * @return {boolean} Whether the destination should display an invalid
+     *     certificate UI warning in the selection dialog and cause a UI
+     *     warning to appear in the preview area when selected.
+     */
+    get shouldShowInvalidCertificateError() {
+      return this.certificateStatus_ ==
+          print_preview.DestinationCertificateStatus.NO &&
+          !loadTimeData.getBoolean('isEnterpriseManaged');
+    }
+
     /** @return {boolean} Whether the destination is considered offline. */
     get isOffline() {
       return arrayContains(
@@ -491,23 +536,26 @@
           this.connectionStatus_);
     }
 
-    /** @return {string} Human readable status for offline destination. */
-    get offlineStatusText() {
-      if (!this.isOffline) {
+    /**
+     * @return {string} Human readable status for a destination that is offline
+     *     or has a bad certificate. */
+    get connectionStatusText() {
+      if (!this.isOffline && !this.shouldShowInvalidCertificateError)
         return '';
-      }
       const offlineDurationMs = Date.now() - this.lastAccessTime_;
-      let offlineMessageId;
-      if (offlineDurationMs > 31622400000.0) {  // One year.
-        offlineMessageId = 'offlineForYear';
+      let statusMessageId;
+      if (this.shouldShowInvalidCertificateError) {
+        statusMessageId = 'noLongerSupported';
+      } else if (offlineDurationMs > 31622400000.0) {  // One year.
+        statusMessageId = 'offlineForYear';
       } else if (offlineDurationMs > 2678400000.0) {  // One month.
-        offlineMessageId = 'offlineForMonth';
+        statusMessageId = 'offlineForMonth';
       } else if (offlineDurationMs > 604800000.0) {  // One week.
-        offlineMessageId = 'offlineForWeek';
+        statusMessageId = 'offlineForWeek';
       } else {
-        offlineMessageId = 'offline';
+        statusMessageId = 'offline';
       }
-      return loadTimeData.getString(offlineMessageId);
+      return loadTimeData.getString(statusMessageId);
     }
 
     /**
@@ -593,6 +641,14 @@
     }
 
     /**
+     * Gets the destination's certificate status.
+     * @return {print_preview.DestinationCertificateStatus}
+     */
+    get certificateStatus() {
+      return this.certificateStatus_;
+    }
+
+    /**
      * Whether the destinaion is provisional.
      * @return {boolean}
      */
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index aa204aa..975c687 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -727,9 +727,7 @@
               destination.id, destination.origin, destination.account);
         }
       } else {
-        cr.dispatchSimpleEvent(
-            this,
-            DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
+        this.sendSelectedDestinationUpdateEvent_();
       }
     }
 
@@ -984,6 +982,20 @@
     }
 
     /**
+     * Sends SELECTED_DESTINATION_CAPABILITIES_READY event if the destination
+     * is supported, or SELECTED_DESTINATION_UNSUPPORTED otherwise.
+     * @private
+     */
+    sendSelectedDestinationUpdateEvent_() {
+      cr.dispatchSimpleEvent(
+          this,
+          this.selectedDestination_.shouldShowInvalidCertificateError ?
+              DestinationStore.EventType.SELECTED_DESTINATION_UNSUPPORTED :
+              DestinationStore.EventType
+                  .SELECTED_DESTINATION_CAPABILITIES_READY);
+    }
+
+    /**
      * Updates an existing print destination with capabilities and display name
      * information. If the destination doesn't already exist, it will be added.
      * @param {!print_preview.Destination} destination Destination to update.
@@ -1008,9 +1020,7 @@
       if (this.selectedDestination_ &&
           (existingDestination == this.selectedDestination_ ||
            destination == this.selectedDestination_)) {
-        cr.dispatchSimpleEvent(
-            this,
-            DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);
+        this.sendSelectedDestinationUpdateEvent_();
       }
     }
 
@@ -1334,6 +1344,8 @@
         '.SELECTED_DESTINATION_CAPABILITIES_READY',
     SELECTED_DESTINATION_INVALID:
         'print_preview.DestinationStore.SELECTED_DESTINATION_INVALID',
+    SELECTED_DESTINATION_UNSUPPORTED:
+        'print_preview.DestinationStore.SELECTED_DESTINATION_UNSUPPORTED',
   };
 
   /**
diff --git a/chrome/browser/resources/print_preview/new/destination_settings.html b/chrome/browser/resources/print_preview/new/destination_settings.html
index 03eb8c37..69f1f01 100644
--- a/chrome/browser/resources/print_preview/new/destination_settings.html
+++ b/chrome/browser/resources/print_preview/new/destination_settings.html
@@ -71,8 +71,8 @@
           <div class="destination-info-wrapper">
             <div class="destination-name">[[destination.id]]</div>
             <div class="destination-location">[[destination.hint]]</div>
-            <div class="destination-offline-status">
-                [[destination.offlineStatusText]]</div>
+            <div class="destination-connection-status">
+                [[destination.connectionStatusText]]</div>
           </div>
         </div>
         <button>$i18n{changeDestination}</button>
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.css b/chrome/browser/resources/print_preview/previewarea/preview_area.css
index f54fe8ae..c44d8a5 100644
--- a/chrome/browser/resources/print_preview/previewarea/preview_area.css
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.css
@@ -75,6 +75,11 @@
   margin-top: 12px;
 }
 
+#preview-area .learn-more-link {
+  -webkit-margin-start: 0.5em;
+  color: rgb(51, 103, 214);
+}
+
 #preview-area .preview-area-open-system-dialog-button-throbber {
   vertical-align: middle;
 }
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.html b/chrome/browser/resources/print_preview/previewarea/preview_area.html
index eec995c..c02a2db7 100644
--- a/chrome/browser/resources/print_preview/previewarea/preview_area.html
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.html
@@ -8,6 +8,12 @@
             ><span>.</span><span>.</span><span>.</span></span>
       </div>
 
+      <div class="preview-area-unsupported-cloud-printer preview-area-message"
+          hidden>
+        <span>$i18n{unsupportedCloudPrinter}</span>
+        <a is="action-link" class="learn-more-link">$i18n{learnMore}</a>
+      </div>
+
       <div class="preview-area-custom-message preview-area-message" hidden>
         <div class="preview-area-custom-message-text"></div>
         <div class="preview-area-custom-action-area">
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js
index 09456592..d1cb9de 100644
--- a/chrome/browser/resources/print_preview/previewarea/preview_area.js
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -11,6 +11,7 @@
  */
 print_preview.PreviewAreaMessageId_ = {
   CUSTOM: 'custom',
+  UNSUPPORTED: 'unsupported-cloud-printer',
   LOADING: 'loading',
   PREVIEW_FAILED: 'preview-failed'
 };
@@ -223,6 +224,9 @@
   PreviewArea.MessageIdClassMap_ = {};
   PreviewArea.MessageIdClassMap_[print_preview.PreviewAreaMessageId_.CUSTOM] =
       'preview-area-custom-message';
+  PreviewArea
+      .MessageIdClassMap_[print_preview.PreviewAreaMessageId_.UNSUPPORTED] =
+      'preview-area-unsupported-cloud-printer';
   PreviewArea.MessageIdClassMap_[print_preview.PreviewAreaMessageId_.LOADING] =
       'preview-area-loading-message';
   PreviewArea
@@ -302,6 +306,14 @@
     },
 
     /**
+     * Shows the unsupported cloud printer message on the preview area's
+     * overlay.
+     */
+    showUnsupportedCloudPrinterMessage: function() {
+      this.showMessage_(print_preview.PreviewAreaMessageId_.UNSUPPORTED);
+    },
+
+    /**
      * Shows a custom message on the preview area's overlay.
      * @param {string} message Custom message to show.
      */
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index eb534d9..0a8f1d3 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -395,6 +395,11 @@
           this.onSelectedDestinationInvalid_.bind(this));
       this.tracker.add(
           this.destinationStore_,
+          print_preview.DestinationStore.EventType
+              .SELECTED_DESTINATION_UNSUPPORTED,
+          this.onSelectedDestinationUnsupported_.bind(this));
+      this.tracker.add(
+          this.destinationStore_,
           print_preview.DestinationStore.EventType.DESTINATION_SELECT,
           this.onDestinationSelect_.bind(this));
 
@@ -992,6 +997,16 @@
     },
 
     /**
+     * Called when the destination store has selected an unsupported cloud
+     * printer.
+     * @private
+     */
+    onSelectedDestinationUnsupported_: function() {
+      this.previewArea_.showUnsupportedCloudPrinterMessage();
+      this.onSettingsInvalid_();
+    },
+
+    /**
      * Called when the destination store fails to fetch capabilities for the
      * selected printer.
      * @private
diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.css b/chrome/browser/resources/print_preview/search/destination_list_item.css
index 02f1cf4..3f07a54c 100644
--- a/chrome/browser/resources/print_preview/search/destination_list_item.css
+++ b/chrome/browser/resources/print_preview/search/destination_list_item.css
@@ -56,7 +56,8 @@
   font-size: 75%;
 }
 
-.destination-list-item .offline-status {
+.destination-list-item .connection-status,
+.destination-list-item .learn-more-link {
   -webkit-margin-start: 1em;
   flex: 0 0 auto;
   font-size: 75%;
@@ -64,6 +65,10 @@
   vertical-align: middle;
 }
 
+.destination-list-item .learn-more-link {
+  color: rgb(51, 103, 214);
+}
+
 .register-promo {
   -webkit-margin-start: 1em;
   flex: 0 0 auto;
diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.html b/chrome/browser/resources/print_preview/search/destination_list_item.html
index f77a404f..c540aff 100644
--- a/chrome/browser/resources/print_preview/search/destination_list_item.html
+++ b/chrome/browser/resources/print_preview/search/destination_list_item.html
@@ -3,7 +3,8 @@
   <span class="destination-list-item-content">
     <img class="destination-list-item-icon" alt="">
     <span class="destination-list-item-name"></span>
-    <span class="offline-status" hidden></span>
+    <span class="connection-status" hidden></span>
+    <a is="action-link" class="learn-more-link" hidden>$i18n{learnMore}</a>
     <span class="register-promo" hidden>
       <button class="register-promo-button">
         $i18n{registerPromoButtonText}
diff --git a/chrome/browser/resources/print_preview/search/destination_list_item.js b/chrome/browser/resources/print_preview/search/destination_list_item.js
index f85e0af..c6ef0c7 100644
--- a/chrome/browser/resources/print_preview/search/destination_list_item.js
+++ b/chrome/browser/resources/print_preview/search/destination_list_item.js
@@ -196,11 +196,21 @@
           this.getChildElement('.extension-controlled-indicator');
       setIsVisible(extensionIndicatorEl, this.destination_.isExtension);
 
-      // Initialize the element which renders the destination's offline status.
-      this.getElement().classList.toggle('stale', this.destination_.isOffline);
-      const offlineStatusEl = this.getChildElement('.offline-status');
-      offlineStatusEl.textContent = this.destination_.offlineStatusText;
-      setIsVisible(offlineStatusEl, this.destination_.isOffline);
+      // Initialize the element which renders the destination's connection
+      // status.
+      this.getElement().classList.toggle(
+          'stale',
+          this.destination_.isOffline ||
+              this.destination_.shouldShowInvalidCertificateError);
+      const connectionStatusEl = this.getChildElement('.connection-status');
+      connectionStatusEl.textContent = this.destination_.connectionStatusText;
+      setIsVisible(
+          connectionStatusEl,
+          this.destination_.isOffline ||
+              this.destination_.shouldShowInvalidCertificateError);
+      setIsVisible(
+          this.getChildElement('.learn-more-link'),
+          this.destination_.shouldShowInvalidCertificateError);
 
       // Initialize registration promo element for Privet unregistered printers.
       setIsVisible(
diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.html b/chrome/browser/resources/print_preview/settings/destination_settings.html
index 3115735..e4ac358 100644
--- a/chrome/browser/resources/print_preview/settings/destination_settings.html
+++ b/chrome/browser/resources/print_preview/settings/destination_settings.html
@@ -15,7 +15,7 @@
         <div class="destination-settings-info">
           <div><div class="destination-settings-name"></div></div>
           <div><div class="destination-settings-location"></div></div>
-          <div><div class="destination-settings-offline-status"></div></div>
+          <div><div class="destination-settings-connection-status"></div></div>
         </div>
       </div>
     </div>
diff --git a/chrome/browser/resources/print_preview/settings/destination_settings.js b/chrome/browser/resources/print_preview/settings/destination_settings.js
index 631df0d..f806180 100644
--- a/chrome/browser/resources/print_preview/settings/destination_settings.js
+++ b/chrome/browser/resources/print_preview/settings/destination_settings.js
@@ -139,17 +139,20 @@
         locationEl.textContent = hint;
         locationEl.title = hint;
 
-        const offlineStatusText = destination.offlineStatusText;
-        const offlineStatusEl =
-            this.getChildElement('.destination-settings-offline-status');
-        offlineStatusEl.textContent = offlineStatusText;
-        offlineStatusEl.title = offlineStatusText;
+        const connectionStatusText = destination.connectionStatusText;
+        const connectionStatusEl =
+            this.getChildElement('.destination-settings-connection-status');
+        connectionStatusEl.textContent = connectionStatusText;
+        connectionStatusEl.title = connectionStatusText;
 
-        const isOffline = destination.isOffline;
+        const hasConnectionError = destination.isOffline ||
+            (destination.hasInvalidCertificate &&
+             !loadTimeData.getBoolean('isEnterpriseManaged'));
         destinationSettingsBoxEl.classList.toggle(
-            print_preview.DestinationSettingsClasses_.STALE, isOffline);
-        setIsVisible(locationEl, !isOffline);
-        setIsVisible(offlineStatusEl, isOffline);
+            print_preview.DestinationSettingsClasses_.STALE,
+            hasConnectionError);
+        setIsVisible(locationEl, !hasConnectionError);
+        setIsVisible(connectionStatusEl, hasConnectionError);
       }
 
       setIsVisible(
diff --git a/chrome/browser/search/README.md b/chrome/browser/search/README.md
index bb545d2..72dcc97 100644
--- a/chrome/browser/search/README.md
+++ b/chrome/browser/search/README.md
@@ -92,13 +92,11 @@
 parameters:
 
 *   `cmd` (required string): must be `"resizeDoodle"`.
-*   `width` (optional string): a CSS width (with units) or `null`.
-    Because the Doodle cannot know the size of the outer page, only
-    `null` (default width) or values based on `"100%"` (`"100%"`,
-    `"calc(100% - 50px)"`) are recommended.
-*   `height` (optional string): a CSS height (with units) or `null` for
-    the default (`"200px"`). Must not be a percentage, but otherwise any
-    units are OK.
+*   `width` (required string): a CSS width (with units). Because the
+    Doodle cannot know the size of the outer page, values based on
+    `"100%"` (e.g. `"100%"` or `"calc(100% - 50px)"`) are recommended.
+*   `height` (required string): a CSS height (with units). Must not be a
+    percentage, but otherwise any units are OK.
 *   `duration` (optional string): a CSS duration, such as `"130ms"` or
     `"1s"`. If `null` or absent, `"0s"` (no transition) is assumed.
 
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index daffb035..4b3981f 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -242,6 +242,8 @@
   result->SetString("altText", meta.alt_text);
   result->SetString("mimeType", meta.mime_type);
   result->SetString("animatedUrl", meta.animated_url.spec());
+  result->SetInteger("iframeWidthPx", meta.iframe_width_px);
+  result->SetInteger("iframeHeightPx", meta.iframe_height_px);
 
   GURL full_page_url = meta.full_page_url;
   if (base::GetFieldTrialParamByFeatureAsBool(
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index 4a996d5a..e431c7b 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -90,6 +90,7 @@
     const GURL& request_url,
     int options_mask,
     const base::Time& time_triggered,
+    const GURL& support_url,
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
     bool is_superfish,
     const base::Callback<void(content::CertificateRequestResultType)>&
@@ -100,7 +101,7 @@
   metrics_helper.get()->StartRecordingCaptivePortalMetrics(overridable);
 
   return new SSLBlockingPage(web_contents, cert_error, ssl_info, request_url,
-                             options_mask, time_triggered,
+                             options_mask, time_triggered, support_url,
                              std::move(ssl_cert_reporter), overridable,
                              std::move(metrics_helper), is_superfish, callback);
 }
@@ -136,6 +137,7 @@
     const GURL& request_url,
     int options_mask,
     const base::Time& time_triggered,
+    const GURL& support_url,
     std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
     bool overridable,
     std::unique_ptr<ChromeMetricsHelper> metrics_helper,
@@ -175,6 +177,7 @@
                                              ssl_info,
                                              options_mask,
                                              time_triggered,
+                                             support_url,
                                              controller())) {
   // Creating an interstitial without showing (e.g. from chrome://interstitials)
   // it leaks memory, so don't create it here.
diff --git a/chrome/browser/ssl/ssl_blocking_page.h b/chrome/browser/ssl/ssl_blocking_page.h
index e6bfd55..7425e04b 100644
--- a/chrome/browser/ssl/ssl_blocking_page.h
+++ b/chrome/browser/ssl/ssl_blocking_page.h
@@ -55,6 +55,7 @@
       const GURL& request_url,
       int options_mask,
       const base::Time& time_triggered,
+      const GURL& support_url,
       std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
       bool is_superfish,
       const base::Callback<void(content::CertificateRequestResultType)>&
@@ -82,6 +83,7 @@
       const GURL& request_url,
       int options_mask,
       const base::Time& time_triggered,
+      const GURL& support_url,
       std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
       bool overrideable,
       std::unique_ptr<ChromeMetricsHelper> metrics_helper,
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index ea33fc27..a288808 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/ssl/mitm_software_blocking_page.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ssl/ssl_blocking_page.h"
+#include "chrome/browser/ssl/ssl_error_assistant.h"
 #include "chrome/browser/ssl/ssl_error_assistant.pb.h"
 #include "chrome/browser/ssl/ssl_error_handler.h"
 #include "chrome/browser/ssl/ssl_error_tab_helper.h"
@@ -5197,7 +5198,8 @@
         net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
     return SSLBlockingPage::Create(
         contents, net::ERR_CERT_CONTAINS_ERRORS, ssl_info, request_url, 0,
-        base::Time::NowFromSystemTime(), nullptr, false /* is superfish */,
+        base::Time::NowFromSystemTime(), GURL(), nullptr,
+        false /* is superfish */,
         base::Callback<void(content::CertificateRequestResultType)>());
   }
 };
@@ -6837,6 +6839,223 @@
                 frame->GetProcess()->GetID(), frame->GetRoutingID()));
 }
 
+// This SPKI hash is from a self signed certificate generated using the
+// following openssl command:
+//  openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
+//  openssl x509 -noout -in certificate.pem -pubkey | \
+//  openssl asn1parse -noout -inform pem -out public.key;
+//  openssl dgst -sha256 -binary public.key | openssl enc -base64
+// The actual value of the hash doesn't matter as long it's a valid SPKI hash.
+const char kDynamicInterstitialCert[] =
+    "sha256/eFi0afYJLdI0YsZFu4U8ra2B5/5ynzfKkI88M94iVFA=";
+
+namespace {
+
+std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig>
+MakeDynamicInterstitial(const std::vector<DynamicInterstitialInfo>& list) {
+  auto config_proto =
+      base::MakeUnique<chrome_browser_ssl::SSLErrorAssistantConfig>();
+  config_proto->set_version_id(kLargeVersionId);
+
+  for (const DynamicInterstitialInfo& info : list) {
+    chrome_browser_ssl::DynamicInterstitial* filter =
+        config_proto->add_dynamic_interstitial();
+    filter->set_interstitial_type(info.interstitial_type);
+    filter->set_cert_error(
+        (chrome_browser_ssl::DynamicInterstitial_CertError)info.cert_error);
+
+    for (const std::string& hash : info.spki_hashes)
+      filter->add_sha256_hash(hash);
+  }
+
+  return config_proto;
+}
+
+class SSLUIDynamicInterstitialTest : public CertVerifierBrowserTest {
+ public:
+  SSLUIDynamicInterstitialTest()
+      : CertVerifierBrowserTest(),
+        https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+  ~SSLUIDynamicInterstitialTest() override {}
+
+  void SetUpCertVerifier() {
+    scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate());
+    net::CertVerifyResult verify_result;
+    verify_result.verified_cert = cert;
+    verify_result.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID;
+
+    net::HashValue hash;
+    ASSERT_TRUE(hash.FromString(kDynamicInterstitialCert));
+    verify_result.public_key_hashes.push_back(hash);
+
+    mock_cert_verifier()->AddResultForCert(cert, verify_result,
+                                           net::ERR_CERT_COMMON_NAME_INVALID);
+  }
+
+  net::EmbeddedTestServer* https_server() { return &https_server_; }
+
+ private:
+  net::EmbeddedTestServer https_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSLUIDynamicInterstitialTest);
+};
+
+}  // namespace
+
+// Tests that the dynamic interstitial list is used when the feature is
+// enabled via Finch. The list is passed to SSLErrorHandler via a proto.
+IN_PROC_BROWSER_TEST_F(SSLUIDynamicInterstitialTest, Match) {
+  ASSERT_TRUE(https_server()->Start());
+
+  SetUpCertVerifier();
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  {
+    std::vector<DynamicInterstitialInfo> list;
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{"sha256/kingfisher",
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL,
+        chrome_browser_ssl::DynamicInterstitial::ERR_CERT_COMMON_NAME_INVALID,
+        GURL()));
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{kDynamicInterstitialCert,
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::
+            INTERSTITIAL_PAGE_CAPTIVE_PORTAL,
+        0, GURL()));
+
+    SSLErrorHandler::SetErrorAssistantProto(MakeDynamicInterstitial(list));
+    ASSERT_TRUE(SSLErrorHandler::GetErrorAssistantProtoVersionIdForTesting() >
+                0);
+
+    SSLInterstitialTimerObserver interstitial_timer_observer(tab);
+    ui_test_utils::NavigateToURL(browser(), https_server()->GetURL("/"));
+    WaitForInterstitial(tab);
+
+    InterstitialPage* interstitial_page = tab->GetInterstitialPage();
+    ASSERT_TRUE(interstitial_page);
+    ASSERT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
+              interstitial_page->GetDelegateForTesting()->GetTypeForTesting());
+    interstitial_page->DontProceed();
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(SSLUIDynamicInterstitialTest, MatchUnknownCertError) {
+  ASSERT_TRUE(https_server()->Start());
+
+  SetUpCertVerifier();
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  {
+    std::vector<DynamicInterstitialInfo> list;
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{"sha256/kingfisher",
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL,
+        chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR, GURL()));
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{kDynamicInterstitialCert,
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::
+            INTERSTITIAL_PAGE_CAPTIVE_PORTAL,
+        chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR, GURL()));
+
+    SSLErrorHandler::SetErrorAssistantProto(MakeDynamicInterstitial(list));
+    ASSERT_TRUE(SSLErrorHandler::GetErrorAssistantProtoVersionIdForTesting() >
+                0);
+
+    SSLInterstitialTimerObserver interstitial_timer_observer(tab);
+    ui_test_utils::NavigateToURL(browser(), https_server()->GetURL("/"));
+    WaitForInterstitial(tab);
+
+    InterstitialPage* interstitial_page = tab->GetInterstitialPage();
+    ASSERT_TRUE(interstitial_page);
+    ASSERT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
+              interstitial_page->GetDelegateForTesting()->GetTypeForTesting());
+    interstitial_page->DontProceed();
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(SSLUIDynamicInterstitialTest, MismatchHash) {
+  ASSERT_TRUE(https_server()->Start());
+
+  SetUpCertVerifier();
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  {
+    // Dynamically update the SSL error assistant config without the dynamic
+    // interstitial SPKI hash.
+    std::vector<DynamicInterstitialInfo> list;
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{"sha256/kingfisher",
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::
+            INTERSTITIAL_PAGE_CAPTIVE_PORTAL,
+        chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR, GURL()));
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{"sha256/sapsucker"},
+        chrome_browser_ssl::DynamicInterstitial::
+            INTERSTITIAL_PAGE_CAPTIVE_PORTAL,
+        chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR, GURL()));
+
+    SSLErrorHandler::SetErrorAssistantProto(MakeDynamicInterstitial(list));
+    ASSERT_TRUE(SSLErrorHandler::GetErrorAssistantProtoVersionIdForTesting() >
+                0);
+
+    SSLInterstitialTimerObserver interstitial_timer_observer(tab);
+    ui_test_utils::NavigateToURL(browser(), https_server()->GetURL("/"));
+    WaitForInterstitial(tab);
+
+    InterstitialPage* interstitial_page = tab->GetInterstitialPage();
+    ASSERT_TRUE(interstitial_page);
+    EXPECT_NE(CaptivePortalBlockingPage::kTypeForTesting,
+              interstitial_page->GetDelegateForTesting()->GetTypeForTesting());
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(SSLUIDynamicInterstitialTest, MismatchCertError) {
+  ASSERT_TRUE(https_server()->Start());
+
+  SetUpCertVerifier();
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+
+  {
+    // Dynamically update the SSL error assistant config without the dynamic
+    // interstitial cert error.
+    std::vector<DynamicInterstitialInfo> list;
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{"sha256/kingfisher",
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL,
+        chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR, GURL()));
+    list.push_back(DynamicInterstitialInfo(
+        std::unordered_set<std::string>{kDynamicInterstitialCert,
+                                        "sha256/flycatcher"},
+        chrome_browser_ssl::DynamicInterstitial::
+            INTERSTITIAL_PAGE_CAPTIVE_PORTAL,
+        chrome_browser_ssl::DynamicInterstitial::ERR_CERT_AUTHORITY_INVALID,
+        GURL()));
+
+    SSLErrorHandler::SetErrorAssistantProto(MakeDynamicInterstitial(list));
+    ASSERT_TRUE(SSLErrorHandler::GetErrorAssistantProtoVersionIdForTesting() >
+                0);
+
+    SSLInterstitialTimerObserver interstitial_timer_observer(tab);
+    ui_test_utils::NavigateToURL(browser(), https_server()->GetURL("/"));
+    WaitForInterstitial(tab);
+
+    InterstitialPage* interstitial_page = tab->GetInterstitialPage();
+    ASSERT_TRUE(interstitial_page);
+    EXPECT_NE(CaptivePortalBlockingPage::kTypeForTesting,
+              interstitial_page->GetDelegateForTesting()->GetTypeForTesting());
+  }
+}
+
 // TODO(jcampan): more tests to do below.
 
 // Visit a page over https that contains a frame with a redirect.
diff --git a/chrome/browser/ssl/ssl_error_assistant.cc b/chrome/browser/ssl/ssl_error_assistant.cc
index ea2fc55..69a443e 100644
--- a/chrome/browser/ssl/ssl_error_assistant.cc
+++ b/chrome/browser/ssl/ssl_error_assistant.cc
@@ -7,7 +7,6 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "build/build_config.h"
-#include "chrome/browser/ssl/ssl_error_assistant.pb.h"
 #include "chrome/common/features.h"
 #include "chrome/grit/browser_resources.h"
 #include "content/public/browser/browser_thread.h"
@@ -18,6 +17,57 @@
 
 namespace {
 
+net::CertStatus MapToCertStatus(
+    chrome_browser_ssl::DynamicInterstitial::CertError error) {
+  switch (error) {
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_COMMON_NAME_INVALID:
+      return net::CERT_STATUS_COMMON_NAME_INVALID;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_DATE_INVALID:
+      return net::CERT_STATUS_DATE_INVALID;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_AUTHORITY_INVALID:
+      return net::CERT_STATUS_AUTHORITY_INVALID;
+    case chrome_browser_ssl::DynamicInterstitial::
+        ERR_CERT_NO_REVOCATION_MECHANISM:
+      return net::CERT_STATUS_NO_REVOCATION_MECHANISM;
+    case chrome_browser_ssl::DynamicInterstitial::
+        ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
+      return net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+    case chrome_browser_ssl::DynamicInterstitial::
+        ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
+      return net::CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_REVOKED:
+      return net::CERT_STATUS_REVOKED;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_INVALID:
+      return net::CERT_STATUS_INVALID;
+    case chrome_browser_ssl::DynamicInterstitial::
+        ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
+      return net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_NON_UNIQUE_NAME:
+      return net::CERT_STATUS_NON_UNIQUE_NAME;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_WEAK_KEY:
+      return net::CERT_STATUS_WEAK_KEY;
+    case chrome_browser_ssl::DynamicInterstitial::
+        ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
+      return net::CERT_STATUS_PINNED_KEY_MISSING;
+    case chrome_browser_ssl::DynamicInterstitial::
+        ERR_CERT_NAME_CONSTRAINT_VIOLATION:
+      return net::CERT_STATUS_NAME_CONSTRAINT_VIOLATION;
+    case chrome_browser_ssl::DynamicInterstitial::ERR_CERT_VALIDITY_TOO_LONG:
+      return net::CERT_STATUS_VALIDITY_TOO_LONG;
+    default:
+      return 0;
+  }
+}
+
+std::unordered_set<std::string> HashesFromDynamicInterstitial(
+    const chrome_browser_ssl::DynamicInterstitial& entry) {
+  std::unordered_set<std::string> hashes;
+  for (const std::string& hash : entry.sha256_hash())
+    hashes.insert(hash);
+
+  return hashes;
+}
+
 std::unique_ptr<std::unordered_set<std::string>> LoadCaptivePortalCertHashes(
     const chrome_browser_ssl::SSLErrorAssistantConfig& proto) {
   auto hashes = base::MakeUnique<std::unordered_set<std::string>>();
@@ -52,6 +102,21 @@
   return mitm_software_list;
 }
 
+std::unique_ptr<std::vector<DynamicInterstitialInfo>>
+LoadDynamicInterstitialList(
+    const chrome_browser_ssl::SSLErrorAssistantConfig& proto) {
+  auto dynamic_interstitial_list =
+      base::MakeUnique<std::vector<DynamicInterstitialInfo>>();
+  for (const chrome_browser_ssl::DynamicInterstitial& entry :
+       proto.dynamic_interstitial()) {
+    dynamic_interstitial_list.get()->push_back(DynamicInterstitialInfo(
+        HashesFromDynamicInterstitial(entry), entry.interstitial_type(),
+        MapToCertStatus(entry.cert_error()), GURL(entry.support_url())));
+  }
+
+  return dynamic_interstitial_list;
+}
+
 // Reads the SSL error assistant configuration from the resource bundle.
 std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig>
 ReadErrorAssistantProtoFromResourceBundle() {
@@ -76,6 +141,21 @@
   return false;
 }
 
+// Returns true if a hash in |ssl_info| is found in |spki_hashes|, a list of
+// hashes.
+bool MatchSSLInfoWithHashes(const net::SSLInfo& ssl_info,
+                            std::unordered_set<std::string> spki_hashes) {
+  for (const net::HashValue& hash_value : ssl_info.public_key_hashes) {
+    if (hash_value.tag() != net::HASH_VALUE_SHA256)
+      continue;
+
+    if (spki_hashes.find(hash_value.ToString()) != spki_hashes.end())
+      return true;
+  }
+
+  return false;
+}
+
 }  // namespace
 
 MITMSoftwareType::MITMSoftwareType(const std::string& name,
@@ -85,6 +165,22 @@
       issuer_common_name_regex(issuer_common_name_regex),
       issuer_organization_regex(issuer_organization_regex) {}
 
+DynamicInterstitialInfo::DynamicInterstitialInfo(
+    const std::unordered_set<std::string>& spki_hashes,
+    chrome_browser_ssl::DynamicInterstitial::InterstitialPageType
+        interstitial_type,
+    int cert_error,
+    const GURL& support_url)
+    : spki_hashes(spki_hashes),
+      interstitial_type(interstitial_type),
+      cert_error(cert_error),
+      support_url(support_url) {}
+
+DynamicInterstitialInfo::~DynamicInterstitialInfo() {}
+
+DynamicInterstitialInfo::DynamicInterstitialInfo(
+    const DynamicInterstitialInfo& other) = default;
+
 SSLErrorAssistant::SSLErrorAssistant() {}
 
 SSLErrorAssistant::~SSLErrorAssistant() {}
@@ -99,16 +195,32 @@
         LoadCaptivePortalCertHashes(*error_assistant_proto_);
   }
 
-  for (const net::HashValue& hash_value : ssl_info.public_key_hashes) {
-    if (hash_value.tag() != net::HASH_VALUE_SHA256) {
-      continue;
-    }
-    if (captive_portal_spki_hashes_->find(hash_value.ToString()) !=
-        captive_portal_spki_hashes_->end()) {
-      return true;
-    }
+  return MatchSSLInfoWithHashes(ssl_info, *(captive_portal_spki_hashes_.get()));
+}
+
+base::Optional<DynamicInterstitialInfo>
+SSLErrorAssistant::MatchDynamicInterstitial(const net::SSLInfo& ssl_info) {
+  // Load the dynamic interstitial data from SSL error assistant proto if it's
+  // not already loaded.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!dynamic_interstitial_list_) {
+    if (!error_assistant_proto_)
+      error_assistant_proto_ = ReadErrorAssistantProtoFromResourceBundle();
+
+    DCHECK(error_assistant_proto_);
+    dynamic_interstitial_list_ =
+        LoadDynamicInterstitialList(*error_assistant_proto_);
   }
-  return false;
+
+  for (const DynamicInterstitialInfo& data : *dynamic_interstitial_list_) {
+    if (data.cert_error && !(ssl_info.cert_status & data.cert_error))
+      continue;
+
+    if (MatchSSLInfoWithHashes(ssl_info, data.spki_hashes))
+      return data;
+  }
+
+  return base::nullopt;
 }
 
 const std::string SSLErrorAssistant::MatchKnownMITMSoftware(
@@ -201,12 +313,16 @@
 
   captive_portal_spki_hashes_ =
       LoadCaptivePortalCertHashes(*error_assistant_proto_);
+
+  dynamic_interstitial_list_ =
+      LoadDynamicInterstitialList(*error_assistant_proto_);
 }
 
 void SSLErrorAssistant::ResetForTesting() {
   error_assistant_proto_.reset();
   mitm_software_list_.reset();
   captive_portal_spki_hashes_.reset();
+  dynamic_interstitial_list_.reset();
 }
 
 int SSLErrorAssistant::GetErrorAssistantProtoVersionIdForTesting() const {
diff --git a/chrome/browser/ssl/ssl_error_assistant.h b/chrome/browser/ssl/ssl_error_assistant.h
index 02271ea..7ec9244 100644
--- a/chrome/browser/ssl/ssl_error_assistant.h
+++ b/chrome/browser/ssl/ssl_error_assistant.h
@@ -9,11 +9,10 @@
 #include <unordered_set>
 #include <vector>
 
+#include "base/optional.h"
+#include "chrome/browser/ssl/ssl_error_assistant.pb.h"
 #include "net/ssl/ssl_info.h"
-
-namespace chrome_browser_ssl {
-class SSLErrorAssistantConfig;
-}  // namespace chrome_browser_ssl
+#include "url/gurl.h"
 
 namespace net {
 class SSLInfo;
@@ -31,6 +30,27 @@
   const std::string issuer_organization_regex;
 };
 
+// Struct which stores data about a dynamic interstitial pulled from the
+// SSLErrorAssistant proto.
+struct DynamicInterstitialInfo {
+  DynamicInterstitialInfo(
+      const std::unordered_set<std::string>& spki_hashes,
+      chrome_browser_ssl::DynamicInterstitial::InterstitialPageType
+          interstitial_type,
+      int cert_error,
+      const GURL& support_url);
+
+  DynamicInterstitialInfo(const DynamicInterstitialInfo& other);
+
+  ~DynamicInterstitialInfo();
+
+  const std::unordered_set<std::string> spki_hashes;
+  const chrome_browser_ssl::DynamicInterstitial::InterstitialPageType
+      interstitial_type;
+  const int cert_error;
+  const GURL support_url;
+};
+
 // Helper class for SSLErrorHandler. This class is responsible for reading in
 // the ssl_error_assistant protobuf and parsing through the data.
 class SSLErrorAssistant {
@@ -50,6 +70,12 @@
   const std::string MatchKnownMITMSoftware(
       const scoped_refptr<net::X509Certificate>& cert);
 
+  // Returns a DynamicInterstitialInfo from |dynamic_interstitial_list_| that
+  // matches with |ssl_info|. If there is no match, returns null. Loads
+  // |dynamic_interstitial_list_| on the first use.
+  base::Optional<DynamicInterstitialInfo> MatchDynamicInterstitial(
+      const net::SSLInfo& ssl_info);
+
   void SetErrorAssistantProto(
       std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig> proto);
 
@@ -67,6 +93,11 @@
   // Null until MatchKnownMITMSoftware() is called.
   std::unique_ptr<std::vector<MITMSoftwareType>> mitm_software_list_;
 
+  // Dynamic interstitial data pulled from the SSLErrorAssistant proto. Null
+  // until MatchDynamicInterstitial() is called.
+  std::unique_ptr<std::vector<DynamicInterstitialInfo>>
+      dynamic_interstitial_list_;
+
   // Error assistant configuration.
   std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig>
       error_assistant_proto_;
diff --git a/chrome/browser/ssl/ssl_error_assistant.proto b/chrome/browser/ssl/ssl_error_assistant.proto
index 5dfa3d42..d9006e2b 100644
--- a/chrome/browser/ssl/ssl_error_assistant.proto
+++ b/chrome/browser/ssl/ssl_error_assistant.proto
@@ -35,8 +35,67 @@
   optional string issuer_organization_regex = 3;
 }
 
+// Unlike MITMSoftware and CaptivePortalCert, DynamicInterstitial is used to
+// trigger a number of different interstitials based on a number of different
+// characteristics.
+// TODO(spqchan): Deprecate MITMSoftware and CaptivePortalCert and use
+// DynamicInterstitial in their place.
+// TODO(spqchan): Add additional fields for common name regex, MitM, etc.
+message DynamicInterstitial {
+  // Enum class used to represent the interstitial page that would be displayed
+  // for a dynamic interstitial.
+  enum InterstitialPageType {
+    INTERSTITIAL_PAGE_NONE = 0;
+    // A standard SSL interstitial page.
+    INTERSTITIAL_PAGE_SSL = 1;
+    // An interstitial page alerting the user that they are in a captive portal.
+    INTERSTITIAL_PAGE_CAPTIVE_PORTAL = 2;
+    // An interstitial page telling the user to fix misconfigured MITM software.
+    INTERSTITIAL_PAGE_MITM_SOFTWARE = 3;
+  }
+
+  // Maps to CertStatus flags (See cert_status_flags_list.h).
+  enum CertError {
+    // Special value. If |cert_error| is set to this value, then anything that
+    // matches with the other fields will be treated as a match, regardless of
+    // |cert_error|.
+    UNKNOWN_CERT_ERROR = 0;
+    ERR_CERT_REVOKED = 1;
+    ERR_CERT_INVALID = 2;
+    ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN = 3;
+    ERR_CERT_AUTHORITY_INVALID = 4;
+    ERR_CERT_COMMON_NAME_INVALID = 5;
+    ERR_CERT_NAME_CONSTRAINT_VIOLATION = 6;
+    ERR_CERT_WEAK_SIGNATURE_ALGORITHM = 7;
+    ERR_CERT_WEAK_KEY = 8;
+    ERR_CERT_DATE_INVALID = 9;
+    ERR_CERT_VALIDITY_TOO_LONG = 10;
+    ERR_CERT_UNABLE_TO_CHECK_REVOCATION = 11;
+    ERR_CERT_NO_REVOCATION_MECHANISM = 12;
+    ERR_CERT_NON_UNIQUE_NAME = 13;
+    ERR_CERTIFICATE_TRANSPARENCY_REQUIRED = 14;
+  };
+
+  // Sha256 hashes of the certificate's public key. If any certificate in the
+  // certificate chain matches any one of the hashes, an interstitial specified
+  // by |interstitial_type| will be displayed.
+  repeated string sha256_hash = 1;
+
+  // If the SSL error's cert status contains |cert_error|, then it can be
+  // matched with this dynamic interstitial.
+  optional CertError cert_error = 2;
+
+  // The type of interstitial that should be shown. This value is associated
+  // with the DynamicInterstitialPageType enum.
+  optional InterstitialPageType interstitial_type = 3;
+
+  // The support URL that will be displayed on the interstitial.
+  optional string support_url = 4;
+}
+
 message SSLErrorAssistantConfig {
   optional uint32 version_id = 1;
   repeated CaptivePortalCert captive_portal_cert = 2;
   repeated MITMSoftware mitm_software = 3;
+  repeated DynamicInterstitial dynamic_interstitial = 4;
 }
diff --git a/chrome/browser/ssl/ssl_error_assistant_unittest.cc b/chrome/browser/ssl/ssl_error_assistant_unittest.cc
index 750fcd9..13ef950 100644
--- a/chrome/browser/ssl/ssl_error_assistant_unittest.cc
+++ b/chrome/browser/ssl/ssl_error_assistant_unittest.cc
@@ -198,3 +198,128 @@
 
   TestMITMSoftwareMatchFromString(kMisconfigSoftwareCert, "");
 }
+
+// Test to see if the dynamic interstitial is matched.
+TEST_F(SSLErrorAssistantTest, DynamicInterstitialListMatch) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  EXPECT_EQ(1u, ssl_info().public_key_hashes.size());
+
+  auto config_proto =
+      base::MakeUnique<chrome_browser_ssl::SSLErrorAssistantConfig>();
+  config_proto->set_version_id(kLargeVersionId);
+
+  // Add a dynamic interstitial that will mismatch.
+  chrome_browser_ssl::DynamicInterstitial* filter =
+      config_proto->add_dynamic_interstitial();
+  filter->set_interstitial_type(chrome_browser_ssl::DynamicInterstitial::
+                                    INTERSTITIAL_PAGE_CAPTIVE_PORTAL);
+  filter->set_cert_error(
+      chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR);
+  filter->add_sha256_hash("sha256/nightjar");
+  filter->add_sha256_hash("sha256/frogmouth");
+  filter->add_sha256_hash("sha256/poorwill");
+
+  // Add a dynamic interstitial that will match.
+  filter = config_proto->add_dynamic_interstitial();
+  filter->set_interstitial_type(
+      chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL);
+  filter->set_cert_error(
+      chrome_browser_ssl::DynamicInterstitial::ERR_CERT_COMMON_NAME_INVALID);
+  filter->add_sha256_hash("sha256/nuthatch");
+  filter->add_sha256_hash(ssl_info().public_key_hashes[0].ToString());
+  filter->add_sha256_hash("sha256/treecreeper");
+
+  error_assistant()->SetErrorAssistantProto(std::move(config_proto));
+
+  base::Optional<DynamicInterstitialInfo> dynamic_interstitial =
+      error_assistant()->MatchDynamicInterstitial(ssl_info());
+  ASSERT_TRUE(dynamic_interstitial);
+  EXPECT_EQ(chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL,
+            dynamic_interstitial->interstitial_type);
+}
+
+// Test to see if the dynamic interstitial is matched when the certificate
+// error is set to UNKNOWN_CERT_ERROR.
+TEST_F(SSLErrorAssistantTest, DynamicInterstitialListMatchUnknownCertError) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  EXPECT_EQ(1u, ssl_info().public_key_hashes.size());
+
+  auto config_proto =
+      base::MakeUnique<chrome_browser_ssl::SSLErrorAssistantConfig>();
+  config_proto->set_version_id(kLargeVersionId);
+
+  // Add a dynamic interstitial that will mismatch.
+  chrome_browser_ssl::DynamicInterstitial* filter =
+      config_proto->add_dynamic_interstitial();
+  filter->set_interstitial_type(chrome_browser_ssl::DynamicInterstitial::
+                                    INTERSTITIAL_PAGE_CAPTIVE_PORTAL);
+  filter->set_cert_error(
+      chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR);
+  filter->add_sha256_hash("sha256/nightjar");
+  filter->add_sha256_hash("sha256/frogmouth");
+  filter->add_sha256_hash("sha256/poorwill");
+
+  // Add a dynamic interstitial that will match.
+  filter = config_proto->add_dynamic_interstitial();
+  filter->set_interstitial_type(
+      chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL);
+  filter->set_cert_error(
+      chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR);
+  filter->add_sha256_hash("sha256/nuthatch");
+  filter->add_sha256_hash(ssl_info().public_key_hashes[0].ToString());
+  filter->add_sha256_hash("sha256/treecreeper");
+
+  error_assistant()->SetErrorAssistantProto(std::move(config_proto));
+
+  base::Optional<DynamicInterstitialInfo> dynamic_interstitial =
+      error_assistant()->MatchDynamicInterstitial(ssl_info());
+  EXPECT_TRUE(dynamic_interstitial);
+  EXPECT_EQ(chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL,
+            dynamic_interstitial->interstitial_type);
+}
+
+// Test for a dynamic interstitial mismatch in the cert error.
+TEST_F(SSLErrorAssistantTest, DynamicInterstitialListCertErrorMismatch) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  EXPECT_EQ(1u, ssl_info().public_key_hashes.size());
+
+  auto config_proto =
+      base::MakeUnique<chrome_browser_ssl::SSLErrorAssistantConfig>();
+  config_proto->set_version_id(kLargeVersionId);
+
+  chrome_browser_ssl::DynamicInterstitial* filter =
+      config_proto->add_dynamic_interstitial();
+  filter->set_interstitial_type(
+      chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL);
+  filter->set_cert_error(
+      chrome_browser_ssl::DynamicInterstitial::ERR_CERT_DATE_INVALID);
+  filter->add_sha256_hash("sha256/nuthatch");
+  filter->add_sha256_hash(ssl_info().public_key_hashes[0].ToString());
+  filter->add_sha256_hash("sha256/treecreeper");
+
+  error_assistant()->SetErrorAssistantProto(std::move(config_proto));
+  EXPECT_FALSE(error_assistant()->MatchDynamicInterstitial(ssl_info()));
+}
+
+// Test for a dynamic interstitial mismatch in the certificate hashes.
+TEST_F(SSLErrorAssistantTest, DynamicInterstitialListHashesMismatch) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  EXPECT_EQ(1u, ssl_info().public_key_hashes.size());
+
+  auto config_proto =
+      base::MakeUnique<chrome_browser_ssl::SSLErrorAssistantConfig>();
+  config_proto->set_version_id(kLargeVersionId);
+
+  chrome_browser_ssl::DynamicInterstitial* filter =
+      config_proto->add_dynamic_interstitial();
+  filter->set_interstitial_type(
+      chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL);
+  filter->set_cert_error(
+      chrome_browser_ssl::DynamicInterstitial::UNKNOWN_CERT_ERROR);
+
+  filter->add_sha256_hash("sha256/yellowlegs");
+  filter->add_sha256_hash("sha256/killdeer");
+
+  error_assistant()->SetErrorAssistantProto(std::move(config_proto));
+  EXPECT_FALSE(error_assistant()->MatchDynamicInterstitial(ssl_info()));
+}
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 11f6b158..6b77f00 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -204,6 +204,11 @@
   const std::string MatchKnownMITMSoftware(
       const scoped_refptr<net::X509Certificate> cert);
 
+  // Returns a DynamicInterstitialInfo that matches with |ssl_info|. If is no
+  // match, return null.
+  base::Optional<DynamicInterstitialInfo> MatchDynamicInterstitial(
+      const net::SSLInfo& ssl_info);
+
   // Testing methods:
   void ResetForTesting();
   void SetInterstitialDelayForTesting(const base::TimeDelta& delay);
@@ -379,6 +384,11 @@
   return ssl_error_assistant_->MatchKnownMITMSoftware(cert);
 }
 
+base::Optional<DynamicInterstitialInfo>
+ConfigSingleton::MatchDynamicInterstitial(const net::SSLInfo& ssl_info) {
+  return ssl_error_assistant_->MatchDynamicInterstitial(ssl_info);
+}
+
 class SSLErrorHandlerDelegateImpl : public SSLErrorHandler::Delegate {
  public:
   SSLErrorHandlerDelegateImpl(
@@ -419,7 +429,7 @@
   void ShowCaptivePortalInterstitial(const GURL& landing_url) override;
   void ShowMITMSoftwareInterstitial(const std::string& mitm_software_name,
                                     bool is_enterprise_managed) override;
-  void ShowSSLInterstitial() override;
+  void ShowSSLInterstitial(const GURL& support_url) override;
   void ShowBadClockInterstitial(const base::Time& now,
                                 ssl_errors::ClockState clock_state) override;
 
@@ -515,12 +525,12 @@
       decision_callback_));
 }
 
-void SSLErrorHandlerDelegateImpl::ShowSSLInterstitial() {
+void SSLErrorHandlerDelegateImpl::ShowSSLInterstitial(const GURL& support_url) {
   // Show SSL blocking page. The interstitial owns the blocking page.
   OnBlockingPageReady(SSLBlockingPage::Create(
       web_contents_, cert_error_, ssl_info_, request_url_, options_mask_,
-      base::Time::NowFromSystemTime(), std::move(ssl_cert_reporter_),
-      is_superfish_, decision_callback_));
+      base::Time::NowFromSystemTime(), support_url,
+      std::move(ssl_cert_reporter_), is_superfish_, decision_callback_));
 }
 
 void SSLErrorHandlerDelegateImpl::ShowBadClockInterstitial(
@@ -708,6 +718,13 @@
     return;
   }
 
+  base::Optional<DynamicInterstitialInfo> dynamic_interstitial =
+      g_config.Pointer()->MatchDynamicInterstitial(ssl_info_);
+  if (dynamic_interstitial) {
+    ShowDynamicInterstitial(dynamic_interstitial.value());
+    return;
+  }
+
   // Ideally, a captive portal interstitial should only be displayed if the only
   // SSL error is a name mismatch error. However, captive portal detector always
   // opens a new tab if it detects a portal ignoring the types of SSL errors. To
@@ -841,7 +858,7 @@
   RecordUMA(delegate_->IsErrorOverridable()
                 ? SHOW_SSL_INTERSTITIAL_OVERRIDABLE
                 : SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE);
-  delegate_->ShowSSLInterstitial();
+  delegate_->ShowSSLInterstitial(GURL());
   // Once an interstitial is displayed, no need to keep the handler around.
   // This is the equivalent of "delete this".
   web_contents_->RemoveUserData(UserDataKey());
@@ -857,6 +874,26 @@
   web_contents_->RemoveUserData(UserDataKey());
 }
 
+void SSLErrorHandler::ShowDynamicInterstitial(
+    const DynamicInterstitialInfo dynamic_interstitial) {
+  switch (dynamic_interstitial.interstitial_type) {
+    case chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_NONE:
+      NOTREACHED();
+    case chrome_browser_ssl::DynamicInterstitial::INTERSTITIAL_PAGE_SSL:
+      delegate_->ShowSSLInterstitial(dynamic_interstitial.support_url);
+      return;
+    case chrome_browser_ssl::DynamicInterstitial::
+        INTERSTITIAL_PAGE_CAPTIVE_PORTAL:
+      delegate_->ShowCaptivePortalInterstitial(GURL());
+      return;
+    case chrome_browser_ssl::DynamicInterstitial::
+        INTERSTITIAL_PAGE_MITM_SOFTWARE:
+      // TODO(spqchan): Implement support for MitM dynamic interstitials.
+      NOTREACHED();
+      return;
+  }
+}
+
 void SSLErrorHandler::CommonNameMismatchHandlerCallback(
     CommonNameMismatchHandler::SuggestedUrlCheckResult result,
     const GURL& suggested_url) {
diff --git a/chrome/browser/ssl/ssl_error_handler.h b/chrome/browser/ssl/ssl_error_handler.h
index 1c2fe324..565ed0f4 100644
--- a/chrome/browser/ssl/ssl_error_handler.h
+++ b/chrome/browser/ssl/ssl_error_handler.h
@@ -29,6 +29,7 @@
 
 class CommonNameMismatchHandler;
 class Profile;
+struct DynamicInterstitialInfo;
 
 namespace base {
 class Clock;
@@ -116,7 +117,7 @@
     virtual void ShowMITMSoftwareInterstitial(
         const std::string& mitm_software_name,
         bool is_enterprise_managed) = 0;
-    virtual void ShowSSLInterstitial() = 0;
+    virtual void ShowSSLInterstitial(const GURL& support_url) = 0;
     virtual void ShowBadClockInterstitial(
         const base::Time& now,
         ssl_errors::ClockState clock_state) = 0;
@@ -187,6 +188,7 @@
   void ShowSSLInterstitial();
   void ShowBadClockInterstitial(const base::Time& now,
                                 ssl_errors::ClockState clock_state);
+  void ShowDynamicInterstitial(const DynamicInterstitialInfo interstitial);
 
   // Gets the result of whether the suggested URL is valid. Displays
   // common name mismatch interstitial or ssl interstitial accordingly.
diff --git a/chrome/browser/ssl/ssl_error_handler_unittest.cc b/chrome/browser/ssl/ssl_error_handler_unittest.cc
index 5f9386ab..6a40341 100644
--- a/chrome/browser/ssl/ssl_error_handler_unittest.cc
+++ b/chrome/browser/ssl/ssl_error_handler_unittest.cc
@@ -233,7 +233,9 @@
     return true;
   }
 
-  void ShowSSLInterstitial() override { ssl_interstitial_shown_ = true; }
+  void ShowSSLInterstitial(const GURL& support_url = GURL()) override {
+    ssl_interstitial_shown_ = true;
+  }
 
   void ShowBadClockInterstitial(const base::Time& now,
                                 ssl_errors::ClockState clock_state) override {
diff --git a/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc b/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc
index 717712f..52475c14 100644
--- a/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc
+++ b/chrome/browser/ssl/ssl_error_navigation_throttle_unittest.cc
@@ -37,10 +37,10 @@
     base::OnceCallback<
         void(std::unique_ptr<security_interstitials::SecurityInterstitialPage>)>
         blocking_page_ready_callback) {
-  std::unique_ptr<SSLBlockingPage> blocking_page(
-      SSLBlockingPage::Create(web_contents, cert_error, ssl_info, request_url,
-                              0, base::Time::NowFromSystemTime(), nullptr,
-                              false /* is superfish */, decision_callback));
+  std::unique_ptr<SSLBlockingPage> blocking_page(SSLBlockingPage::Create(
+      web_contents, cert_error, ssl_info, request_url, 0,
+      base::Time::NowFromSystemTime(), GURL(), nullptr,
+      false /* is superfish */, decision_callback));
   if (async) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(blocking_page_ready_callback),
diff --git a/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc b/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc
index d44ed71c..672493f 100644
--- a/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc
+++ b/chrome/browser/ssl/ssl_error_tab_helper_unittest.cc
@@ -42,6 +42,7 @@
             request_url,
             0,
             base::Time::NowFromSystemTime(),
+            GURL(),
             nullptr /* ssl_cert_reporter */,
             true /* overridable */,
             CreateMetricsHelper(web_contents),
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index d2b6695..ca302dd 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -23,12 +23,14 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
+#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_pack.h"
 #include "chrome/browser/themes/custom_theme_supplier.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/themes/theme_syncable_service.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
@@ -917,9 +919,22 @@
   }
 
   // Offer to revert to the old theme.
-  if (can_revert_theme && !suppress_infobar) {
-    ThemeInstalledInfoBarDelegate::Create(
-        extension, profile_, previous_theme_id, previous_using_system_theme);
+  if (can_revert_theme && !suppress_infobar && extension->is_theme()) {
+    // FindTabbedBrowser() is called with |match_original_profiles| true because
+    // a theme install in either a normal or incognito window for a profile
+    // affects all normal and incognito windows for that profile.
+    Browser* browser = chrome::FindTabbedBrowser(profile_, true);
+    if (browser) {
+      content::WebContents* web_contents =
+          browser->tab_strip_model()->GetActiveWebContents();
+      if (web_contents) {
+        ThemeInstalledInfoBarDelegate::Create(
+            InfoBarService::FromWebContents(web_contents),
+            extensions::ExtensionSystem::Get(profile_)->extension_service(),
+            ThemeServiceFactory::GetForProfile(profile_), extension->name(),
+            extension->id(), previous_theme_id, previous_using_system_theme);
+      }
+    }
   }
   building_extension_id_.clear();
 }
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index f721bc8a..243f3a24 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -12,6 +12,7 @@
 #include "ash/accelerators/magnifier_key_scroller.h"
 #include "ash/accelerators/spoken_feedback_toggler.h"
 #include "ash/accessibility/accessibility_delegate.h"
+#include "ash/display/display_configuration_observer.h"
 #include "ash/display/display_prefs.h"
 #include "ash/public/cpp/accessibility_types.h"
 #include "ash/shell.h"
@@ -31,7 +32,6 @@
 #include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h"
 #include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/background/ash_wallpaper_delegate.h"
-#include "chrome/browser/chromeos/display/display_configuration_observer.h"
 #include "chrome/browser/chromeos/policy/display_rotation_default_handler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -288,7 +288,8 @@
 }
 
 void ChromeShellDelegate::PreInit() {
-  // TODO: port to mash. http://crbug.com/678949.
+  // TODO(mash): port DisplayRotationDefaultHandler to mash once CrosSettings
+  // is moved to a service. http://crbug.com/678949.
   if (chromeos::GetAshConfig() == ash::Config::MASH)
     return;
 
@@ -296,15 +297,6 @@
   // Setup is done in OnShellInitialized() so this needs to be constructed after
   // Shell is constructed but before OnShellInitialized() is called.
   new policy::DisplayRotationDefaultHandler();
-
-  // Set the observer now so that we can save the initial state
-  // in Shell::Init.
-  display_configuration_observer_.reset(
-      new chromeos::DisplayConfigurationObserver());
-}
-
-void ChromeShellDelegate::PreShutdown() {
-  display_configuration_observer_.reset();
 }
 
 void ChromeShellDelegate::OpenUrlFromArc(const GURL& url) {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 76572659..b0b3eb8 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -14,10 +14,6 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
-namespace chromeos {
-class DisplayConfigurationObserver;
-}
-
 namespace keyboard {
 class KeyboardUI;
 }
@@ -34,7 +30,6 @@
   bool CanShowWindowForUser(aura::Window* window) const override;
   bool IsForceMaximizeOnFirstRun() const override;
   void PreInit() override;
-  void PreShutdown() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
   void OpenUrlFromArc(const GURL& url) override;
   ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() override;
@@ -54,9 +49,6 @@
 
   content::NotificationRegistrar registrar_;
 
-  std::unique_ptr<chromeos::DisplayConfigurationObserver>
-      display_configuration_observer_;
-
   std::unique_ptr<ash::NetworkingConfigDelegate> networking_config_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeShellDelegate);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index cf1bef3..5c16c506 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -252,7 +252,7 @@
 
 void ChromeAutofillClient::LoadRiskData(
     const base::Callback<void(const std::string&)>& callback) {
-  ::autofill::LoadRiskData(0, web_contents(), callback, connector_);
+  ::autofill::LoadRiskData(0, web_contents(), callback);
 }
 
 bool ChromeAutofillClient::HasCreditCardScanFeature() {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index d552bcc..3dcfa21d 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -29,10 +29,6 @@
 class WebContents;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 namespace autofill {
 
 class AutofillPopupControllerImpl;
@@ -115,7 +111,6 @@
 #endif  // !defined(OS_ANDROID)
 
  private:
-  friend class SaveCardBubbleViewsBrowserTestBase;
   friend class content::WebContentsUserData<ChromeAutofillClient>;
 
   explicit ChromeAutofillClient(content::WebContents* web_contents);
@@ -128,13 +123,6 @@
   // The identity provider, used for Payments integration.
   std::unique_ptr<IdentityProvider> identity_provider_;
 
-  // An optional connector to expose test services. For example, if set, this
-  // connector is used when loading risk data. The test class that sets this
-  // pointer is responsible for the ownership of its object.
-  // TODO(crbug.com/791155): Necessary for testing due to leaks in the
-  // geolocation setup code when running browsertests.
-  service_manager::Connector* connector_ = nullptr;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeAutofillClient);
 };
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm
index 9744ffc1..ee3b9da 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm
@@ -376,8 +376,9 @@
 }
 
 - (NSString*)elideTitle:(int)availableWidth {
-  return base::SysUTF16ToNSString(gfx::ElideFilename(
-      downloadPath_, gfx::FontList(gfx::Font([self font])), availableWidth));
+  return base::SysUTF16ToNSString(
+      gfx::ElideFilename(downloadPath_, gfx::FontList(gfx::Font([self font])),
+                         availableWidth, gfx::Typesetter::PLATFORM));
 }
 
 - (NSString*)elideStatus:(int)availableWidth {
diff --git a/chrome/browser/ui/cocoa/download/md_download_item_view.mm b/chrome/browser/ui/cocoa/download/md_download_item_view.mm
index a32f4e9a..17c63227 100644
--- a/chrome/browser/ui/cocoa/download/md_download_item_view.mm
+++ b/chrome/browser/ui/cocoa/download/md_download_item_view.mm
@@ -556,7 +556,8 @@
   filenameView_.stringValue = base::SysUTF16ToNSString(
       gfx::ElideFilename(downloadModel->download()->GetFileNameToReportUser(),
                          gfx::FontList(gfx::Font(filenameView_.font)),
-                         NSWidth(filenameView_.bounds) - lineFragmentPadding));
+                         NSWidth(filenameView_.bounds) - lineFragmentPadding,
+                         gfx::Typesetter::PLATFORM));
 
   NSString* statusString =
       base::SysUTF16ToNSString(downloadModel->GetStatusText());
diff --git a/chrome/browser/ui/exclusive_access/OWNERS b/chrome/browser/ui/exclusive_access/OWNERS
index 192ee8f..21149b0 100644
--- a/chrome/browser/ui/exclusive_access/OWNERS
+++ b/chrome/browser/ui/exclusive_access/OWNERS
@@ -1,5 +1,4 @@
 mgiuca@chromium.org
 miu@chromium.org
-scheib@chromium.org
 
 # COMPONENT: UI>Browser>FullScreen
diff --git a/chrome/browser/ui/libgtkui/app_indicator_icon.cc b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
index f7943a2..378a15fb 100644
--- a/chrome/browser/ui/libgtkui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
@@ -285,11 +285,11 @@
   base::FilePath icon_theme_path = temp_dir.AppendASCII("icons");
 
   // On KDE4, an image located in a directory ending with
-  // "icons/hicolor/24x24/apps" can be used as the app indicator image because
-  // "/usr/share/icons/hicolor/24x24/apps" exists.
-  base::FilePath image_dir = icon_theme_path.AppendASCII("hicolor")
-                                 .AppendASCII("24x24")
-                                 .AppendASCII("apps");
+  // "icons/hicolor/22x22/apps" can be used as the app indicator image because
+  // "/usr/share/icons/hicolor/22x22/apps" exists.
+  base::FilePath image_dir =
+      icon_theme_path.AppendASCII("hicolor").AppendASCII("22x22").AppendASCII(
+          "apps");
 
   if (!base::CreateDirectory(image_dir))
     return SetImageFromFileParams();
@@ -307,9 +307,9 @@
   std::string icon_name = base::StringPrintf(
       "chrome_app_indicator2_%s", base::MD5DigestToBase16(digest).c_str());
 
-  // If |bitmap| is not 24x24, KDE does some really ugly resizing. Pad |bitmap|
-  // with transparent pixels to make it 24x24.
-  const int kDesiredSize = 24;
+  // If |bitmap| is not 22x22, KDE does some really ugly resizing. Pad |bitmap|
+  // with transparent pixels to make it 22x22.
+  const int kDesiredSize = 22;
   SkBitmap scaled_bitmap;
   scaled_bitmap.allocN32Pixels(kDesiredSize, kDesiredSize);
   scaled_bitmap.eraseARGB(0, 0, 0, 0);
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
index b95d50b..322e791 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
@@ -20,11 +20,8 @@
 #include "components/autofill/core/browser/credit_card_save_manager.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "device/geolocation/public/interfaces/geolocation_context.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "device/geolocation/public/cpp/scoped_geolocation_overrider.h"
 #include "net/url_request/test_url_fetcher_factory.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connector.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/window/dialog_client_view.h"
@@ -45,71 +42,11 @@
     "{\"error\":{\"code\":\"FAILED_PRECONDITION\",\"user_error_message\":\"An "
     "unexpected error has occurred. Please try again later.\"}}";
 
-const double kFakeGeolocationLatitude = -42.0;
-const double kFakeGeolocationLongitude = 17.3;
-const double kFakeGeolocationAltitude = 123.4;
-const double kFakeGeolocationAccuracy = 73.7;
-const int kFakeGeolocationTime = 87;
+const double kFakeGeolocationLatitude = 1.23;
+const double kFakeGeolocationLongitude = 4.56;
 
 }  // namespace
 
-// A fake geolocation client; necessary due to leaks in the geolocation setup
-// code that causes browsertests to fail when run.
-// TODO(crbug.com/791155): Remove this class's implementation once the leak is
-// fixed and the original geolocation client can be used in browsertests.
-class SaveCardBubbleViewsBrowserTestBase::FakeGeolocation
-    : public device::mojom::GeolocationContext,
-      public device::mojom::Geolocation {
- public:
-  explicit FakeGeolocation(device::mojom::Geoposition& position);
-  ~FakeGeolocation() override;
-
-  void Bind(device::mojom::GeolocationContextRequest request);
-
-  // device::mojom::Geolocation implementation:
-  void QueryNextPosition(QueryNextPositionCallback callback) override;
-  void SetHighAccuracy(bool high_accuracy) override;
-
-  // device::mojom::GeolocationContext implementation:
-  void BindGeolocation(device::mojom::GeolocationRequest request) override;
-  void SetOverride(device::mojom::GeopositionPtr geoposition) override;
-  void ClearOverride() override;
-
- private:
-  mojo::Binding<device::mojom::GeolocationContext> binding_context_;
-  mojo::Binding<device::mojom::Geolocation> binding_;
-  device::mojom::Geoposition position_;
-};
-
-SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::FakeGeolocation(
-    device::mojom::Geoposition& position)
-    : binding_context_(this), binding_(this), position_(position) {}
-
-SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::~FakeGeolocation() {}
-
-void SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::Bind(
-    device::mojom::GeolocationContextRequest request) {
-  binding_context_.Bind(std::move(request));
-}
-
-void SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::QueryNextPosition(
-    QueryNextPositionCallback callback) {
-  std::move(callback).Run(position_.Clone());
-}
-
-void SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::SetHighAccuracy(
-    bool high_accuracy) {}
-
-void SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::BindGeolocation(
-    device::mojom::GeolocationRequest request) {
-  binding_.Bind(std::move(request));
-}
-
-void SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::SetOverride(
-    device::mojom::GeopositionPtr geoposition) {}
-
-void SaveCardBubbleViewsBrowserTestBase::FakeGeolocation::ClearOverride() {}
-
 SaveCardBubbleViewsBrowserTestBase::SaveCardBubbleViewsBrowserTestBase(
     const std::string& test_file_path)
     : test_file_path_(test_file_path) {}
@@ -137,23 +74,9 @@
           ->credit_card_save_manager_.get();
   credit_card_save_manager->SetEventObserverForTesting(this);
 
-  // Set up fake geolocation. Necessary due to leaks in the geolocation setup
-  // code when loading risk data.
-  device::mojom::Geoposition position;
-  position.latitude = kFakeGeolocationLatitude;
-  position.longitude = kFakeGeolocationLongitude;
-  position.altitude = kFakeGeolocationAltitude;
-  position.accuracy = kFakeGeolocationAccuracy;
-  position.timestamp = base::Time::UnixEpoch() +
-                       base::TimeDelta::FromMilliseconds(kFakeGeolocationTime);
-  service_manager::mojom::ConnectorRequest connector_request;
-  connector_ = service_manager::Connector::Create(&connector_request);
-  fake_geolocation_ = std::make_unique<FakeGeolocation>(position);
-  registry_.AddInterface<device::mojom::GeolocationContext>(base::BindRepeating(
-      &FakeGeolocation::Bind, base::Unretained(fake_geolocation_.get())));
-  ChromeAutofillClient* chrome_autofill_client =
-      ChromeAutofillClient::FromWebContents(GetActiveWebContents());
-  chrome_autofill_client->connector_ = connector_.get();
+  // Set up the fake geolocation data.
+  geolocation_overrider_ = std::make_unique<device::ScopedGeolocationOverrider>(
+      kFakeGeolocationLatitude, kFakeGeolocationLongitude);
 
   NavigateTo(test_file_path_);
 }
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h
index 2f398c8..abf1354 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.h
@@ -18,14 +18,14 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/autofill/core/browser/credit_card_save_manager.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "device/geolocation/public/interfaces/geolocation_context.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/url_request/test_url_fetcher_factory.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+namespace device {
+class ScopedGeolocationOverrider;
+}
+
 namespace autofill {
 
 // Base class for any interactive SaveCardBubbleViews browser test that will
@@ -103,14 +103,9 @@
  private:
   std::unique_ptr<DialogEventWaiter<DialogEvent>> event_waiter_;
   std::unique_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
+  std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_;
   const std::string test_file_path_;
 
-  // FakeGeolocation setup:
-  class FakeGeolocation;
-  std::unique_ptr<FakeGeolocation> fake_geolocation_;
-  std::unique_ptr<service_manager::Connector> connector_;
-  service_manager::BinderRegistry registry_;
-
   DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleViewsBrowserTestBase);
 };
 
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 5ca1171..ab55a514 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
@@ -18,10 +18,12 @@
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
+#include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
@@ -87,6 +89,10 @@
   if (TabletModeClient::Get())
     TabletModeClient::Get()->RemoveObserver(this);
   ash::Shell::Get()->RemoveShellObserver(this);
+  if (back_button_) {
+    browser_view()->browser()->command_controller()->RemoveCommandObserver(
+        this);
+  }
 }
 
 void BrowserNonClientFrameViewAsh::Init() {
@@ -106,7 +112,8 @@
   if (browser->is_app() && IsV1AppBackButtonEnabled()) {
     back_button_ = new ash::FrameBackButton();
     AddChildView(back_button_);
-    // TODO(oshima): Update the back button state.
+    // TODO(oshima): Add Tooltip, accessibility name.
+    browser->command_controller()->AddCommandObserver(IDC_BACK, this);
   }
 
   frame_header_ = CreateFrameHeader();
@@ -425,6 +432,12 @@
   return delegate ? delegate->GetWindowIcon() : gfx::ImageSkia();
 }
 
+void BrowserNonClientFrameViewAsh::EnabledStateChangedForCommand(int id,
+                                                                 bool enabled) {
+  if (id == IDC_BACK && back_button_)
+    back_button_->SetEnabled(enabled);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserNonClientFrameViewAsh, protected:
 
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 81e9348..bc43040 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
@@ -10,6 +10,7 @@
 #include "ash/shell_observer.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "chrome/browser/command_observer.h"
 #include "chrome/browser/ui/ash/tablet_mode_client_observer.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 #include "chrome/browser/ui/views/tab_icon_view_model.h"
@@ -27,7 +28,8 @@
 class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView,
                                      public ash::ShellObserver,
                                      public TabletModeClientObserver,
-                                     public TabIconViewModel {
+                                     public TabIconViewModel,
+                                     public CommandObserver {
  public:
   BrowserNonClientFrameViewAsh(BrowserFrame* frame, BrowserView* browser_view);
   ~BrowserNonClientFrameViewAsh() override;
@@ -71,6 +73,9 @@
   bool ShouldTabIconViewAnimate() const override;
   gfx::ImageSkia GetFaviconForTabIconView() override;
 
+  // CommandObserver:
+  void EnabledStateChangedForCommand(int id, bool enabled) override;
+
  protected:
   // BrowserNonClientFrameView:
   void UpdateProfileIcons() override;
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 1ba79a573..1dcfd95f 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
@@ -599,15 +599,27 @@
       browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
   Browser* browser = new Browser(params);
+  AddBlankTabAndShow(browser);
+
   views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
       browser->window()->GetNativeWindow());
-
   BrowserNonClientFrameViewAsh* frame_view =
       static_cast<BrowserNonClientFrameViewAsh*>(
           widget->non_client_view()->frame_view());
   ASSERT_TRUE(frame_view->back_button_);
   EXPECT_TRUE(frame_view->back_button_->visible());
+  // The back button should be disabled initially.
+  EXPECT_FALSE(frame_view->back_button_->enabled());
+
+  // Nagivate to a page. The back button should now be enabled.
+  const GURL kAppStartURL("http://example.org/");
+  NavigateParams nav_params(browser, kAppStartURL, ui::PAGE_TRANSITION_LINK);
+  ui_test_utils::NavigateToURL(&nav_params);
   EXPECT_TRUE(frame_view->back_button_->enabled());
+
+  // Go back to the blank. The back button should be disabled again.
+  chrome::GoBack(browser, WindowOpenDisposition::CURRENT_TAB);
+  EXPECT_FALSE(frame_view->back_button_->enabled());
 }
 
 // Test the normal type browser's kTopViewInset is always 0.
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
index be97883..37c210a 100644
--- a/chrome/browser/ui/webui/devtools_ui.cc
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -71,6 +71,8 @@
 // requests. Three types of requests could be handled based on the URL path:
 // 1. /bundled/: bundled DevTools frontend is served.
 // 2. /remote/: remote DevTools frontend is served from App Engine.
+// 3. /custom/: custom DevTools frontend is served from the server as specified
+//    by the --custom-devtools-frontend flag.
 class DevToolsDataSource : public content::URLDataSource,
                            public net::URLFetcherDelegate {
  public:
@@ -192,6 +194,7 @@
                        base::CompareCase::INSENSITIVE_ASCII)) {
     GURL url = GURL(custom_frontend_url +
                     path.substr(custom_path_prefix.length()));
+    DCHECK(url.is_valid());
     StartCustomDataRequest(url, callback);
     return;
   }
@@ -350,6 +353,27 @@
       content::GetWebKitRevision().c_str()));
 }
 
+// static
+bool DevToolsUI::IsFrontendResourceURL(const GURL& url) {
+  if (url.host_piece() == kRemoteFrontendDomain)
+    return true;
+
+  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  if (cmd_line->HasSwitch(switches::kCustomDevtoolsFrontend)) {
+    GURL custom_frontend_url =
+        GURL(cmd_line->GetSwitchValueASCII(switches::kCustomDevtoolsFrontend));
+    if (custom_frontend_url.is_valid() &&
+        custom_frontend_url.scheme_piece() == url.scheme_piece() &&
+        custom_frontend_url.host_piece() == url.host_piece() &&
+        custom_frontend_url.EffectiveIntPort() == url.EffectiveIntPort() &&
+        base::StartsWith(url.path_piece(), custom_frontend_url.path_piece(),
+                         base::CompareCase::SENSITIVE)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 DevToolsUI::DevToolsUI(content::WebUI* web_ui)
     : WebUIController(web_ui), bindings_(web_ui->GetWebContents()) {
   web_ui->SetBindings(0);
diff --git a/chrome/browser/ui/webui/devtools_ui.h b/chrome/browser/ui/webui/devtools_ui.h
index 809e4e4..88c7913 100644
--- a/chrome/browser/ui/webui/devtools_ui.h
+++ b/chrome/browser/ui/webui/devtools_ui.h
@@ -13,6 +13,7 @@
  public:
   static GURL GetProxyURL(const std::string& frontend_url);
   static GURL GetRemoteBaseURL();
+  static bool IsFrontendResourceURL(const GURL& url);
 
   explicit DevToolsUI(content::WebUI* web_ui);
   ~DevToolsUI() override;
diff --git a/chrome/browser/ui/webui/favicon_source.cc b/chrome/browser/ui/webui/favicon_source.cc
index f58940089..9c7b15f 100644
--- a/chrome/browser/ui/webui/favicon_source.cc
+++ b/chrome/browser/ui/webui/favicon_source.cc
@@ -75,6 +75,11 @@
   }
 
   GURL url(parsed.url);
+  if (!url.is_valid()) {
+    SendDefaultResponse(callback);
+    return;
+  }
+
   int desired_size_in_pixel =
       std::ceil(parsed.size_in_dip * parsed.device_scale_factor);
 
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index eef48b3..24fc3095 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -174,7 +174,7 @@
     options_mask |= security_interstitials::SSLErrorUI::STRICT_ENFORCEMENT;
   return SSLBlockingPage::Create(
       web_contents, cert_error, ssl_info, request_url, options_mask,
-      time_triggered_, nullptr, is_superfish,
+      time_triggered_, GURL(), nullptr, is_superfish,
       base::Callback<void(content::CertificateRequestResultType)>());
 }
 
diff --git a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
index ad17ba5..5d5f896 100644
--- a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
+++ b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
@@ -437,8 +437,8 @@
 
 void OfflineInternalsUIMessageHandler::HandleAddToRequestQueue(
     const base::ListValue* args) {
-  const base::Value* callback_id;
-  CHECK(args->Get(0, &callback_id));
+  std::string callback_id;
+  CHECK(args->GetString(0, &callback_id));
 
   if (request_coordinator_) {
     std::string url;
@@ -453,14 +453,24 @@
     params.url = GURL(url);
     params.client_id = offline_pages::ClientId(offline_pages::kAsyncNamespace,
                                                id_stream.str());
-    ResolveJavascriptCallback(
-        *callback_id,
-        base::Value(request_coordinator_->SavePageLater(params) > 0));
+    request_coordinator_->SavePageLater(
+        params,
+        base::Bind(
+            &OfflineInternalsUIMessageHandler::HandleSavePageLaterCallback,
+            weak_ptr_factory_.GetWeakPtr(), callback_id));
   } else {
-    ResolveJavascriptCallback(*callback_id, base::Value(false));
+    ResolveJavascriptCallback(base::Value(callback_id), base::Value(false));
   }
 }
 
+void OfflineInternalsUIMessageHandler::HandleSavePageLaterCallback(
+    std::string callback_id,
+    offline_pages::AddRequestResult result) {
+  ResolveJavascriptCallback(
+      base::Value(callback_id),
+      base::Value(result == offline_pages::AddRequestResult::SUCCESS));
+}
+
 void OfflineInternalsUIMessageHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
       "deleteSelectedPages",
diff --git a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.h b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.h
index bace356..6092fd8 100644
--- a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.h
+++ b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.h
@@ -107,6 +107,10 @@
       std::string callback_id,
       const offline_pages::MultipleItemStatuses& results);
 
+  // Callback for SavePageLater calls.
+  void HandleSavePageLaterCallback(std::string callback_id,
+                                   offline_pages::AddRequestResult result);
+
   // Offline page model to call methods on.
   offline_pages::OfflinePageModel* offline_page_model_;
 
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc
index 2a360fd..fb26e7f 100644
--- a/chrome/browser/ui/webui/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -90,7 +90,6 @@
     {CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA, nullptr},
     {CONTENT_SETTINGS_TYPE_BLUETOOTH_GUARD, nullptr},
     {CONTENT_SETTINGS_TYPE_AUTOPLAY, nullptr},
-    {CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, nullptr},
     {CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, nullptr},
     {CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA, nullptr},
     {CONTENT_SETTINGS_TYPE_ADS_DATA, nullptr},
diff --git a/chrome/browser/vr/model/model.cc b/chrome/browser/vr/model/model.cc
index beab13f..5a802a6d 100644
--- a/chrome/browser/vr/model/model.cc
+++ b/chrome/browser/vr/model/model.cc
@@ -75,6 +75,14 @@
   return kModeBrowsing;
 }
 
+bool Model::has_mode_in_stack(UiMode mode) const {
+  for (auto stacked_mode : ui_modes) {
+    if (mode == stacked_mode)
+      return true;
+  }
+  return false;
+}
+
 bool Model::browsing_enabled() const {
   return !web_vr_enabled();
 }
diff --git a/chrome/browser/vr/model/model.h b/chrome/browser/vr/model/model.h
index 601f4fc..c79ca889 100644
--- a/chrome/browser/vr/model/model.h
+++ b/chrome/browser/vr/model/model.h
@@ -53,6 +53,7 @@
   void pop_mode(UiMode mode);
   void toggle_mode(UiMode mode);
   UiMode get_last_opaque_mode() const;
+  bool has_mode_in_stack(UiMode mode) const;
   bool browsing_enabled() const;
   bool default_browsing_enabled() const;
   bool voice_search_enabled() const;
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index fd1a0dd..5f7354b 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1482,7 +1482,6 @@
                      base::Unretained(model_)),
       VR_BIND_LAMBDA(
           [](TextInput* e, Model* m, const bool& v) {
-            m->omnibox_text_field_info = TextInputInfo();
             if (v) {
               e->RequestFocus();
             } else {
@@ -1491,11 +1490,21 @@
           },
           base::Unretained(omnibox_text_field.get()),
           base::Unretained(model_))));
+  omnibox_text_field->AddBinding(base::MakeUnique<Binding<bool>>(
+      VR_BIND_LAMBDA(
+          [](Model* m) { return m->has_mode_in_stack(kModeEditingOmnibox); },
+          base::Unretained(model_)),
+      VR_BIND_LAMBDA(
+          [](TextInput* e, Model* m, const bool& unused) {
+            m->omnibox_text_field_info = TextInputInfo();
+          },
+          base::Unretained(omnibox_text_field.get()),
+          base::Unretained(model_))));
   omnibox_text_field->AddBinding(base::MakeUnique<Binding<AutocompleteStatus>>(
       VR_BIND_LAMBDA(
           [](Model* m) {
             AutocompleteStatus state;
-            state.active = m->omnibox_editing_enabled();
+            state.active = m->has_mode_in_stack(kModeEditingOmnibox);
             state.input = m->omnibox_text_field_info.text;
             return state;
           },
@@ -1531,15 +1540,9 @@
   mic_icon_box->SetSize(kOmniboxTextFieldIconButtonSizeDMM,
                         kOmniboxTextFieldIconButtonSizeDMM);
   mic_icon_box->set_corner_radius(kOmniboxTextFieldIconButtonRadiusDMM);
-  mic_icon_box->AddBinding(base::MakeUnique<Binding<bool>>(
-      VR_BIND_LAMBDA(
-          [](Model* m) {
-            return !m->incognito &&
-                   m->speech.has_or_can_request_audio_permission;
-          },
-          base::Unretained(model_)),
-      VR_BIND_LAMBDA([](UiElement* e, const bool& v) { e->SetVisible(v); },
-                     mic_icon_box.get())));
+  VR_BIND_VISIBILITY(
+      mic_icon_box,
+      !model->incognito && model->speech.has_or_can_request_audio_permission);
   VR_BIND_BUTTON_COLORS(model_, mic_icon_box.get(),
                         &ColorScheme::omnibox_voice_search_button_colors,
                         &Button::SetButtonColors);
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 0064fc02..d08a945 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -103,6 +103,7 @@
     "attrition_experiments.h",
     "auto_start_linux.cc",
     "auto_start_linux.h",
+    "browser_controls_state_param_traits.h",
     "child_process_logging.h",
     "child_process_logging_win.cc",
     "chrome_content_client.cc",
diff --git a/chrome/common/browser_controls_state.typemap b/chrome/common/browser_controls_state.typemap
new file mode 100644
index 0000000..2fe1644
--- /dev/null
+++ b/chrome/common/browser_controls_state.typemap
@@ -0,0 +1,13 @@
+# 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.
+
+mojom = "//chrome/common/chrome_render_frame.mojom"
+public_headers = [ "//content/public/common/browser_controls_state.h" ]
+traits_headers = [ "//chrome/common/browser_controls_state_param_traits.h" ]
+public_deps = [
+  "//ipc",
+]
+
+type_mappings =
+    [ "chrome.mojom.BrowserControlsState=content::BrowserControlsState" ]
diff --git a/chrome/common/browser_controls_state_param_traits.h b/chrome/common/browser_controls_state_param_traits.h
new file mode 100644
index 0000000..27ab55b
--- /dev/null
+++ b/chrome/common/browser_controls_state_param_traits.h
@@ -0,0 +1,12 @@
+// 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 "content/public/common/browser_controls_state.h"
+#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/web/WebConsoleMessage.h"
+
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebConsoleMessage::Level,
+                          blink::WebConsoleMessage::kLevelLast)
+IPC_ENUM_TRAITS_MAX_VALUE(content::BrowserControlsState,
+                          content::BROWSER_CONTROLS_STATE_LAST)
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 83fb3f0..6bfa93f 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -483,6 +483,10 @@
 const base::Feature kSafeSearchUrlReporting{"SafeSearchUrlReporting",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether the user is prompted when sites request attestation.
+const base::Feature kSecurityKeyAttestationPrompt{
+    "SecurityKeyAttestationPrompt", base::FEATURE_DISABLED_BY_DEFAULT};
+
 #if defined(OS_MACOSX)
 // Whether to show all dialogs with toolkit-views on Mac, rather than Cocoa. A
 // subset of "pilot" dialogs can be enabled with kSecondaryUiMd.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index edc33b2..7b032d18 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -253,6 +253,8 @@
 
 extern const base::Feature kSafeSearchUrlReporting;
 
+extern const base::Feature kSecurityKeyAttestationPrompt;
+
 #if defined(OS_MACOSX)
 extern const base::Feature kShowAllDialogsWithViewsToolkit;
 #endif
diff --git a/chrome/common/chrome_render_frame.mojom b/chrome/common/chrome_render_frame.mojom
index b15b790..0e39c26 100644
--- a/chrome/common/chrome_render_frame.mojom
+++ b/chrome/common/chrome_render_frame.mojom
@@ -14,6 +14,9 @@
 };
 
 [Native]
+enum BrowserControlsState;
+
+[Native]
 struct WebApplicationInfo;
 
 // Messages sent from chrome to the render frame.
@@ -47,4 +50,13 @@
 
   // Requests the web application info from the renderer.
   GetWebApplicationInfo() => (WebApplicationInfo web_application_info);
-};
+
+  // TODO(cm.sanchi): enable below mojom only for Android once EnabledIf
+  // attribute is supported in mojom files. See https://crbug.com/676224
+  // Notifies the renderer whether hiding/showing the browser controls is
+  // enabled, what the current state should be, and whether or not to
+  // animate to the proper state.
+  UpdateBrowserControlsState(BrowserControlsState constraints,
+                             BrowserControlsState current,
+                             bool animate);
+};
\ No newline at end of file
diff --git a/chrome/common/extensions/api/cryptotoken_private.idl b/chrome/common/extensions/api/cryptotoken_private.idl
index 23544d0..0e4b70d 100644
--- a/chrome/common/extensions/api/cryptotoken_private.idl
+++ b/chrome/common/extensions/api/cryptotoken_private.idl
@@ -4,11 +4,24 @@
 
 // <code>chrome.cryptotokenPrivate</code> API that provides hooks to Chrome to
 // be used by cryptotoken component extension.
+// <p>In the context of this API, an AppId is roughly an origin and is formally
+// defined in
+// <a href="https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-appid-and-facets-v1.2-ps-20170411.html">
+// the FIDO spec</a></p>
 namespace cryptotokenPrivate {
 
   // Callback for appId check
   callback AppIdCallback = void(boolean result);
 
+  dictionary CanAppIdGetAttestationOptions {
+    // The AppId (see definition, above) that was used in the registration
+    // request and which has been authenticated by |canOriginAssertAppId|.
+    DOMString appId;
+    // Identifies the tab in which the registration is occuring so that any
+    // permissions prompt is correctly located.
+    long tabId;
+  };
+
   interface Functions {
     // Checks whether the origin is allowed to assert the appId, according to
     // the same origin policy defined at
@@ -27,5 +40,12 @@
     // use its batch attestation certificate.
     static void isAppIdHashInEnterpriseContext(ArrayBuffer appIdHash,
                                                AppIdCallback callback);
+
+    // Checks whether the given appId may receive attestation data that
+    // identifies the token. If not, the attestation from the token must be
+    // substituted with a randomly generated certificate since webauthn and U2F
+    // require that some attestation be provided.
+    static void canAppIdGetAttestation(CanAppIdGetAttestationOptions options,
+                                       AppIdCallback callback);
   };
 };
diff --git a/chrome/common/prerender_url_loader_throttle.cc b/chrome/common/prerender_url_loader_throttle.cc
index 183b318..d57ef0d 100644
--- a/chrome/common/prerender_url_loader_throttle.cc
+++ b/chrome/common/prerender_url_loader_throttle.cc
@@ -54,12 +54,6 @@
       histogram_prefix_(histogram_prefix),
       canceler_getter_(std::move(canceler_getter)),
       canceler_getter_task_runner_(canceler_getter_task_runner) {
-  if (mode_ == PREFETCH_ONLY) {
-    detached_timer_.Start(FROM_HERE,
-                          base::TimeDelta::FromMilliseconds(
-                              content::kDefaultDetachableCancelDelayMs),
-                          this, &PrerenderURLLoaderThrottle::OnTimedOut);
-  }
 }
 
 PrerenderURLLoaderThrottle::~PrerenderURLLoaderThrottle() {
@@ -119,8 +113,6 @@
     // Delay icon fetching until the contents are getting swapped in
     // to conserve network usage in mobile devices.
     *defer = true;
-
-    // No need to call AddIdleResource() on Android.
     return;
   }
 #else
@@ -137,6 +129,13 @@
     request->priority = net::IDLE;
   }
 #endif  // OS_ANDROID
+
+  if (mode_ == PREFETCH_ONLY) {
+    detached_timer_.Start(FROM_HERE,
+                          base::TimeDelta::FromMilliseconds(
+                              content::kDefaultDetachableCancelDelayMs),
+                          this, &PrerenderURLLoaderThrottle::OnTimedOut);
+  }
 }
 
 void PrerenderURLLoaderThrottle::WillRedirectRequest(
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 770ac69..5d304ee5 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -13,20 +13,19 @@
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "chrome/common/browser_controls_state_param_traits.h"
 #include "chrome/common/features.h"
 #include "chrome/common/web_application_info_provider_param_traits.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/offline_pages/features/features.h"
-#include "content/public/common/browser_controls_state.h"
 #include "content/public/common/webplugininfo.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_platform_file.h"
 #include "media/media_features.h"
 #include "ppapi/features/features.h"
-#include "third_party/WebKit/public/web/WebConsoleMessage.h"
 #include "url/gurl.h"
 #include "url/ipc/url_param_traits.h"
 #include "url/origin.h"
@@ -40,11 +39,6 @@
 
 #define IPC_MESSAGE_START ChromeMsgStart
 
-IPC_ENUM_TRAITS_MAX_VALUE(blink::WebConsoleMessage::Level,
-                          blink::WebConsoleMessage::kLevelLast)
-IPC_ENUM_TRAITS_MAX_VALUE(content::BrowserControlsState,
-                          content::BROWSER_CONTROLS_STATE_LAST)
-
 //-----------------------------------------------------------------------------
 // RenderView messages
 // These are messages sent from the browser to the renderer process.
@@ -58,14 +52,6 @@
                     int  /* request_id */,
                     bool /* allowed */)
 
-// Notifies the renderer whether hiding/showing the browser controls is enabled,
-// what the current state should be, and whether or not to animate to the
-// proper state.
-IPC_MESSAGE_ROUTED3(ChromeViewMsg_UpdateBrowserControlsState,
-                    content::BrowserControlsState /* constraints */,
-                    content::BrowserControlsState /* current */,
-                    bool /* animate */)
-
 // JavaScript related messages -----------------------------------------------
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index 80520c8f..690106a 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -465,3 +465,16 @@
   render_frame()->GetRenderView()->GetWebView()->SetWindowFeatures(
       content::ConvertMojoWindowFeaturesToWebWindowFeatures(*window_features));
 }
+
+void ChromeRenderFrameObserver::UpdateBrowserControlsState(
+    content::BrowserControlsState constraints,
+    content::BrowserControlsState current,
+    bool animate) {
+#if defined(OS_ANDROID)
+  render_frame()->GetRenderView()->UpdateBrowserControlsState(constraints,
+                                                              current, animate);
+#else
+  // TODO(https://crbug.com/676224): remove this reporting.
+  mojo::ReportBadMessage("UpdateBrowserControlsState is OS_ANDROID only.");
+#endif
+}
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h
index 954d76b..55deaea8 100644
--- a/chrome/renderer/chrome_render_frame_observer.h
+++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -29,9 +29,8 @@
 
 // This class holds the Chrome specific parts of RenderFrame, and has the same
 // lifetime.
-class ChromeRenderFrameObserver
-    : public content::RenderFrameObserver,
-      public chrome::mojom::ChromeRenderFrame {
+class ChromeRenderFrameObserver : public content::RenderFrameObserver,
+                                  public chrome::mojom::ChromeRenderFrame {
  public:
   explicit ChromeRenderFrameObserver(content::RenderFrame* render_frame);
   ~ChromeRenderFrameObserver() override;
@@ -77,6 +76,9 @@
   void SetClientSidePhishingDetection(bool enable_phishing_detection) override;
   void GetWebApplicationInfo(
       const GetWebApplicationInfoCallback& callback) override;
+  void UpdateBrowserControlsState(content::BrowserControlsState constraints,
+                                  content::BrowserControlsState current,
+                                  bool animate) override;
 
   void OnRenderFrameObserverRequest(
       chrome::mojom::ChromeRenderFrameAssociatedRequest request);
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index 5d11074..f38858c 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -4,40 +4,7 @@
 
 #include "chrome/renderer/chrome_render_view_observer.h"
 
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/debug/crash_logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-#include "chrome/common/crash_keys.h"
-#include "chrome/common/render_messages.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/renderer/prerender/prerender_helper.h"
 #include "components/web_cache/renderer/web_cache_impl.h"
-#include "content/public/common/bindings_policy.h"
-#include "content/public/renderer/content_renderer_client.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_view.h"
-#include "extensions/features/features.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-#include "third_party/WebKit/public/web/WebView.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "chrome/common/extensions/chrome_extension_messages.h"
-#endif
-
-using blink::WebFrame;
-using blink::WebLocalFrame;
-using blink::WebWindowFeatures;
 
 ChromeRenderViewObserver::ChromeRenderViewObserver(
     content::RenderView* render_view,
@@ -48,29 +15,6 @@
 ChromeRenderViewObserver::~ChromeRenderViewObserver() {
 }
 
-bool ChromeRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
-#if defined(OS_ANDROID)
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ChromeRenderViewObserver, message)
-    IPC_MESSAGE_HANDLER(ChromeViewMsg_UpdateBrowserControlsState,
-                        OnUpdateBrowserControlsState)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-#else
-  return false;
-#endif
-}
-
-#if defined(OS_ANDROID)
-void ChromeRenderViewObserver::OnUpdateBrowserControlsState(
-    content::BrowserControlsState constraints,
-    content::BrowserControlsState current,
-    bool animate) {
-  render_view()->UpdateBrowserControlsState(constraints, current, animate);
-}
-#endif
-
 void ChromeRenderViewObserver::Navigate(const GURL& url) {
   // Execute cache clear operations that were postponed until a navigation
   // event (including tab reload).
diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h
index bcf065ee..c6090ea6 100644
--- a/chrome/renderer/chrome_render_view_observer.h
+++ b/chrome/renderer/chrome_render_view_observer.h
@@ -5,16 +5,11 @@
 #ifndef CHROME_RENDERER_CHROME_RENDER_VIEW_OBSERVER_H_
 #define CHROME_RENDERER_CHROME_RENDER_VIEW_OBSERVER_H_
 
-#include <set>
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
-#include "base/timer/timer.h"
-#include "build/build_config.h"
 #include "content/public/common/browser_controls_state.h"
 #include "content/public/renderer/render_view_observer.h"
-#include "extensions/features/features.h"
 #include "url/gurl.h"
 
 namespace web_cache {
@@ -33,16 +28,9 @@
 
  private:
   // RenderViewObserver implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
   void Navigate(const GURL& url) override;
   void OnDestruct() override;
 
-#if defined(OS_ANDROID)
-  void OnUpdateBrowserControlsState(content::BrowserControlsState constraints,
-                                    content::BrowserControlsState current,
-                                    bool animate);
-#endif
-
   // Determines if a host is in the strict security host set.
   bool IsStrictSecurityHost(const std::string& host);
 
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/add_watcher/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/add_watcher/manifest.json
index b079405..5b2a56d 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/add_watcher/manifest.json
+++ b/chrome/test/data/extensions/api_test/file_system_provider/add_watcher/manifest.json
@@ -14,7 +14,8 @@
     "fileManagerPrivate"
   ],
   "file_system_provider_capabilities": {
-    "source": "device"
+    "source": "device",
+    "watchable": true
   },
   "app": {
     "background": {
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/notify/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/notify/manifest.json
index 90e4c0a..e0dbae2 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/notify/manifest.json
+++ b/chrome/test/data/extensions/api_test/file_system_provider/notify/manifest.json
@@ -14,7 +14,8 @@
     "fileManagerPrivate"
   ],
   "file_system_provider_capabilities": {
-    "source": "device"
+    "source": "device",
+    "watchable": true
   },
   "app": {
     "background": {
diff --git a/chrome/test/data/extensions/api_test/file_system_provider/remove_watcher/manifest.json b/chrome/test/data/extensions/api_test/file_system_provider/remove_watcher/manifest.json
index e2aab8f..0d595ac 100644
--- a/chrome/test/data/extensions/api_test/file_system_provider/remove_watcher/manifest.json
+++ b/chrome/test/data/extensions/api_test/file_system_provider/remove_watcher/manifest.json
@@ -14,7 +14,8 @@
     "fileManagerPrivate"
   ],
   "file_system_provider_capabilities": {
-    "source": "device"
+    "source": "device",
+    "watchable": true
   },
   "app": {
     "background": {
diff --git a/chrome/test/data/extensions/api_test/webrequest/devtoolsfrontend/fakedevtools.html b/chrome/test/data/extensions/api_test/webrequest/devtoolsfrontend/fakedevtools.html
new file mode 100644
index 0000000..49feb904
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/devtoolsfrontend/fakedevtools.html
@@ -0,0 +1,9 @@
+<!--
+ * 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.
+-->
+<!DOCTYPE html>
+Fake devtools page. If the reference fragment is set to a URL, this page will
+navigate to the given URL.
+<script src="fakedevtools.js"></script>
diff --git a/chrome/test/data/extensions/api_test/webrequest/devtoolsfrontend/fakedevtools.js b/chrome/test/data/extensions/api_test/webrequest/devtoolsfrontend/fakedevtools.js
new file mode 100644
index 0000000..6d7bc0a6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/devtoolsfrontend/fakedevtools.js
@@ -0,0 +1,17 @@
+// 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.
+
+window.onload = function() {
+  if (location.hash) {
+    var completionUrl = new URL(location.hash.slice(1)).href;
+
+    console.log(
+        'Fake devtools loaded. Going to notify test extension via ' +
+        completionUrl);
+
+    // Cannot do "location.href = completionUrl" because chrome-devtools://...
+    // disallows top-level navigation to a non-chrome-devtools:-URL.
+    new Image().src = completionUrl;
+  }
+};
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_devtools.html b/chrome/test/data/extensions/api_test/webrequest/test_devtools.html
new file mode 100644
index 0000000..efc6b5af
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/test_devtools.html
@@ -0,0 +1,9 @@
+<!--
+ * 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.
+-->
+<body>
+  <script src="framework.js"></script>
+  <script src="test_devtools.js"></script>
+</body>
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_devtools.js b/chrome/test/data/extensions/api_test/webrequest/test_devtools.js
new file mode 100644
index 0000000..acbd442
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/webrequest/test_devtools.js
@@ -0,0 +1,328 @@
+// 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.
+
+// To debug failing tests, we need to see all observed requests in order to
+// determine whether an unexpected request was received (which suggests that the
+// implementation is broken) or whether an expected event was observed too early
+// (which can be an indication of unreasonable test expectations
+// suggests that some previous events were hidden, indicating a broken test).
+// To do so, we override logAllRequests=false from framework.js.
+logAllRequests = true;
+
+// The URL that fakedevtools.html requests upon completion. This is used to
+// detect when the DevTools resource has finished loading, because the requested
+// front-end resources should not be visible in the webRequest API.
+function getCompletionURL() {
+  // We do not care about the exact events, so use a non-existing extension
+  // resource because it produces only two events: onBeforeRequest and
+  // onErrorOccurred.
+  return getURL('does_not_exist.html');
+}
+
+// The expected events when fakedevtools.html requests to |getCompletionURL()|.
+function expectCompletionEvents() {
+  // These events are expected to occur. If that does not happen, check whether
+  // fakedevtools.html was actually loaded via the chrome-devtools:-URL.
+  expect(
+      [
+        {
+          label: 'onBeforeRequest',
+          event: 'onBeforeRequest',
+          details: {
+            type: 'image',
+            url: getURL('does_not_exist.html'),
+            frameUrl: 'unknown frame URL',
+          },
+        },
+        {
+          label: 'onErrorOccurred',
+          event: 'onErrorOccurred',
+          details: {
+            type: 'image',
+            url: getURL('does_not_exist.html'),
+            fromCache: false,
+            error: 'net::ERR_FILE_NOT_FOUND',
+          }
+        },
+      ],
+      [['onBeforeRequest', 'onErrorOccurred']]);
+}
+
+function expectNormalTabNavigationEvents(url) {
+  var scriptUrl = new URL(url);
+  var frontendHost = scriptUrl.hostname;
+  scriptUrl.search = scriptUrl.hash = '';
+  scriptUrl.pathname = scriptUrl.pathname.replace(/\.html$/, '.js');
+  scriptUrl = scriptUrl.href;
+
+  expect(
+      [
+        {
+          label: 'onBeforeRequest-1',
+          event: 'onBeforeRequest',
+          details: {
+            type: 'main_frame',
+            url,
+            frameUrl: url,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onBeforeSendHeaders-1',
+          event: 'onBeforeSendHeaders',
+          details: {
+            type: 'main_frame',
+            url,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onSendHeaders-1',
+          event: 'onSendHeaders',
+          details: {
+            type: 'main_frame',
+            url,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onHeadersReceived-1',
+          event: 'onHeadersReceived',
+          details: {
+            type: 'main_frame',
+            url,
+            statusLine: 'HTTP/1.1 200 OK',
+            statusCode: 200,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onResponseStarted-1',
+          event: 'onResponseStarted',
+          details: {
+            type: 'main_frame',
+            url,
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onCompleted-1',
+          event: 'onCompleted',
+          details: {
+            type: 'main_frame',
+            url,
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onBeforeRequest-2',
+          event: 'onBeforeRequest',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            frameUrl: url,
+            initiator: getServerDomain(initiators.WEB_INITIATED, frontendHost)
+          }
+        },
+        {
+          label: 'onBeforeSendHeaders-2',
+          event: 'onBeforeSendHeaders',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            initiator: getServerDomain(initiators.WEB_INITIATED, frontendHost)
+          }
+        },
+        {
+          label: 'onSendHeaders-2',
+          event: 'onSendHeaders',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            initiator: getServerDomain(initiators.WEB_INITIATED, frontendHost)
+          }
+        },
+        {
+          label: 'onHeadersReceived-2',
+          event: 'onHeadersReceived',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            statusLine: 'HTTP/1.1 200 OK',
+            statusCode: 200,
+            initiator: getServerDomain(initiators.WEB_INITIATED, frontendHost)
+          }
+        },
+        {
+          label: 'onResponseStarted-2',
+          event: 'onResponseStarted',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            initiator: getServerDomain(initiators.WEB_INITIATED, frontendHost)
+          }
+        },
+        {
+          label: 'onCompleted-2',
+          event: 'onCompleted',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            statusCode: 200,
+            ip: '127.0.0.1',
+            fromCache: false,
+            statusLine: 'HTTP/1.1 200 OK',
+            initiator: getServerDomain(initiators.WEB_INITIATED, frontendHost)
+          }
+        },
+      ],
+      [[
+        'onBeforeRequest-1', 'onBeforeSendHeaders-1', 'onSendHeaders-1',
+        'onHeadersReceived-1', 'onResponseStarted-1', 'onCompleted-1',
+        'onBeforeRequest-2', 'onBeforeSendHeaders-2', 'onSendHeaders-2',
+        'onHeadersReceived-2', 'onResponseStarted-2', 'onCompleted-2'
+      ]]);
+}
+
+// When the response is mocked via URLRequestMockHTTPJob, then the response
+// differs from reality. Notably all header-related events are missing, the
+// HTTP status line is different and the IP is missing.
+// This difference is not a problem, since we are primarily interested in
+// determining whether a request was observed or not.
+function expectMockedTabNavigationEvents(url) {
+  var scriptUrl = new URL(url);
+  var frontendOrigin = scriptUrl.origin;
+  scriptUrl.search = scriptUrl.hash = '';
+  scriptUrl.pathname = scriptUrl.pathname.replace(/\.html$/, '.js');
+  scriptUrl = scriptUrl.href;
+
+  expect(
+      [
+        {
+          label: 'onBeforeRequest-1',
+          event: 'onBeforeRequest',
+          details: {
+            type: 'main_frame',
+            url,
+            frameUrl: url,
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onResponseStarted-1',
+          event: 'onResponseStarted',
+          details: {
+            type: 'main_frame',
+            url,
+            statusCode: 200,
+            fromCache: false,
+            statusLine: 'HTTP/1.0 200 OK',
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onCompleted-1',
+          event: 'onCompleted',
+          details: {
+            type: 'main_frame',
+            url,
+            statusCode: 200,
+            fromCache: false,
+            statusLine: 'HTTP/1.0 200 OK',
+            initiator: getServerDomain(initiators.BROWSER_INITIATED)
+          }
+        },
+        {
+          label: 'onBeforeRequest-2',
+          event: 'onBeforeRequest',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            frameUrl: url,
+            // Cannot use getServerDomain(initiators.WEB_INITIATED) because it
+            // always adds a port, while this request does not have any ports.
+            initiator: frontendOrigin
+          }
+        },
+        {
+          label: 'onResponseStarted-2',
+          event: 'onResponseStarted',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            statusCode: 200,
+            fromCache: false,
+            statusLine: 'HTTP/1.0 200 OK',
+            initiator: frontendOrigin
+          }
+        },
+        {
+          label: 'onCompleted-2',
+          event: 'onCompleted',
+          details: {
+            type: 'script',
+            url: scriptUrl,
+            statusCode: 200,
+            fromCache: false,
+            statusLine: 'HTTP/1.0 200 OK',
+            initiator: frontendOrigin
+          }
+        },
+      ],
+      [[
+        'onBeforeRequest-1', 'onResponseStarted-1', 'onCompleted-1',
+        'onBeforeRequest-2', 'onResponseStarted-2', 'onCompleted-2'
+      ]]);
+}
+
+runTests([
+  // Tests that chrome-devtools://devtools/custom/ is hidden from webRequest.
+  function testDevToolsCustomFrontendRequest() {
+    expectCompletionEvents();
+    // DevToolsFrontendInWebRequestApuTest has set the kCustomDevtoolsFrontend
+    // switch to the customfrontend/ subdirectory, so we do not include the path
+    // name in the URL again.
+    navigateAndWait(
+        'chrome-devtools://devtools/custom/fakedevtools.html#' +
+        getCompletionURL());
+  },
+
+  // Tests that the custom front-end URL is visible in non-DevTools requests.
+  function testNonDevToolsCustomFrontendRequest() {
+    // The URL that would be loaded by chrome-devtools://devtools/custom/...
+    var customFrontendUrl = getServerURL(
+        'devtoolsfrontend/fakedevtools.html', 'customfrontend.example.com');
+    expectNormalTabNavigationEvents(customFrontendUrl);
+    navigateAndWait(customFrontendUrl);
+  },
+
+  // Tests that chrome-devtools://devtools/remote/ is hidden from webRequest.
+  function testDevToolsRemoteFrontendRequest() {
+    expectCompletionEvents();
+    navigateAndWait(
+        'chrome-devtools://devtools/remote/devtoolsfrontend/fakedevtools.html' +
+        '#' + getCompletionURL());
+  },
+
+  // Tests that the custom front-end URL is visible in non-DevTools requests.
+  function testNonDevToolsRemoteFrontendRequest() {
+    // The URL that would be loaded by chrome-devtools://devtools/remote/...
+    var remoteFrontendUrl = 'https://chrome-devtools-frontend.appspot.com/' +
+        'devtoolsfrontend/fakedevtools.html';
+    expectMockedTabNavigationEvents(remoteFrontendUrl);
+    navigateAndWait(remoteFrontendUrl);
+  },
+]);
diff --git a/chrome/typemaps.gni b/chrome/typemaps.gni
index 67d11fb..d9a9bd7 100644
--- a/chrome/typemaps.gni
+++ b/chrome/typemaps.gni
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 typemaps = [
+  "//chrome/common/browser_controls_state.typemap",
   "//chrome/common/search.typemap",
   "//chrome/common/web_application_info_provider.typemap",
   "//chrome/services/file_util/public/interfaces/safe_archive_analyzer.typemap",
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc
index 23f21fea..62834c2 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -236,29 +236,6 @@
   prefs_->ClearPref(kObsoleteMouseLockExceptionsPref);
 #endif  // !defined(OS_ANDROID)
 #endif  // !defined(OS_IOS)
-
-#if !defined(OS_IOS)
-  // Migrate CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT to
-  // CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA.
-  // TODO(raymes): See crbug.com/681709. Remove after M60.
-  const std::string prompt_no_decision_count_pref =
-      WebsiteSettingsRegistry::GetInstance()
-          ->Get(CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT)
-          ->pref_name();
-  const base::DictionaryValue* old_dict =
-      prefs_->GetDictionary(prompt_no_decision_count_pref);
-
-  const std::string permission_autoblocker_data_pref =
-      WebsiteSettingsRegistry::GetInstance()
-          ->Get(CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA)
-          ->pref_name();
-  const base::DictionaryValue* new_dict =
-      prefs_->GetDictionary(permission_autoblocker_data_pref);
-
-  if (!old_dict->empty() && new_dict->empty())
-    prefs_->Set(permission_autoblocker_data_pref, *old_dict);
-  prefs_->ClearPref(prompt_no_decision_count_pref);
-#endif  // !defined(OS_IOS)
 }
 
 void PrefProvider::SetClockForTesting(base::Clock* clock) {
diff --git a/components/content_settings/core/browser/website_settings_registry.cc b/components/content_settings/core/browser/website_settings_registry.cc
index 2987e16..b33ded9 100644
--- a/components/content_settings/core/browser/website_settings_registry.cc
+++ b/components/content_settings/core/browser/website_settings_registry.cc
@@ -147,13 +147,6 @@
            WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE,
            DESKTOP | PLATFORM_ANDROID,
            WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
-  // TODO(raymes): Deprecated. See crbug.com/681709. Remove after M60.
-  Register(CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
-           "prompt-no-decision-count", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
-           WebsiteSettingsInfo::NOT_LOSSY,
-           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
-           DESKTOP | PLATFORM_ANDROID,
-           WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
   Register(CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO, "important-site-info",
            nullptr, WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
            WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h
index 1f71c909..ef4c1f0 100644
--- a/components/content_settings/core/common/content_settings_types.h
+++ b/components/content_settings/core/common/content_settings_types.h
@@ -43,8 +43,6 @@
   CONTENT_SETTINGS_TYPE_BLUETOOTH_GUARD,
   CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC,
   CONTENT_SETTINGS_TYPE_AUTOPLAY,
-  // TODO(raymes): Deprecated. See crbug.com/681709. Remove after M60.
-  CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT,
   CONTENT_SETTINGS_TYPE_IMPORTANT_SITE_INFO,
   CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA,
   CONTENT_SETTINGS_TYPE_ADS,
diff --git a/components/offline_pages/core/background/request_coordinator.cc b/components/offline_pages/core/background/request_coordinator.cc
index b5eb604..ecce5eee 100644
--- a/components/offline_pages/core/background/request_coordinator.cc
+++ b/components/offline_pages/core/background/request_coordinator.cc
@@ -248,12 +248,16 @@
 RequestCoordinator::~RequestCoordinator() {}
 
 int64_t RequestCoordinator::SavePageLater(
-    const SavePageLaterParams& save_page_later_params) {
+    const SavePageLaterParams& save_page_later_params,
+    const SavePageLaterCallback& save_page_later_callback) {
   DVLOG(2) << "URL is " << save_page_later_params.url << " " << __func__;
 
   if (!OfflinePageModel::CanSaveURL(save_page_later_params.url)) {
     DVLOG(1) << "Not able to save page for requested url: "
              << save_page_later_params.url;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(save_page_later_callback, AddRequestResult::URL_ERROR));
     return 0L;
   }
 
@@ -274,10 +278,11 @@
   }
 
   // Put the request on the request queue.
-  queue_->AddRequest(request,
-                     base::Bind(&RequestCoordinator::AddRequestResultCallback,
-                                weak_ptr_factory_.GetWeakPtr(),
-                                save_page_later_params.availability));
+  queue_->AddRequest(
+      request,
+      base::Bind(&RequestCoordinator::AddRequestResultCallback,
+                 weak_ptr_factory_.GetWeakPtr(), save_page_later_callback,
+                 save_page_later_params.availability));
 
   // Record the network quality when this request is made.
   if (network_quality_estimator_) {
@@ -487,6 +492,7 @@
 }
 
 void RequestCoordinator::AddRequestResultCallback(
+    const SavePageLaterCallback& save_page_later_callback,
     RequestAvailability availability,
     AddRequestResult result,
     const SavePageRequest& request) {
@@ -505,6 +511,8 @@
   } else if (request.user_requested()) {
     StartImmediatelyIfConnected();
   }
+
+  save_page_later_callback.Run(result);
 }
 
 void RequestCoordinator::UpdateMultipleRequestsCallback(
diff --git a/components/offline_pages/core/background/request_coordinator.h b/components/offline_pages/core/background/request_coordinator.h
index a113156..adf2adbe 100644
--- a/components/offline_pages/core/background/request_coordinator.h
+++ b/components/offline_pages/core/background/request_coordinator.h
@@ -107,6 +107,9 @@
   // Callback for stopping the background offlining.
   typedef base::Callback<void(int64_t request_id)> CancelCallback;
 
+  // Callback for SavePageLater calls.
+  typedef base::Callback<void(AddRequestResult)> SavePageLaterCallback;
+
   RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy,
                      std::unique_ptr<Offliner> offliner,
                      std::unique_ptr<RequestQueue> queue,
@@ -119,7 +122,8 @@
 
   // Queues |request| to later load and save when system conditions allow.
   // Returns an id if the page could be queued successfully, 0L otherwise.
-  int64_t SavePageLater(const SavePageLaterParams& save_page_later_params);
+  int64_t SavePageLater(const SavePageLaterParams& save_page_later_params,
+                        const SavePageLaterCallback& save_page_later_callback);
 
   // Remove a list of requests by |request_id|.  This removes requests from the
   // request queue, and cancels an in-progress offliner.
@@ -274,9 +278,11 @@
       std::vector<std::unique_ptr<SavePageRequest>> requests);
 
   // Receives the result of add requests to the request queue.
-  void AddRequestResultCallback(RequestAvailability availability,
-                                AddRequestResult result,
-                                const SavePageRequest& request);
+  void AddRequestResultCallback(
+      const SavePageLaterCallback& save_page_later_callback,
+      RequestAvailability availability,
+      AddRequestResult result,
+      const SavePageRequest& request);
 
   void UpdateMultipleRequestsCallback(
       std::unique_ptr<UpdateRequestsResult> result);
diff --git a/components/offline_pages/core/background/request_coordinator_unittest.cc b/components/offline_pages/core/background/request_coordinator_unittest.cc
index d3c6dfd..9e50875 100644
--- a/components/offline_pages/core/background/request_coordinator_unittest.cc
+++ b/components/offline_pages/core/background/request_coordinator_unittest.cc
@@ -263,13 +263,20 @@
 
   SavePageRequest AddRequest2();
 
+  void SavePageRequestCallback(AddRequestResult result) {
+    ASSERT_EQ(expected_add_request_result_, result);
+    add_request_callback_called_ = true;
+  }
+
   int64_t SavePageLater() {
     RequestCoordinator::SavePageLaterParams params;
     params.url = kUrl1;
     params.client_id = kClientId1;
     params.user_requested = kUserRequested;
     params.request_origin = kRequestOrigin;
-    return coordinator()->SavePageLater(params);
+    return coordinator()->SavePageLater(
+        params, base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
+                           base::Unretained(this)));
   }
 
   int64_t SavePageLaterWithAvailability(
@@ -280,7 +287,9 @@
     params.user_requested = kUserRequested;
     params.availability = availability;
     params.request_origin = kRequestOrigin;
-    return coordinator()->SavePageLater(params);
+    return coordinator()->SavePageLater(
+        params, base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
+                           base::Unretained(this)));
   }
 
   Offliner::RequestStatus last_offlining_status() const {
@@ -318,6 +327,8 @@
     return coordinator()->prioritized_requests_;
   }
 
+  bool add_request_callback_called() { return add_request_callback_called_; }
+
  private:
   GetRequestsResult last_get_requests_result_;
   MultipleItemStatuses last_remove_results_;
@@ -329,6 +340,8 @@
   OfflinerStub* offliner_;
   base::WaitableEvent waiter_;
   ObserverStub observer_;
+  AddRequestResult expected_add_request_result_;
+  bool add_request_callback_called_;
   bool processing_callback_called_;
   bool processing_callback_result_;
   DeviceConditions device_conditions_;
@@ -344,6 +357,8 @@
       offliner_(nullptr),
       waiter_(base::WaitableEvent::ResetPolicy::MANUAL,
               base::WaitableEvent::InitialState::NOT_SIGNALED),
+      expected_add_request_result_(AddRequestResult::SUCCESS),
+      add_request_callback_called_(false),
       processing_callback_called_(false),
       processing_callback_result_(false),
       device_conditions_(!kPowerRequired,
@@ -569,7 +584,10 @@
   params.client_id = kClientId1;
   params.original_url = kUrl2;
   params.request_origin = kRequestOrigin;
-  EXPECT_NE(0, coordinator()->SavePageLater(params));
+  EXPECT_NE(0, coordinator()->SavePageLater(
+                   params,
+                   base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
+                              base::Unretained(this))));
 
   // Expect that a request got placed on the queue.
   coordinator()->queue()->GetRequests(base::Bind(
@@ -581,6 +599,7 @@
   // Wait for callbacks to finish, both request queue and offliner.
   PumpLoop();
   EXPECT_TRUE(processing_callback_called());
+  EXPECT_TRUE(add_request_callback_called());
 
   // Check the request queue is as expected.
   ASSERT_EQ(1UL, last_requests().size());
@@ -634,6 +653,7 @@
     EXPECT_TRUE(processing_callback_result());
   }
 
+  EXPECT_TRUE(add_request_callback_called());
   // Check the request queue is as expected.
   EXPECT_EQ(1UL, last_requests().size());
   EXPECT_EQ(kUrl1, last_requests().at(0)->url());
@@ -1411,7 +1431,10 @@
   params.url = kUrl2;
   params.client_id = kClientId2;
   params.user_requested = kUserRequested;
-  EXPECT_NE(0, coordinator()->SavePageLater(params));
+  EXPECT_NE(0, coordinator()->SavePageLater(
+                   params,
+                   base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
+                              base::Unretained(this))));
   PumpLoop();
 
   // Verify immediate processing did start this time.
diff --git a/components/offline_pages/core/background/request_queue_results.h b/components/offline_pages/core/background/request_queue_results.h
index 5468fd2e..4789634 100644
--- a/components/offline_pages/core/background/request_queue_results.h
+++ b/components/offline_pages/core/background/request_queue_results.h
@@ -25,6 +25,7 @@
   ALREADY_EXISTS,
   REQUEST_QUOTA_HIT,  // Cannot add a request with this namespace, as it has
                       // reached a quota of active requests.
+  URL_ERROR,          // Cannot save this URL.
 };
 
 // GENERATED_JAVA_ENUM_PACKAGE:org.chromium.components.offlinepages.background
diff --git a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
index a5adafdb..0ad63ef7 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -258,12 +258,15 @@
   task_runner_->RunUntilIdle();
 }
 
+void SavePageLaterCallback(AddRequestResult ignored) {}
+
 int64_t DownloadUIAdapterTest::AddRequest(const GURL& url,
                                           const ClientId& client_id) {
   RequestCoordinator::SavePageLaterParams params;
   params.url = url;
   params.client_id = client_id;
-  return request_coordinator()->SavePageLater(params);
+  return request_coordinator()->SavePageLater(
+      params, base::Bind(&SavePageLaterCallback));
 }
 
 TEST_F(DownloadUIAdapterTest, InitialLoad) {
diff --git a/components/search_provider_logos/google_logo_api.cc b/components/search_provider_logos/google_logo_api.cc
index d85ad36..43c9d1bc 100644
--- a/components/search_provider_logos/google_logo_api.cc
+++ b/components/search_provider_logos/google_logo_api.cc
@@ -26,6 +26,10 @@
 namespace search_provider_logos {
 
 namespace {
+
+const int kDefaultIframeWidthPx = 500;
+const int kDefaultIframeHeightPx = 200;
+
 // Appends the provided |value| to the "async" query param, according to the
 // format used by the Google doodle servers: "async=param:value,other:foo"
 // Derived from net::AppendOrReplaceQueryParameter, that can't be used because
@@ -181,7 +185,7 @@
   }
 
   const bool is_animated = (logo->metadata.type == LogoType::ANIMATED);
-  const bool is_interactive = (logo->metadata.type == LogoType::INTERACTIVE);
+  bool is_interactive = (logo->metadata.type == LogoType::INTERACTIVE);
 
   // Check if the main image is animated.
   if (is_animated) {
@@ -242,9 +246,21 @@
         (behavior == "NEW_WINDOW")) {
       logo->metadata.type = LogoType::SIMPLE;
       logo->metadata.on_click_url = logo->metadata.full_page_url;
+      is_interactive = false;
     }
   }
 
+  logo->metadata.iframe_width_px = 0;
+  logo->metadata.iframe_height_px = 0;
+  if (is_interactive) {
+    if (!ddljson->GetInteger("iframe_width_px",
+                             &logo->metadata.iframe_width_px))
+      logo->metadata.iframe_width_px = kDefaultIframeWidthPx;
+    if (!ddljson->GetInteger("iframe_height_px",
+                             &logo->metadata.iframe_height_px))
+      logo->metadata.iframe_height_px = kDefaultIframeHeightPx;
+  }
+
   base::TimeDelta time_to_live;
   // The JSON doesn't guarantee the number to fit into an int.
   double ttl_ms = 0;  // Expires immediately if the parameter is missing.
diff --git a/components/search_provider_logos/google_logo_api_unittest.cc b/components/search_provider_logos/google_logo_api_unittest.cc
index 8bffa8a..599df1d 100644
--- a/components/search_provider_logos/google_logo_api_unittest.cc
+++ b/components/search_provider_logos/google_logo_api_unittest.cc
@@ -116,7 +116,9 @@
   "ddljson": {
     "doodle_type": "INTERACTIVE",
     "target_url": "http://www.doodle.com/target",
-    "fullpage_interactive_url": "http://www.doodle.com/interactive"
+    "fullpage_interactive_url": "http://www.doodle.com/interactive",
+    "iframe_width_px": 500,
+    "iframe_height_px": 200
   }
 })json";
 
@@ -139,7 +141,9 @@
   "ddljson": {
     "doodle_type": "INTERACTIVE",
     "target_url": "http://www.doodle.com/target",
-    "fullpage_interactive_url": "http://www.doodle.com/interactive"
+    "fullpage_interactive_url": "http://www.doodle.com/interactive",
+    "iframe_width_px": 500,
+    "iframe_height_px": 200
   }
 })json";
 
@@ -212,7 +216,9 @@
   "ddljson": {
     "doodle_type": "INTERACTIVE",
     "fullpage_interactive_url": "/fullpage",
-    "target_url": "/target"
+    "target_url": "/target",
+    "iframe_width_px": 500,
+    "iframe_height_px": 200
   }
 })json";
 
@@ -224,6 +230,8 @@
   ASSERT_TRUE(logo);
   EXPECT_EQ(GURL("https://base.doo/fullpage"), logo->metadata.full_page_url);
   EXPECT_EQ(LogoType::INTERACTIVE, logo->metadata.type);
+  EXPECT_EQ(500, logo->metadata.iframe_width_px);
+  EXPECT_EQ(200, logo->metadata.iframe_height_px);
 }
 
 TEST(GoogleNewLogoApiTest, ParsesInteractiveDoodleWithNewWindowAsSimple) {
@@ -236,7 +244,9 @@
         "target_url": "/search?q=interactive",
         "fullpage_interactive_url": "/play",
         "launch_interactive_behavior": "NEW_WINDOW",
-        "data_uri": "data:image/png;base64,YWJj"
+        "data_uri": "data:image/png;base64,YWJj",
+        "iframe_width_px": 500,
+        "iframe_height_px": 200
       }
     })json";
 
@@ -249,9 +259,34 @@
   EXPECT_EQ(LogoType::SIMPLE, logo->metadata.type);
   EXPECT_EQ(GURL("https://base.doo/play"), logo->metadata.on_click_url);
   EXPECT_EQ(GURL("https://base.doo/play"), logo->metadata.full_page_url);
+  EXPECT_EQ(0, logo->metadata.iframe_width_px);
+  EXPECT_EQ(0, logo->metadata.iframe_height_px);
   EXPECT_EQ("abc", logo->encoded_image->data());
 }
 
+TEST(GoogleNewLogoApiTest, DefaultsInteractiveIframeSize) {
+  const GURL base_url("https://base.doo/");
+  const std::string json = R"json()]}'
+    {
+      "ddljson": {
+        "doodle_type": "INTERACTIVE",
+        "target_url": "/search?q=interactive",
+        "fullpage_interactive_url": "/play"
+      }
+    })json";
+
+  bool failed = false;
+  std::unique_ptr<EncodedLogo> logo = ParseDoodleLogoResponse(
+      base_url, std::make_unique<std::string>(json), base::Time(), &failed);
+
+  ASSERT_FALSE(failed);
+  ASSERT_TRUE(logo);
+  EXPECT_EQ(LogoType::INTERACTIVE, logo->metadata.type);
+  EXPECT_EQ(GURL("https://base.doo/play"), logo->metadata.full_page_url);
+  EXPECT_EQ(500, logo->metadata.iframe_width_px);
+  EXPECT_EQ(200, logo->metadata.iframe_height_px);
+}
+
 TEST(GoogleNewLogoApiTest, ParsesCapturedApiResult) {
   const GURL base_url("https://base.doo/");
 
diff --git a/components/search_provider_logos/logo_common.h b/components/search_provider_logos/logo_common.h
index d3cb6de9..fdc20e24 100644
--- a/components/search_provider_logos/logo_common.h
+++ b/components/search_provider_logos/logo_common.h
@@ -65,6 +65,11 @@
   // SIMPLE, INTERACTIVE: not used.
   GURL animated_url;
 
+  // SIMPLE, ANIMATED: ignored
+  // INTERACTIVE: appropriate dimensions for the iframe.
+  int iframe_width_px;
+  int iframe_height_px;
+
   // For use by LogoService ---------------------------------------------------
 
   // The URL from which the logo was downloaded (without the fingerprint param).
diff --git a/components/security_interstitials/core/ssl_error_ui.cc b/components/security_interstitials/core/ssl_error_ui.cc
index c8126c07..5fc7a31 100644
--- a/components/security_interstitials/core/ssl_error_ui.cc
+++ b/components/security_interstitials/core/ssl_error_ui.cc
@@ -15,7 +15,7 @@
 namespace security_interstitials {
 namespace {
 
-// Path to the relevant help center page.
+// Path to the relevant help center page. Used if |support_url_| is invalid.
 const char kHelpPath[] = "answer/6098869";
 
 bool IsMasked(int options, SSLErrorUI::SSLErrorOptionsMask mask) {
@@ -29,11 +29,13 @@
                        const net::SSLInfo& ssl_info,
                        int display_options,
                        const base::Time& time_triggered,
+                       const GURL& support_url,
                        ControllerClient* controller)
     : request_url_(request_url),
       cert_error_(cert_error),
       ssl_info_(ssl_info),
       time_triggered_(time_triggered),
+      support_url_(support_url),
       requested_strict_enforcement_(
           IsMasked(display_options, STRICT_ENFORCEMENT)),
       soft_override_enabled_(IsMasked(display_options, SOFT_OVERRIDE_ENABLED)),
@@ -190,8 +192,12 @@
     case CMD_OPEN_HELP_CENTER:
       controller_->metrics_helper()->RecordUserInteraction(
           security_interstitials::MetricsHelper::SHOW_LEARN_MORE);
+
+      // If |support_url_| is invalid, use the default help center url.
       controller_->OpenUrlInNewForegroundTab(
-          controller_->GetBaseHelpCenterUrl().Resolve(kHelpPath));
+          support_url_.is_valid()
+              ? support_url_
+              : controller_->GetBaseHelpCenterUrl().Resolve(kHelpPath));
       break;
     case CMD_RELOAD:
       controller_->metrics_helper()->RecordUserInteraction(
diff --git a/components/security_interstitials/core/ssl_error_ui.h b/components/security_interstitials/core/ssl_error_ui.h
index 3bb8dc8..3be2a598 100644
--- a/components/security_interstitials/core/ssl_error_ui.h
+++ b/components/security_interstitials/core/ssl_error_ui.h
@@ -44,6 +44,7 @@
              const net::SSLInfo& ssl_info,
              int display_options,  // Bitmask of SSLErrorOptionsMask values.
              const base::Time& time_triggered,
+             const GURL& support_url,
              ControllerClient* controller);
   virtual ~SSLErrorUI();
 
@@ -64,6 +65,7 @@
   const int cert_error_;
   const net::SSLInfo ssl_info_;
   const base::Time time_triggered_;
+  const GURL support_url_;
 
   // Set by the |display_options|.
   const bool requested_strict_enforcement_;
diff --git a/components/security_interstitials/core/superfish_error_ui.cc b/components/security_interstitials/core/superfish_error_ui.cc
index e209391..912f36ac 100644
--- a/components/security_interstitials/core/superfish_error_ui.cc
+++ b/components/security_interstitials/core/superfish_error_ui.cc
@@ -31,6 +31,7 @@
                  ssl_info,
                  display_options,
                  time_triggered,
+                 GURL(),
                  controller) {}
 
 void SuperfishErrorUI::PopulateStringsForHTML(
diff --git a/components/viz/common/gpu/in_process_context_provider.cc b/components/viz/common/gpu/in_process_context_provider.cc
index 7fceb9b..d85e714 100644
--- a/components/viz/common/gpu/in_process_context_provider.cc
+++ b/components/viz/common/gpu/in_process_context_provider.cc
@@ -16,10 +16,8 @@
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "gpu/command_buffer/client/raster_implementation_gles.h"
 #include "gpu/command_buffer/common/context_creation_attribs.h"
-#include "gpu/command_buffer/service/framebuffer_completeness_cache.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
-#include "gpu/command_buffer/service/shader_translator_cache.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/ipc/common/surface_handle.h"
diff --git a/components/viz/host/hit_test/hit_test_query.cc b/components/viz/host/hit_test/hit_test_query.cc
index 9e85ae3..fc514ee 100644
--- a/components/viz/host/hit_test/hit_test_query.cc
+++ b/components/viz/host/hit_test/hit_test_query.cc
@@ -119,12 +119,18 @@
       ShouldUseTouchBounds(event_source)
           ? (region->flags & mojom::kHitTestTouch) != 0u
           : (region->flags & mojom::kHitTestMouse) != 0u;
-  if ((region->flags & mojom::kHitTestMine) && match_touch_or_mouse_region) {
+  if (!match_touch_or_mouse_region)
+    return false;
+  if (region->flags & mojom::kHitTestMine) {
     target->frame_sink_id = region->frame_sink_id;
     target->location_in_target = location_in_target;
     target->flags = region->flags;
     return true;
   }
+  if (region->flags & mojom::kHitTestAsk) {
+    target->flags = region->flags;
+    return true;
+  }
   return false;
 }
 
diff --git a/components/viz/host/hit_test/hit_test_query_unittest.cc b/components/viz/host/hit_test/hit_test_query_unittest.cc
index e21e8e88..fc6f4fbc 100644
--- a/components/viz/host/hit_test/hit_test_query_unittest.cc
+++ b/components/viz/host/hit_test/hit_test_query_unittest.cc
@@ -911,5 +911,91 @@
   EXPECT_EQ(target4.flags, mojom::kHitTestMine | mojom::kHitTestTouch);
 }
 
+TEST_F(HitTestQueryTest, RootHitTestAskFlag) {
+  FrameSinkId e_id = FrameSinkId(1, 1);
+  gfx::Rect e_bounds = gfx::Rect(0, 0, 600, 600);
+  gfx::Transform transform_e_to_e;
+  AggregatedHitTestRegion* aggregated_hit_test_region_list =
+      aggregated_hit_test_region();
+  aggregated_hit_test_region_list[0] =
+      AggregatedHitTestRegion(e_id, mojom::kHitTestAsk | mojom::kHitTestMouse,
+                              e_bounds, transform_e_to_e, 0);  // e
+
+  // All points are in e's coordinate system when we reach this case.
+  gfx::Point point1(1, 1);
+  gfx::Point point2(600, 600);
+
+  // point1 is inside e but we have to ask clients for targeting.
+  Target target1 =
+      hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
+  EXPECT_EQ(target1.frame_sink_id, FrameSinkId());
+  EXPECT_EQ(target1.location_in_target, gfx::Point());
+  EXPECT_EQ(target1.flags, mojom::kHitTestAsk | mojom::kHitTestMouse);
+
+  // point2 is on the bounds of e so no target found.
+  Target target2 =
+      hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
+  EXPECT_EQ(target2.frame_sink_id, FrameSinkId());
+  EXPECT_EQ(target2.location_in_target, gfx::Point());
+  EXPECT_FALSE(target2.flags);
+}
+
+// One embedder with two children.
+//
+//  +e------------+     Point   maps to
+//  | +c1-+ +c2---|     -----   -------
+//  |1|   | |     |      1        e
+//  | | 2 | | 3   |      2        c1
+//  | +---+ |     |      3        c2
+//  +-------------+
+//
+TEST_F(HitTestQueryTest, ChildHitTestAskFlag) {
+  FrameSinkId e_id = FrameSinkId(1, 1);
+  FrameSinkId c1_id = FrameSinkId(2, 2);
+  FrameSinkId c2_id = FrameSinkId(3, 3);
+  gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+  gfx::Rect c1_bounds_in_e = gfx::Rect(0, 0, 200, 200);
+  gfx::Rect c2_bounds_in_e = gfx::Rect(0, 0, 400, 400);
+  gfx::Transform transform_e_to_e, transform_e_to_c1, transform_e_to_c2;
+  transform_e_to_c1.Translate(-100, -100);
+  transform_e_to_c2.Translate(-300, -300);
+  AggregatedHitTestRegion* aggregated_hit_test_region_list =
+      aggregated_hit_test_region();
+  aggregated_hit_test_region_list[0] =
+      AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
+                              e_bounds_in_e, transform_e_to_e, 2);  // e
+  aggregated_hit_test_region_list[1] =
+      AggregatedHitTestRegion(c1_id, mojom::kHitTestMine | mojom::kHitTestMouse,
+                              c1_bounds_in_e, transform_e_to_c1, 0);  // c1
+  aggregated_hit_test_region_list[2] =
+      AggregatedHitTestRegion(c2_id, mojom::kHitTestAsk | mojom::kHitTestMouse,
+                              c2_bounds_in_e, transform_e_to_c2, 0);  // c2
+
+  // All points are in e's coordinate system when we reach this case.
+  gfx::Point point1(99, 200);
+  gfx::Point point2(150, 150);
+  gfx::Point point3(400, 400);
+
+  Target target1 =
+      hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
+  EXPECT_EQ(target1.frame_sink_id, e_id);
+  EXPECT_EQ(target1.location_in_target, point1);
+  EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+
+  Target target2 =
+      hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
+  EXPECT_EQ(target2.frame_sink_id, c1_id);
+  EXPECT_EQ(target2.location_in_target, gfx::Point(50, 50));
+  EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+
+  // point3 is inside c2 but we have to ask clients for targeting. Event
+  // shouldn't go back to e.
+  Target target3 =
+      hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
+  EXPECT_EQ(target3.frame_sink_id, FrameSinkId());
+  EXPECT_EQ(target3.location_in_target, gfx::Point());
+  EXPECT_EQ(target3.flags, mojom::kHitTestAsk | mojom::kHitTestMouse);
+}
+
 }  // namespace test
 }  // namespace viz
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 43460c3..5fc3bdb6 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -23,7 +23,7 @@
          method == "Debugger.setBreakpointByUrl" ||
          method == "Debugger.removeBreakpoint" ||
          method == "Debugger.setBreakpointsActive" ||
-         method == "Performance.getMetrics";
+         method == "Performance.getMetrics" || method == "Page.crash";
 }
 
 }  // namespace
diff --git a/content/browser/locks/lock_manager.cc b/content/browser/locks/lock_manager.cc
index c4fdf7d..4ca29af 100644
--- a/content/browser/locks/lock_manager.cc
+++ b/content/browser/locks/lock_manager.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -76,22 +77,100 @@
 
 LockManager::~LockManager() = default;
 
-LockManager::OriginState::OriginState() = default;
-LockManager::OriginState::~OriginState() = default;
+class LockManager::OriginState {
+ public:
+  OriginState() = default;
+  ~OriginState() = default;
 
-bool LockManager::OriginState::IsGrantable(const std::string& name,
-                                           LockMode mode) const {
-  if (mode == LockMode::EXCLUSIVE) {
-    return !shared.count(name) && !exclusive.count(name);
-  } else {
-    return !exclusive.count(name);
+  void AddRequest(int64_t lock_id,
+                  const std::string& name,
+                  LockMode mode,
+                  blink::mojom::LockRequestPtr request) {
+    requested_.emplace(std::make_pair(
+        lock_id,
+        std::make_unique<Lock>(name, mode, lock_id, std::move(request))));
   }
-}
 
-void LockManager::OriginState::MergeLockState(const std::string& name,
-                                              LockMode mode) {
-  (mode == LockMode::SHARED ? shared : exclusive).insert(name);
-}
+  bool EraseLock(int64_t lock_id) {
+    return requested_.erase(lock_id) || held_.erase(lock_id);
+  }
+
+  bool IsEmpty() const { return requested_.empty() && held_.empty(); }
+
+  bool IsGrantable(const std::string& name, LockMode mode) const {
+    if (mode == LockMode::EXCLUSIVE) {
+      return !shared_.count(name) && !exclusive_.count(name);
+    } else {
+      return !exclusive_.count(name);
+    }
+  }
+
+  void ProcessRequests(LockManager* lock_manager, const url::Origin& origin) {
+    if (requested_.empty())
+      return;
+
+    shared_.clear();
+    exclusive_.clear();
+    for (const auto& id_lock_pair : held_) {
+      const auto& lock = id_lock_pair.second;
+      MergeLockState(lock->name, lock->mode);
+    }
+
+    for (auto it = requested_.begin(); it != requested_.end();) {
+      auto& lock = it->second;
+
+      bool granted = IsGrantable(lock->name, lock->mode);
+
+      MergeLockState(lock->name, lock->mode);
+
+      if (granted) {
+        std::unique_ptr<Lock> grantee = std::move(lock);
+        it = requested_.erase(it);
+        grantee->request->Granted(LockHandleImpl::Create(
+            lock_manager->weak_ptr_factory_.GetWeakPtr(), origin, grantee->id));
+        grantee->request = nullptr;
+        held_.insert(std::make_pair(grantee->id, std::move(grantee)));
+      } else {
+        ++it;
+      }
+    }
+  }
+
+  std::vector<blink::mojom::LockInfoPtr> SnapshotRequested() const {
+    std::vector<blink::mojom::LockInfoPtr> out;
+    out.reserve(requested_.size());
+    for (const auto& id_lock_pair : requested_) {
+      out.emplace_back(base::in_place, id_lock_pair.second->name,
+                       id_lock_pair.second->mode);
+    }
+    return out;
+  }
+
+  std::vector<blink::mojom::LockInfoPtr> SnapshotHeld() const {
+    std::vector<blink::mojom::LockInfoPtr> out;
+    out.reserve(held_.size());
+    for (const auto& id_lock_pair : held_) {
+      out.emplace_back(base::in_place, id_lock_pair.second->name,
+                       id_lock_pair.second->mode);
+    }
+    return out;
+  }
+
+ private:
+  void MergeLockState(const std::string& name, LockMode mode) {
+    (mode == LockMode::SHARED ? shared_ : exclusive_).insert(name);
+  }
+
+  // These represent the actual state of locks in the origin.
+  std::map<int64_t, std::unique_ptr<Lock>> requested_;
+  std::map<int64_t, std::unique_ptr<Lock>> held_;
+
+  // These sets represent what is held or requested, so that "IsGrantable"
+  // tests are simple. These are cleared/rebuilt when the request queue
+  // is processed.
+  std::unordered_set<std::string> shared_;
+  std::unordered_set<std::string> exclusive_;
+};
 
 void LockManager::CreateService(blink::mojom::LockManagerRequest request,
                                 const url::Origin& origin) {
@@ -112,27 +191,22 @@
   }
 
   int64_t lock_id = next_lock_id++;
-
   request.set_connection_error_handler(base::BindOnce(
       &LockManager::ReleaseLock, base::Unretained(this), origin, lock_id));
-
-  origins_[origin].requested.emplace(std::make_pair(
-      lock_id,
-      std::make_unique<Lock>(name, mode, lock_id, std::move(request))));
-
+  origins_[origin].AddRequest(lock_id, name, mode, std::move(request));
   ProcessRequests(origin);
 }
 
-void LockManager::ReleaseLock(const url::Origin& origin, int64_t id) {
+void LockManager::ReleaseLock(const url::Origin& origin, int64_t lock_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!base::ContainsKey(origins_, origin))
     return;
   OriginState& state = origins_[origin];
 
-  bool dirty = state.requested.erase(id) || state.held.erase(id);
+  bool dirty = state.EraseLock(lock_id);
 
-  if (state.requested.empty() && state.held.empty())
+  if (state.IsEmpty())
     origins_.erase(origin);
   else if (dirty)
     ProcessRequests(origin);
@@ -146,31 +220,17 @@
     return;
   OriginState& state = origins_[origin];
 
-  std::vector<blink::mojom::LockInfoPtr> pending;
-  pending.reserve(state.requested.size());
-  for (const auto& id_lock_pair : state.requested) {
-    pending.emplace_back(base::in_place, id_lock_pair.second->name,
-                         id_lock_pair.second->mode);
-  }
-
-  std::vector<blink::mojom::LockInfoPtr> held;
-  held.reserve(state.held.size());
-  for (const auto& id_lock_pair : state.held) {
-    held.emplace_back(base::in_place, id_lock_pair.second->name,
-                      id_lock_pair.second->mode);
-  }
-
-  std::move(callback).Run(std::move(pending), std::move(held));
+  std::move(callback).Run(state.SnapshotRequested(), state.SnapshotHeld());
 }
 
 bool LockManager::IsGrantable(const url::Origin& origin,
                               const std::string& name,
-                              LockMode mode) {
+                              LockMode mode) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!base::ContainsKey(origins_, origin))
+  auto it = origins_.find(origin);
+  if (it == origins_.end())
     return true;
-
-  return origins_[origin].IsGrantable(name, mode);
+  return it->second.IsGrantable(name, mode);
 }
 
 void LockManager::ProcessRequests(const url::Origin& origin) {
@@ -179,37 +239,9 @@
     return;
 
   OriginState& state = origins_[origin];
-
-  if (state.requested.empty())
-    return;
-
-  state.shared.clear();
-  state.exclusive.clear();
-  for (const auto& id_lock_pair : state.held) {
-    const auto& lock = id_lock_pair.second;
-    state.MergeLockState(lock->name, lock->mode);
-  }
-
-  for (auto it = state.requested.begin(); it != state.requested.end();) {
-    auto& lock = it->second;
-
-    bool granted = state.IsGrantable(lock->name, lock->mode);
-
-    state.MergeLockState(lock->name, lock->mode);
-
-    if (granted) {
-      std::unique_ptr<Lock> grantee = std::move(lock);
-      it = state.requested.erase(it);
-      grantee->request->Granted(LockHandleImpl::Create(
-          weak_ptr_factory_.GetWeakPtr(), origin, grantee->id));
-      grantee->request = nullptr;
-      state.held.insert(std::make_pair(grantee->id, std::move(grantee)));
-    } else {
-      ++it;
-    }
-  }
-
-  DCHECK(!(state.requested.empty() && state.held.empty()));
+  DCHECK(!state.IsEmpty());
+  state.ProcessRequests(this, origin);
+  DCHECK(!state.IsEmpty());
 }
 
 }  // namespace content
diff --git a/content/browser/locks/lock_manager.h b/content/browser/locks/lock_manager.h
index 5e8df5b..c541796 100644
--- a/content/browser/locks/lock_manager.h
+++ b/content/browser/locks/lock_manager.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 #include <string>
-#include <unordered_set>
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
@@ -38,7 +37,7 @@
                    blink::mojom::LockRequestPtr request) override;
 
   // Called by a LockHandle's implementation when destructed.
-  void ReleaseLock(const url::Origin& origin, int64_t id);
+  void ReleaseLock(const url::Origin& origin, int64_t lock_id);
 
   // Called to request a snapshot of the current lock state for an origin.
   void QueryState(QueryStateCallback callback) override;
@@ -52,26 +51,11 @@
   struct Lock;
 
   // State for a particular origin.
-  struct OriginState {
-    OriginState();
-    ~OriginState();
-
-    bool IsGrantable(const std::string& name,
-                     blink::mojom::LockMode mode) const;
-    void MergeLockState(const std::string& name, blink::mojom::LockMode mode);
-
-    std::map<int64_t, std::unique_ptr<Lock>> requested;
-    std::map<int64_t, std::unique_ptr<Lock>> held;
-
-    // These sets represent what is held or requested, so that "IsGrantable"
-    // tests are simple.
-    std::unordered_set<std::string> shared;
-    std::unordered_set<std::string> exclusive;
-  };
+  class OriginState;
 
   bool IsGrantable(const url::Origin& origin,
                    const std::string& name,
-                   blink::mojom::LockMode mode);
+                   blink::mojom::LockMode mode) const;
 
   // Called when a lock is requested and optionally when a lock is released,
   // to process outstanding requests within the origin.
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 156258bf..40661e7 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -44,7 +44,6 @@
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
-#include "content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h"
 #include "sandbox/win/src/process_mitigations.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #include "services/service_manager/sandbox/win/sandbox_win.h"
@@ -296,9 +295,6 @@
   filter_ = new PepperMessageFilter();
   process_->AddFilter(filter_.get());
   process_->GetHost()->AddFilter(host_impl_->message_filter().get());
-#if defined(OS_WIN)
-  process_->AddFilter(new DWriteFontProxyMessageFilter());
-#endif
 
   GetContentClient()->browser()->DidCreatePpapiPlugin(host_impl_.get());
 
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
index 163af1c..d1b125c 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
+++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
@@ -23,8 +23,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
-#include "content/common/dwrite_font_proxy_messages.h"
-#include "ipc/ipc_message_macros.h"
+#include "mojo/public/cpp/bindings/callback_helpers.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "ui/gfx/win/direct_write.h"
 #include "ui/gfx/win/text_analysis_source.h"
 
@@ -178,48 +178,30 @@
 
 }  // namespace
 
-DWriteFontProxyMessageFilter::DWriteFontProxyMessageFilter()
-    : BrowserMessageFilter(DWriteFontProxyMsgStart),
-      windows_fonts_path_(GetWindowsFontsPath()),
-      custom_font_file_loading_mode_(ENABLE),
-      dwrite_io_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
-          {base::TaskPriority::USER_BLOCKING, base::MayBlock()})) {}
+DWriteFontProxyImpl::DWriteFontProxyImpl()
+    : windows_fonts_path_(GetWindowsFontsPath()),
+      custom_font_file_loading_mode_(ENABLE) {}
 
-DWriteFontProxyMessageFilter::~DWriteFontProxyMessageFilter() = default;
+DWriteFontProxyImpl::~DWriteFontProxyImpl() = default;
 
-bool DWriteFontProxyMessageFilter::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(DWriteFontProxyMessageFilter, message)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_FindFamily, OnFindFamily)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_GetFamilyCount, OnGetFamilyCount)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_GetFamilyNames, OnGetFamilyNames)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_GetFontFiles, OnGetFontFiles)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_MapCharacters, OnMapCharacters)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
+// static
+void DWriteFontProxyImpl::Create(
+    mojom::DWriteFontProxyRequest request,
+    const service_manager::BindSourceInfo& source_info) {
+  mojo::MakeStrongBinding(std::make_unique<DWriteFontProxyImpl>(),
+                          std::move(request));
 }
 
-base::TaskRunner* DWriteFontProxyMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& message) {
-  if (IPC_MESSAGE_CLASS(message) == DWriteFontProxyMsgStart)
-    return dwrite_io_task_runner_.get();
-  return nullptr;
-}
-
-void DWriteFontProxyMessageFilter::SetWindowsFontsPathForTesting(
-    base::string16 path) {
+void DWriteFontProxyImpl::SetWindowsFontsPathForTesting(base::string16 path) {
   windows_fonts_path_.swap(path);
 }
 
-void DWriteFontProxyMessageFilter::OnFindFamily(
-    const base::string16& family_name,
-    UINT32* family_index) {
+void DWriteFontProxyImpl::FindFamily(const base::string16& family_name,
+                                     FindFamilyCallback callback) {
   InitializeDirectWrite();
   TRACE_EVENT0("dwrite", "FontProxyHost::OnFindFamily");
   DCHECK(collection_);
-  *family_index = UINT32_MAX;
+  UINT32 family_index = UINT32_MAX;
   if (collection_) {
     BOOL exists = FALSE;
     UINT32 index = UINT32_MAX;
@@ -227,26 +209,25 @@
         collection_->FindFamilyName(family_name.data(), &index, &exists);
     if (SUCCEEDED(hr) && exists &&
         CheckRequiredStylesPresent(collection_.Get(), family_name, index)) {
-      *family_index = index;
+      family_index = index;
     }
   }
+  std::move(callback).Run(family_index);
 }
 
-void DWriteFontProxyMessageFilter::OnGetFamilyCount(UINT32* count) {
+void DWriteFontProxyImpl::GetFamilyCount(GetFamilyCountCallback callback) {
   InitializeDirectWrite();
   TRACE_EVENT0("dwrite", "FontProxyHost::OnGetFamilyCount");
   DCHECK(collection_);
-  if (!collection_)
-    *count = 0;
-  else
-    *count = collection_->GetFontFamilyCount();
+  std::move(callback).Run(collection_->GetFontFamilyCount());
 }
 
-void DWriteFontProxyMessageFilter::OnGetFamilyNames(
-    UINT32 family_index,
-    std::vector<DWriteStringPair>* family_names) {
+void DWriteFontProxyImpl::GetFamilyNames(UINT32 family_index,
+                                         GetFamilyNamesCallback callback) {
   InitializeDirectWrite();
   TRACE_EVENT0("dwrite", "FontProxyHost::OnGetFamilyNames");
+  callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+      std::move(callback), std::vector<mojom::DWriteStringPairPtr>());
   DCHECK(collection_);
   if (!collection_)
     return;
@@ -269,6 +250,7 @@
 
   std::vector<base::char16> locale;
   std::vector<base::char16> name;
+  std::vector<mojom::DWriteStringPairPtr> family_names;
   for (size_t index = 0; index < string_count; ++index) {
     UINT32 length = 0;
     hr = localized_names->GetLocaleNameLength(index, &length);
@@ -296,18 +278,19 @@
     }
     CHECK_EQ(L'\0', name[length - 1]);
 
-    // Would be great to use emplace_back instead.
-    family_names->push_back(std::pair<base::string16, base::string16>(
-        base::string16(locale.data()), base::string16(name.data())));
+    family_names.emplace_back(base::in_place, base::string16(locale.data()),
+                              base::string16(name.data()));
   }
+  std::move(callback).Run(std::move(family_names));
 }
 
-void DWriteFontProxyMessageFilter::OnGetFontFiles(
-    uint32_t family_index,
-    std::vector<base::string16>* file_paths,
-    std::vector<IPC::PlatformFileForTransit>* file_handles) {
+void DWriteFontProxyImpl::GetFontFiles(uint32_t family_index,
+                                       GetFontFilesCallback callback) {
   InitializeDirectWrite();
   TRACE_EVENT0("dwrite", "FontProxyHost::OnGetFontFiles");
+  callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+      std::move(callback), std::vector<base::FilePath>(),
+      std::vector<base::File>());
   DCHECK(collection_);
   if (!collection_)
     return;
@@ -342,6 +325,7 @@
     }
   }
 
+  std::vector<base::File> file_handles;
   // For files outside the windows fonts directory we pass them to the renderer
   // as file handles. The renderer would be unable to open the files directly
   // due to sandbox policy (it would get ERROR_ACCESS_DENIED instead). Passing
@@ -354,37 +338,40 @@
                     base::File::FLAG_OPEN | base::File::FLAG_READ |
                         base::File::FLAG_EXCLUSIVE_WRITE);
     if (file.IsValid()) {
-      file_handles->push_back(IPC::TakePlatformFileForTransit(std::move(file)));
+      file_handles.push_back(std::move(file));
     }
   }
 
-  file_paths->assign(path_set.begin(), path_set.end());
-  LogLastResortFontFileCount(file_paths->size());
+  std::vector<base::FilePath> file_paths;
+  for (const auto& path : path_set) {
+    file_paths.emplace_back(base::FilePath(path));
+  }
+  LogLastResortFontFileCount(file_paths.size());
+  std::move(callback).Run(file_paths, std::move(file_handles));
 }
 
-void DWriteFontProxyMessageFilter::OnMapCharacters(
-    const base::string16& text,
-    const DWriteFontStyle& font_style,
-    const base::string16& locale_name,
-    uint32_t reading_direction,
-    const base::string16& base_family_name,
-    MapCharactersResult* result) {
+void DWriteFontProxyImpl::MapCharacters(const base::string16& text,
+                                        mojom::DWriteFontStylePtr font_style,
+                                        const base::string16& locale_name,
+                                        uint32_t reading_direction,
+                                        const base::string16& base_family_name,
+                                        MapCharactersCallback callback) {
   InitializeDirectWrite();
-  result->family_index = UINT32_MAX;
-  result->mapped_length = text.length();
-  result->family_name.clear();
-  result->scale = 0.0;
-  result->font_style.font_slant = DWRITE_FONT_STYLE_NORMAL;
-  result->font_style.font_stretch = DWRITE_FONT_STRETCH_NORMAL;
-  result->font_style.font_weight = DWRITE_FONT_WEIGHT_NORMAL;
+  callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+      std::move(callback),
+      mojom::MapCharactersResult::New(
+          UINT32_MAX, L"", text.length(), 0.0,
+          mojom::DWriteFontStyle::New(DWRITE_FONT_STYLE_NORMAL,
+                                      DWRITE_FONT_STRETCH_NORMAL,
+                                      DWRITE_FONT_WEIGHT_NORMAL)));
   if (factory2_ == nullptr || collection_ == nullptr)
     return;
   if (font_fallback_ == nullptr) {
-    if (FAILED(factory2_->GetSystemFontFallback(&font_fallback_)))
+    if (FAILED(factory2_->GetSystemFontFallback(&font_fallback_))) {
       return;
+    }
   }
 
-  UINT32 length;
   mswr::ComPtr<IDWriteFont> mapped_font;
 
   mswr::ComPtr<IDWriteNumberSubstitution> number_substitution;
@@ -402,20 +389,26 @@
     return;
   }
 
+  auto result = mojom::MapCharactersResult::New(
+      UINT32_MAX, L"", text.length(), 0.0,
+      mojom::DWriteFontStyle::New(DWRITE_FONT_STYLE_NORMAL,
+                                  DWRITE_FONT_STRETCH_NORMAL,
+                                  DWRITE_FONT_WEIGHT_NORMAL));
   if (FAILED(font_fallback_->MapCharacters(
           analysis_source.Get(), 0, text.length(), collection_.Get(),
           base_family_name.c_str(),
-          static_cast<DWRITE_FONT_WEIGHT>(font_style.font_weight),
-          static_cast<DWRITE_FONT_STYLE>(font_style.font_slant),
-          static_cast<DWRITE_FONT_STRETCH>(font_style.font_stretch), &length,
-          &mapped_font, &result->scale))) {
+          static_cast<DWRITE_FONT_WEIGHT>(font_style->font_weight),
+          static_cast<DWRITE_FONT_STYLE>(font_style->font_slant),
+          static_cast<DWRITE_FONT_STRETCH>(font_style->font_stretch),
+          &result->mapped_length, &mapped_font, &result->scale))) {
     DCHECK(false);
     return;
   }
 
-  result->mapped_length = length;
-  if (mapped_font == nullptr)
+  if (mapped_font == nullptr) {
+    std::move(callback).Run(std::move(result));
     return;
+  }
 
   mswr::ComPtr<IDWriteFontFamily> mapped_family;
   if (FAILED(mapped_font->GetFontFamily(&mapped_family))) {
@@ -428,9 +421,9 @@
     return;
   }
 
-  result->font_style.font_slant = mapped_font->GetStyle();
-  result->font_style.font_stretch = mapped_font->GetStretch();
-  result->font_style.font_weight = mapped_font->GetWeight();
+  result->font_style->font_slant = mapped_font->GetStyle();
+  result->font_style->font_stretch = mapped_font->GetStretch();
+  result->font_style->font_weight = mapped_font->GetWeight();
 
   std::vector<base::char16> name;
   size_t name_count = family_names->GetCount();
@@ -452,16 +445,17 @@
     // Found a matching family!
     result->family_index = index;
     result->family_name = name.data();
+    std::move(callback).Run(std::move(result));
     return;
   }
+
   // Could not find a matching family
   LogMessageFilterError(MAP_CHARACTERS_NO_FAMILY);
   DCHECK_EQ(result->family_index, UINT32_MAX);
   DCHECK_GT(result->mapped_length, 0u);
 }
 
-void DWriteFontProxyMessageFilter::InitializeDirectWrite() {
-  DCHECK(dwrite_io_task_runner_->RunsTasksInCurrentSequence());
+void DWriteFontProxyImpl::InitializeDirectWrite() {
   if (direct_write_initialized_)
     return;
   direct_write_initialized_ = true;
@@ -506,7 +500,7 @@
   LogLastResortFontCount(last_resort_fonts_.size());
 }
 
-bool DWriteFontProxyMessageFilter::AddFilesForFont(
+bool DWriteFontProxyImpl::AddFilesForFont(
     std::set<base::string16>* path_set,
     std::set<base::string16>* custom_font_path_set,
     IDWriteFont* font) {
@@ -574,7 +568,7 @@
   return true;
 }
 
-bool DWriteFontProxyMessageFilter::AddLocalFile(
+bool DWriteFontProxyImpl::AddLocalFile(
     std::set<base::string16>* path_set,
     std::set<base::string16>* custom_font_path_set,
     IDWriteLocalFontFileLoader* local_loader,
@@ -619,8 +613,7 @@
   return true;
 }
 
-bool DWriteFontProxyMessageFilter::IsLastResortFallbackFont(
-    uint32_t font_index) {
+bool DWriteFontProxyImpl::IsLastResortFallbackFont(uint32_t font_index) {
   for (auto iter = last_resort_fonts_.begin(); iter != last_resort_fonts_.end();
        ++iter) {
     if (*iter == font_index)
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h
index 808b78cf..9a8212d6 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h
+++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h
@@ -17,15 +17,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
+#include "content/common/dwrite_font_proxy.mojom.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
-#include "ipc/ipc_platform_file.h"
 
-struct DWriteFontStyle;
-struct MapCharactersResult;
-
-namespace base {
-class SequencedTaskRunner;
+namespace service_manager {
+struct BindSourceInfo;
 }
 
 namespace content {
@@ -33,34 +30,31 @@
 // Implements a message filter that handles the dwrite font proxy messages.
 // If DWrite is enabled, calls into the system font collection to obtain
 // results. Otherwise, acts as if the system collection contains no fonts.
-class CONTENT_EXPORT DWriteFontProxyMessageFilter
-    : public BrowserMessageFilter {
+class CONTENT_EXPORT DWriteFontProxyImpl : public mojom::DWriteFontProxy {
  public:
-  DWriteFontProxyMessageFilter();
+  DWriteFontProxyImpl();
+  ~DWriteFontProxyImpl() override;
 
-  // BrowserMessageFilter:
-  bool OnMessageReceived(const IPC::Message& message) override;
-  base::TaskRunner* OverrideTaskRunnerForMessage(const IPC::Message&) override;
+  static void Create(mojom::DWriteFontProxyRequest request,
+                     const service_manager::BindSourceInfo& source_info);
 
   void SetWindowsFontsPathForTesting(base::string16 path);
 
  protected:
-  ~DWriteFontProxyMessageFilter() override;
-
-  void OnFindFamily(const base::string16& family_name, UINT32* family_index);
-  void OnGetFamilyCount(UINT32* count);
-  void OnGetFamilyNames(
-      UINT32 family_index,
-      std::vector<std::pair<base::string16, base::string16>>* family_names);
-  void OnGetFontFiles(UINT32 family_index,
-                      std::vector<base::string16>* file_paths,
-                      std::vector<IPC::PlatformFileForTransit>* file_handles);
-  void OnMapCharacters(const base::string16& text,
-                       const DWriteFontStyle& font_style,
-                       const base::string16& locale_name,
-                       uint32_t reading_direction,
-                       const base::string16& base_family_name,
-                       MapCharactersResult* result);
+  // mojom::DWriteFontProxy:
+  void FindFamily(const base::string16& family_name,
+                  FindFamilyCallback callback) override;
+  void GetFamilyCount(GetFamilyCountCallback callback) override;
+  void GetFamilyNames(uint32_t family_index,
+                      GetFamilyNamesCallback callback) override;
+  void GetFontFiles(uint32_t family_index,
+                    GetFontFilesCallback callback) override;
+  void MapCharacters(const base::string16& text,
+                     mojom::DWriteFontStylePtr font_style,
+                     const base::string16& locale_name,
+                     uint32_t reading_direction,
+                     const base::string16& base_family_name,
+                     MapCharactersCallback callback) override;
 
   void InitializeDirectWrite();
 
@@ -84,12 +78,11 @@
   Microsoft::WRL::ComPtr<IDWriteFontFallback> font_fallback_;
   base::string16 windows_fonts_path_;
   CustomFontFileLoadingMode custom_font_file_loading_mode_;
-  scoped_refptr<base::SequencedTaskRunner> dwrite_io_task_runner_;
 
   // Temp code to help track down crbug.com/561873
   std::vector<uint32_t> last_resort_fonts_;
 
-  DISALLOW_COPY_AND_ASSIGN(DWriteFontProxyMessageFilter);
+  DISALLOW_COPY_AND_ASSIGN(DWriteFontProxyImpl);
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc
index a340ba7..78db702 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc
+++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win_unittest.cc
@@ -15,9 +15,9 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/windows_version.h"
-#include "content/common/dwrite_font_proxy_messages.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "ipc/ipc_message_macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/bind_source_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/win/direct_write.h"
 
@@ -27,45 +27,10 @@
 
 namespace {
 
-class FilterWithFakeSender : public DWriteFontProxyMessageFilter {
+class DWriteFontProxyImplUnitTest : public testing::Test {
  public:
-  bool Send(IPC::Message* msg) override {
-    EXPECT_EQ(nullptr, reply_message_.get());
-    reply_message_.reset(msg);
-    return true;
-  }
-
-  IPC::Message* GetReply() { return reply_message_.get(); }
-
-  void ResetReply() { reply_message_.reset(nullptr); }
-
- private:
-  ~FilterWithFakeSender() override = default;
-
-  std::unique_ptr<IPC::Message> reply_message_;
-};
-
-class DWriteFontProxyMessageFilterUnitTest : public testing::Test {
- public:
-  DWriteFontProxyMessageFilterUnitTest() {
-    filter_ = new FilterWithFakeSender();
-  }
-
-  void Send(IPC::SyncMessage* message) {
-    std::unique_ptr<IPC::SyncMessage> deleter(message);
-    std::unique_ptr<IPC::MessageReplyDeserializer> serializer(
-        message->GetReplyDeserializer());
-    base::TaskRunner* dwrite_io_task_runner =
-        filter_->OverrideTaskRunnerForMessage(*message);
-    dwrite_io_task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(base::IgnoreResult(
-                       &DWriteFontProxyMessageFilter::OnMessageReceived),
-                   filter_, base::ConstRef(*message)));
-    scoped_task_environment_.RunUntilIdle();
-    ASSERT_NE(nullptr, filter_->GetReply());
-    serializer->SerializeOutputParameters(*(filter_->GetReply()));
-  }
+  DWriteFontProxyImplUnitTest()
+      : binding_(&impl_, mojo::MakeRequest(&dwrite_font_proxy_)) {}
 
   bool IsDWrite2Available() {
     mswr::ComPtr<IDWriteFactory> factory;
@@ -79,166 +44,154 @@
     }
     return factory2.Get();
   }
+  mojom::DWriteFontProxy& dwrite_font_proxy() { return *dwrite_font_proxy_; }
 
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  scoped_refptr<FilterWithFakeSender> filter_;
+  mojom::DWriteFontProxyPtr dwrite_font_proxy_;
+  DWriteFontProxyImpl impl_;
+  mojo::Binding<mojom::DWriteFontProxy> binding_;
 };
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, GetFamilyCount) {
+TEST_F(DWriteFontProxyImplUnitTest, GetFamilyCount) {
   UINT32 family_count = 0;
-  Send(new DWriteFontProxyMsg_GetFamilyCount(&family_count));
+  dwrite_font_proxy().GetFamilyCount(&family_count);
   EXPECT_NE(0u, family_count);  // Assume there's some fonts on the test system.
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, FindFamily) {
+TEST_F(DWriteFontProxyImplUnitTest, FindFamily) {
   UINT32 arial_index = 0;
-  Send(new DWriteFontProxyMsg_FindFamily(L"Arial", &arial_index));
+  dwrite_font_proxy().FindFamily(L"Arial", &arial_index);
   EXPECT_NE(UINT_MAX, arial_index);
 
-  filter_->ResetReply();
   UINT32 times_index = 0;
-  Send(new DWriteFontProxyMsg_FindFamily(L"Times New Roman", &times_index));
+  dwrite_font_proxy().FindFamily(L"Times New Roman", &times_index);
   EXPECT_NE(UINT_MAX, times_index);
   EXPECT_NE(arial_index, times_index);
 
-  filter_->ResetReply();
   UINT32 unknown_index = 0;
-  Send(new DWriteFontProxyMsg_FindFamily(L"Not a font family", &unknown_index));
+  dwrite_font_proxy().FindFamily(L"Not a font family", &unknown_index);
   EXPECT_EQ(UINT_MAX, unknown_index);
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, GetFamilyNames) {
+TEST_F(DWriteFontProxyImplUnitTest, GetFamilyNames) {
   UINT32 arial_index = 0;
-  Send(new DWriteFontProxyMsg_FindFamily(L"Arial", &arial_index));
-  filter_->ResetReply();
+  dwrite_font_proxy().FindFamily(L"Arial", &arial_index);
 
-  std::vector<DWriteStringPair> names;
-  Send(new DWriteFontProxyMsg_GetFamilyNames(arial_index, &names));
+  std::vector<mojom::DWriteStringPairPtr> names;
+  dwrite_font_proxy().GetFamilyNames(arial_index, &names);
 
   EXPECT_LT(0u, names.size());
   for (const auto& pair : names) {
-    EXPECT_STRNE(L"", pair.first.c_str());
-    EXPECT_STRNE(L"", pair.second.c_str());
+    EXPECT_FALSE(pair->first.empty());
+    EXPECT_FALSE(pair->second.empty());
   }
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, GetFamilyNamesIndexOutOfBounds) {
-  std::vector<DWriteStringPair> names;
+TEST_F(DWriteFontProxyImplUnitTest, GetFamilyNamesIndexOutOfBounds) {
+  std::vector<mojom::DWriteStringPairPtr> names;
   UINT32 invalid_index = 1000000;
-  Send(new DWriteFontProxyMsg_GetFamilyNames(invalid_index, &names));
+  dwrite_font_proxy().GetFamilyNames(invalid_index, &names);
 
-  EXPECT_EQ(0u, names.size());
+  EXPECT_TRUE(names.empty());
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, GetFontFiles) {
+TEST_F(DWriteFontProxyImplUnitTest, GetFontFiles) {
   UINT32 arial_index = 0;
-  Send(new DWriteFontProxyMsg_FindFamily(L"Arial", &arial_index));
-  filter_->ResetReply();
+  dwrite_font_proxy().FindFamily(L"Arial", &arial_index);
 
-  std::vector<base::string16> files;
-  std::vector<IPC::PlatformFileForTransit> handles;
-  Send(new DWriteFontProxyMsg_GetFontFiles(arial_index, &files, &handles));
+  std::vector<base::FilePath> files;
+  std::vector<base::File> handles;
+  dwrite_font_proxy().GetFontFiles(arial_index, &files, &handles);
 
   EXPECT_LT(0u, files.size());
-  for (const base::string16& file : files) {
-    EXPECT_STRNE(L"", file.c_str());
+  for (const auto& file : files) {
+    EXPECT_FALSE(file.value().empty());
   }
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, GetFontFilesIndexOutOfBounds) {
-  std::vector<base::string16> files;
-  std::vector<IPC::PlatformFileForTransit> handles;
+TEST_F(DWriteFontProxyImplUnitTest, GetFontFilesIndexOutOfBounds) {
+  std::vector<base::FilePath> files;
+  std::vector<base::File> handles;
   UINT32 invalid_index = 1000000;
-  Send(new DWriteFontProxyMsg_GetFontFiles(invalid_index, &files, &handles));
+  dwrite_font_proxy().GetFontFiles(invalid_index, &files, &handles);
 
   EXPECT_EQ(0u, files.size());
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, MapCharacter) {
+TEST_F(DWriteFontProxyImplUnitTest, MapCharacter) {
   if (!IsDWrite2Available())
     return;
 
-  DWriteFontStyle font_style;
-  font_style.font_weight = DWRITE_FONT_WEIGHT_NORMAL;
-  font_style.font_slant = DWRITE_FONT_STYLE_NORMAL;
-  font_style.font_stretch = DWRITE_FONT_STRETCH_NORMAL;
+  mojom::MapCharactersResultPtr result;
+  dwrite_font_proxy().MapCharacters(
+      L"abc",
+      mojom::DWriteFontStyle::New(DWRITE_FONT_WEIGHT_NORMAL,
+                                  DWRITE_FONT_STYLE_NORMAL,
+                                  DWRITE_FONT_STRETCH_NORMAL),
+      L"", DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, L"", &result);
 
-  MapCharactersResult result;
-  Send(new DWriteFontProxyMsg_MapCharacters(
-      L"abc", font_style, L"", DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, L"",
-      &result));
-
-  EXPECT_NE(UINT32_MAX, result.family_index);
-  EXPECT_STRNE(L"", result.family_name.c_str());
-  EXPECT_EQ(3u, result.mapped_length);
-  EXPECT_NE(0.0, result.scale);
-  EXPECT_NE(0, result.font_style.font_weight);
-  EXPECT_EQ(DWRITE_FONT_STYLE_NORMAL, result.font_style.font_slant);
-  EXPECT_NE(0, result.font_style.font_stretch);
+  EXPECT_NE(UINT32_MAX, result->family_index);
+  EXPECT_STRNE(L"", result->family_name.c_str());
+  EXPECT_EQ(3u, result->mapped_length);
+  EXPECT_NE(0.0, result->scale);
+  EXPECT_NE(0, result->font_style->font_weight);
+  EXPECT_EQ(DWRITE_FONT_STYLE_NORMAL, result->font_style->font_slant);
+  EXPECT_NE(0, result->font_style->font_stretch);
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, MapCharacterInvalidCharacter) {
+TEST_F(DWriteFontProxyImplUnitTest, MapCharacterInvalidCharacter) {
   if (!IsDWrite2Available())
     return;
 
-  DWriteFontStyle font_style;
-  font_style.font_weight = DWRITE_FONT_WEIGHT_NORMAL;
-  font_style.font_slant = DWRITE_FONT_STYLE_NORMAL;
-  font_style.font_stretch = DWRITE_FONT_STRETCH_NORMAL;
+  mojom::MapCharactersResultPtr result;
+  dwrite_font_proxy().MapCharacters(
+      L"\ufffe\uffffabc",
+      mojom::DWriteFontStyle::New(DWRITE_FONT_WEIGHT_NORMAL,
+                                  DWRITE_FONT_STYLE_NORMAL,
+                                  DWRITE_FONT_STRETCH_NORMAL),
+      L"en-us", DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, L"", &result);
 
-  MapCharactersResult result;
-  Send(new DWriteFontProxyMsg_MapCharacters(
-      L"\ufffe\uffffabc", font_style, L"en-us",
-      DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, L"", &result));
-
-  EXPECT_EQ(UINT32_MAX, result.family_index);
-  EXPECT_STREQ(L"", result.family_name.c_str());
-  EXPECT_EQ(2u, result.mapped_length);
+  EXPECT_EQ(UINT32_MAX, result->family_index);
+  EXPECT_STREQ(L"", result->family_name.c_str());
+  EXPECT_EQ(2u, result->mapped_length);
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, MapCharacterInvalidAfterValid) {
+TEST_F(DWriteFontProxyImplUnitTest, MapCharacterInvalidAfterValid) {
   if (!IsDWrite2Available())
     return;
 
-  DWriteFontStyle font_style;
-  font_style.font_weight = DWRITE_FONT_WEIGHT_NORMAL;
-  font_style.font_slant = DWRITE_FONT_STYLE_NORMAL;
-  font_style.font_stretch = DWRITE_FONT_STRETCH_NORMAL;
+  mojom::MapCharactersResultPtr result;
+  dwrite_font_proxy().MapCharacters(
+      L"abc\ufffe\uffff",
+      mojom::DWriteFontStyle::New(DWRITE_FONT_WEIGHT_NORMAL,
+                                  DWRITE_FONT_STYLE_NORMAL,
+                                  DWRITE_FONT_STRETCH_NORMAL),
+      L"en-us", DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, L"", &result);
 
-  MapCharactersResult result;
-  Send(new DWriteFontProxyMsg_MapCharacters(
-      L"abc\ufffe\uffff", font_style, L"en-us",
-      DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, L"", &result));
-
-  EXPECT_NE(UINT32_MAX, result.family_index);
-  EXPECT_STRNE(L"", result.family_name.c_str());
-  EXPECT_EQ(3u, result.mapped_length);
-  EXPECT_NE(0.0, result.scale);
-  EXPECT_NE(0, result.font_style.font_weight);
-  EXPECT_EQ(DWRITE_FONT_STYLE_NORMAL, result.font_style.font_slant);
-  EXPECT_NE(0, result.font_style.font_stretch);
+  EXPECT_NE(UINT32_MAX, result->family_index);
+  EXPECT_STRNE(L"", result->family_name.c_str());
+  EXPECT_EQ(3u, result->mapped_length);
+  EXPECT_NE(0.0, result->scale);
+  EXPECT_NE(0, result->font_style->font_weight);
+  EXPECT_EQ(DWRITE_FONT_STYLE_NORMAL, result->font_style->font_slant);
+  EXPECT_NE(0, result->font_style->font_stretch);
 }
 
-TEST_F(DWriteFontProxyMessageFilterUnitTest, TestCustomFontFiles) {
+TEST_F(DWriteFontProxyImplUnitTest, TestCustomFontFiles) {
   // Override windows fonts path to force the custom font file codepath.
-  filter_->SetWindowsFontsPathForTesting(L"X:\\NotWindowsFonts");
-  // Set the peer process so the filter duplicates handles into the current
-  // process.
-  filter_->set_peer_process_for_testing(base::Process::Current());
+  impl_.SetWindowsFontsPathForTesting(L"X:\\NotWindowsFonts");
 
   UINT32 arial_index = 0;
-  Send(new DWriteFontProxyMsg_FindFamily(L"Arial", &arial_index));
-  filter_->ResetReply();
+  dwrite_font_proxy().FindFamily(L"Arial", &arial_index);
 
-  std::vector<base::string16> files;
-  std::vector<IPC::PlatformFileForTransit> handles;
-  Send(new DWriteFontProxyMsg_GetFontFiles(arial_index, &files, &handles));
+  std::vector<base::FilePath> files;
+  std::vector<base::File> handles;
+  dwrite_font_proxy().GetFontFiles(arial_index, &files, &handles);
 
   EXPECT_TRUE(files.empty());
   EXPECT_FALSE(handles.empty());
-  for (const IPC::PlatformFileForTransit& handle : handles) {
-    EXPECT_TRUE(handle.IsValid());
-    base::File file = IPC::PlatformFileForTransitToFile(handle);
+  for (auto& file : handles) {
+    EXPECT_TRUE(file.IsValid());
     EXPECT_LT(0, file.GetLength());  // Check the file exists
   }
 }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 928c26b0..959cbbf 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -227,7 +227,6 @@
 #if defined(OS_WIN)
 #include "base/win/scoped_com_initializer.h"
 #include "base/win/windows_version.h"
-#include "content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #include "services/service_manager/sandbox/win/sandbox_win.h"
 #include "ui/display/win/dpi.h"
@@ -1777,8 +1776,6 @@
       base::WrapRefCounted(storage_partition_impl_->GetFileSystemContext())));
 #if defined(OS_MACOSX)
   AddFilter(new TextInputClientMessageFilter());
-#elif defined(OS_WIN)
-  AddFilter(new DWriteFontProxyMessageFilter());
 #endif
 
   scoped_refptr<CacheStorageDispatcherHost> cache_storage_filter =
diff --git a/content/browser/service_manager/common_browser_interfaces.cc b/content/browser/service_manager/common_browser_interfaces.cc
index 1376dea..caa6252 100644
--- a/content/browser/service_manager/common_browser_interfaces.cc
+++ b/content/browser/service_manager/common_browser_interfaces.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/task_runner.h"
+#include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "components/discardable_memory/service/discardable_shared_memory_manager.h"
 #include "content/browser/browser_main_loop.h"
@@ -22,6 +23,7 @@
 #include "ui/base/ui_base_switches.h"
 
 #if defined(OS_WIN)
+#include "content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h"
 #include "content/common/font_cache_dispatcher_win.h"
 #endif
 
@@ -43,6 +45,10 @@
   ConnectionFilterImpl() {
 #if defined(OS_WIN)
     registry_.AddInterface(base::BindRepeating(&FontCacheDispatcher::Create));
+    registry_.AddInterface(
+        base::BindRepeating(&DWriteFontProxyImpl::Create),
+        base::CreateSequencedTaskRunnerWithTraits(
+            {base::TaskPriority::USER_BLOCKING, base::MayBlock()}));
 #endif
     if (!IsRunningWithMus()) {
       // For mus, the mojom::discardable_memory::DiscardableSharedMemoryManager
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index cdb87ff..1075566 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -81,10 +81,6 @@
 #include "jni/ContentNfcDelegate_jni.h"
 #endif
 
-#if defined(OS_WIN)
-#include "content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h"
-#endif
-
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
 #endif
@@ -133,10 +129,6 @@
   } else {
     // Start a new process for this service.
     UtilityProcessHostImpl* impl = new UtilityProcessHostImpl(nullptr, nullptr);
-#if defined(OS_WIN)
-    if (sandbox_type == service_manager::SANDBOX_TYPE_PDF_COMPOSITOR)
-      impl->AddFilter(new DWriteFontProxyMessageFilter());
-#endif
     impl->SetName(process_name);
     impl->SetServiceIdentity(service_manager::Identity(service_name));
     impl->SetSandboxType(sandbox_type);
diff --git a/content/browser/service_worker/OWNERS b/content/browser/service_worker/OWNERS
index c028a7d..6e75cbe 100644
--- a/content/browser/service_worker/OWNERS
+++ b/content/browser/service_worker/OWNERS
@@ -8,6 +8,7 @@
 #   //third_party/WebKit/common/service_worker/
 #   //third_party/WebKit/public/web/modules/serviceworker/
 #   //third_party/WebKit/public/platform/modules/serviceworker/
+#   //third_party/WebKit/LayoutTests/external/wpt/service-workers/
 #   //third_party/WebKit/Source/modules/serviceworkers/
 
 falken@chromium.org
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc
index 6f97811..dbb9e2e 100644
--- a/content/browser/service_worker/service_worker_client_utils.cc
+++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -41,7 +41,7 @@
 
 using OpenURLCallback = base::Callback<void(int, int)>;
 using GetWindowClientsCallback =
-    base::Callback<void(std::unique_ptr<ServiceWorkerClients>)>;
+    base::Callback<void(std::unique_ptr<ServiceWorkerClientPtrs>)>;
 
 // The OpenURLObserver class is a WebContentsObserver that will wait for a
 // WebContents to be initialized, run the |callback| passed to its constructor
@@ -311,24 +311,25 @@
                                          host->client_uuid()));
 }
 
-void AddNonWindowClient(ServiceWorkerProviderHost* host,
-                        const ServiceWorkerClientQueryOptions& options,
-                        ServiceWorkerClients* clients) {
+void AddNonWindowClient(
+    const ServiceWorkerProviderHost* host,
+    blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
+    ServiceWorkerClientPtrs* out_clients) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   blink::mojom::ServiceWorkerClientType host_client_type = host->client_type();
   if (host_client_type == blink::mojom::ServiceWorkerClientType::kWindow)
     return;
-  if (options.client_type != blink::mojom::ServiceWorkerClientType::kAll &&
-      options.client_type != host_client_type)
+  if (options->client_type != blink::mojom::ServiceWorkerClientType::kAll &&
+      options->client_type != host_client_type)
     return;
 
-  blink::mojom::ServiceWorkerClientInfo client_info(
+  auto client_info = blink::mojom::ServiceWorkerClientInfo::New(
       host->document_url(), host->client_uuid(), host_client_type,
       blink::mojom::PageVisibilityState::kHidden,
       false,  // is_focused
       network::mojom::RequestContextFrameType::kNone, base::TimeTicks(),
       host->create_time());
-  clients->push_back(client_info);
+  out_clients->push_back(std::move(client_info));
 }
 
 void OnGetWindowClientsOnUI(
@@ -337,7 +338,7 @@
         clients_info,
     const GURL& script_url,
     const GetWindowClientsCallback& callback,
-    std::unique_ptr<ServiceWorkerClients> clients) {
+    std::unique_ptr<ServiceWorkerClientPtrs> out_clients) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   for (const auto& it : clients_info) {
@@ -357,37 +358,37 @@
     if (info.url.GetOrigin() != script_url.GetOrigin())
       continue;
 
-    clients->push_back(info);
+    out_clients->push_back(info.Clone());
   }
 
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                          base::BindOnce(callback, base::Passed(&clients)));
+                          base::BindOnce(callback, base::Passed(&out_clients)));
 }
 
 struct ServiceWorkerClientInfoSort {
-  bool operator()(const blink::mojom::ServiceWorkerClientInfo& a,
-                  const blink::mojom::ServiceWorkerClientInfo& b) const {
+  bool operator()(const blink::mojom::ServiceWorkerClientInfoPtr& a,
+                  const blink::mojom::ServiceWorkerClientInfoPtr& b) const {
     // Clients for windows should be appeared earlier.
-    if (a.client_type == blink::mojom::ServiceWorkerClientType::kWindow &&
-        b.client_type != blink::mojom::ServiceWorkerClientType::kWindow) {
+    if (a->client_type == blink::mojom::ServiceWorkerClientType::kWindow &&
+        b->client_type != blink::mojom::ServiceWorkerClientType::kWindow) {
       return true;
     }
-    if (a.client_type != blink::mojom::ServiceWorkerClientType::kWindow &&
-        b.client_type == blink::mojom::ServiceWorkerClientType::kWindow) {
+    if (a->client_type != blink::mojom::ServiceWorkerClientType::kWindow &&
+        b->client_type == blink::mojom::ServiceWorkerClientType::kWindow) {
       return false;
     }
 
     // Clients focused recently should be appeared earlier.
-    if (a.last_focus_time != b.last_focus_time)
-      return a.last_focus_time > b.last_focus_time;
+    if (a->last_focus_time != b->last_focus_time)
+      return a->last_focus_time > b->last_focus_time;
 
     // Clients created before should be appeared earlier.
-    return a.creation_time < b.creation_time;
+    return a->creation_time < b->creation_time;
   }
 };
 
 void DidGetClients(const ClientsCallback& callback,
-                   std::unique_ptr<ServiceWorkerClients> clients) {
+                   std::unique_ptr<ServiceWorkerClientPtrs> clients) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   std::sort(clients->begin(), clients->end(), ServiceWorkerClientInfoSort());
@@ -395,47 +396,51 @@
   callback.Run(std::move(clients));
 }
 
-void GetNonWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
-                         const ServiceWorkerClientQueryOptions& options,
-                         const ClientsCallback& callback,
-                         std::unique_ptr<ServiceWorkerClients> clients) {
+void GetNonWindowClients(
+    const base::WeakPtr<ServiceWorkerVersion>& controller,
+    blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
+    const ClientsCallback& callback,
+    std::unique_ptr<ServiceWorkerClientPtrs> clients) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (!options.include_uncontrolled) {
+  if (!options->include_uncontrolled) {
     for (auto& controllee : controller->controllee_map())
-      AddNonWindowClient(controllee.second, options, clients.get());
+      AddNonWindowClient(controllee.second, std::move(options), clients.get());
   } else if (controller->context()) {
     GURL origin = controller->script_url().GetOrigin();
     for (auto it = controller->context()->GetClientProviderHostIterator(origin);
          !it->IsAtEnd(); it->Advance()) {
-      AddNonWindowClient(it->GetProviderHost(), options, clients.get());
+      AddNonWindowClient(it->GetProviderHost(), std::move(options),
+                         clients.get());
     }
   }
   DidGetClients(callback, std::move(clients));
 }
 
-void DidGetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
-                         const ServiceWorkerClientQueryOptions& options,
-                         const ClientsCallback& callback,
-                         std::unique_ptr<ServiceWorkerClients> clients) {
+void DidGetWindowClients(
+    const base::WeakPtr<ServiceWorkerVersion>& controller,
+    blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
+    const ClientsCallback& callback,
+    std::unique_ptr<ServiceWorkerClientPtrs> clients) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (options.client_type == blink::mojom::ServiceWorkerClientType::kAll) {
-    GetNonWindowClients(controller, options, callback, std::move(clients));
+  if (options->client_type == blink::mojom::ServiceWorkerClientType::kAll) {
+    GetNonWindowClients(controller, std::move(options), callback,
+                        std::move(clients));
     return;
   }
   DidGetClients(callback, std::move(clients));
 }
 
 void GetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
-                      const ServiceWorkerClientQueryOptions& options,
+                      blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
                       const ClientsCallback& callback,
-                      std::unique_ptr<ServiceWorkerClients> clients) {
+                      std::unique_ptr<ServiceWorkerClientPtrs> clients) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(options.client_type ==
+  DCHECK(options->client_type ==
              blink::mojom::ServiceWorkerClientType::kWindow ||
-         options.client_type == blink::mojom::ServiceWorkerClientType::kAll);
+         options->client_type == blink::mojom::ServiceWorkerClientType::kAll);
 
   std::vector<std::tuple<int, int, base::TimeTicks, std::string>> clients_info;
-  if (!options.include_uncontrolled) {
+  if (!options->include_uncontrolled) {
     for (auto& controllee : controller->controllee_map())
       AddWindowClient(controllee.second, &clients_info);
   } else if (controller->context()) {
@@ -447,16 +452,18 @@
   }
 
   if (clients_info.empty()) {
-    DidGetWindowClients(controller, options, callback, std::move(clients));
+    DidGetWindowClients(controller, std::move(options), callback,
+                        std::move(clients));
     return;
   }
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &OnGetWindowClientsOnUI, clients_info, controller->script_url(),
-          base::Bind(&DidGetWindowClients, controller, options, callback),
-          base::Passed(&clients)));
+      base::BindOnce(&OnGetWindowClientsOnUI, clients_info,
+                     controller->script_url(),
+                     base::Bind(&DidGetWindowClients, controller,
+                                base::Passed(std::move(options)), callback),
+                     base::Passed(&clients)));
 }
 
 }  // namespace
@@ -534,24 +541,26 @@
 }
 
 void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
-                const ServiceWorkerClientQueryOptions& options,
+                blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
                 const ClientsCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  auto clients = std::make_unique<ServiceWorkerClients>();
-  if (!controller->HasControllee() && !options.include_uncontrolled) {
+  auto clients = std::make_unique<ServiceWorkerClientPtrs>();
+  if (!controller->HasControllee() && !options->include_uncontrolled) {
     DidGetClients(callback, std::move(clients));
     return;
   }
 
   // For Window clients we want to query the info on the UI thread first.
-  if (options.client_type == blink::mojom::ServiceWorkerClientType::kWindow ||
-      options.client_type == blink::mojom::ServiceWorkerClientType::kAll) {
-    GetWindowClients(controller, options, callback, std::move(clients));
+  if (options->client_type == blink::mojom::ServiceWorkerClientType::kWindow ||
+      options->client_type == blink::mojom::ServiceWorkerClientType::kAll) {
+    GetWindowClients(controller, std::move(options), callback,
+                     std::move(clients));
     return;
   }
 
-  GetNonWindowClients(controller, options, callback, std::move(clients));
+  GetNonWindowClients(controller, std::move(options), callback,
+                      std::move(clients));
 }
 
 }  // namespace service_worker_client_utils
diff --git a/content/browser/service_worker/service_worker_client_utils.h b/content/browser/service_worker/service_worker_client_utils.h
index 4863d76a..19e8f50b 100644
--- a/content/browser/service_worker/service_worker_client_utils.h
+++ b/content/browser/service_worker/service_worker_client_utils.h
@@ -21,7 +21,6 @@
 class ServiceWorkerContextCore;
 class ServiceWorkerProviderHost;
 class ServiceWorkerVersion;
-struct ServiceWorkerClientQueryOptions;
 
 namespace service_worker_client_utils {
 
@@ -30,9 +29,10 @@
     const blink::mojom::ServiceWorkerClientInfo& client_info)>;
 using ClientCallback = base::Callback<void(
     const blink::mojom::ServiceWorkerClientInfo& client_info)>;
-using ServiceWorkerClients = std::vector<blink::mojom::ServiceWorkerClientInfo>;
+using ServiceWorkerClientPtrs =
+    std::vector<blink::mojom::ServiceWorkerClientInfoPtr>;
 using ClientsCallback =
-    base::Callback<void(std::unique_ptr<ServiceWorkerClients> clients)>;
+    base::Callback<void(std::unique_ptr<ServiceWorkerClientPtrs> clients)>;
 
 // Focuses the window client associated with |provider_host|. |callback| is
 // called with the client information on completion.
@@ -65,7 +65,7 @@
 // Collects clients matched with |options|. |callback| is called with the client
 // information sorted in MRU order (most recently focused order) on completion.
 void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller,
-                const ServiceWorkerClientQueryOptions& options,
+                blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
                 const ClientsCallback& callback);
 
 }  // namespace service_worker_client_utils
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index e41496a..3cfc33c 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -46,7 +46,6 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
 #include "third_party/WebKit/common/origin_trials/trial_token_validator.h"
-#include "third_party/WebKit/common/service_worker/service_worker_client.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_error_type.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_installed_scripts_manager.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
@@ -999,8 +998,6 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClient, OnGetClient)
-    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients,
-                        OnGetClients)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenNewTab, OnOpenNewTab)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenNewPopup, OnOpenNewPopup)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient,
@@ -1074,6 +1071,31 @@
                           base::nullopt);
 }
 
+void ServiceWorkerVersion::GetClients(
+    blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
+    GetClientsCallback callback) {
+  service_worker_client_utils::GetClients(
+      weak_factory_.GetWeakPtr(), std::move(options),
+      base::Bind(&ServiceWorkerVersion::OnGetClientsFinished,
+                 weak_factory_.GetWeakPtr(),
+                 base::Passed(std::move(callback))));
+}
+
+void ServiceWorkerVersion::OnGetClientsFinished(
+    GetClientsCallback callback,
+    std::unique_ptr<ServiceWorkerClientPtrs> clients) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  // When Clients.matchAll() is called on the script evaluation phase, the
+  // running status can be STARTING here.
+  if (running_status() != EmbeddedWorkerStatus::STARTING &&
+      running_status() != EmbeddedWorkerStatus::RUNNING) {
+    return;
+  }
+
+  std::move(callback).Run(std::move(*clients));
+}
+
 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64_t callback_id,
                                                        size_t size,
                                                        int result) {
@@ -1132,38 +1154,6 @@
       ServiceWorkerMsg_DidGetClient(request_id, client_info));
 }
 
-void ServiceWorkerVersion::OnGetClients(
-    int request_id,
-    const ServiceWorkerClientQueryOptions& options) {
-  TRACE_EVENT_ASYNC_BEGIN2(
-      "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id,
-      "client_type",
-      ServiceWorkerUtils::ClientTypeToString(options.client_type),
-      "include_uncontrolled", options.include_uncontrolled);
-  service_worker_client_utils::GetClients(
-      weak_factory_.GetWeakPtr(), options,
-      base::Bind(&ServiceWorkerVersion::OnGetClientsFinished,
-                 weak_factory_.GetWeakPtr(), request_id));
-}
-
-void ServiceWorkerVersion::OnGetClientsFinished(
-    int request_id,
-    std::unique_ptr<ServiceWorkerClients> clients) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClients",
-                         request_id, "The number of clients", clients->size());
-
-  // When Clients.matchAll() is called on the script evaluation phase, the
-  // running status can be STARTING here.
-  if (running_status() != EmbeddedWorkerStatus::STARTING &&
-      running_status() != EmbeddedWorkerStatus::RUNNING) {
-    return;
-  }
-
-  embedded_worker_->SendIpcMessage(
-      ServiceWorkerMsg_DidGetClients(request_id, *clients));
-}
-
 void ServiceWorkerVersion::OnSimpleEventFinished(
     int request_id,
     blink::mojom::ServiceWorkerEventStatus status,
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 9e35eb3..5d0358a 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -43,6 +43,7 @@
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/WebKit/common/origin_trials/trial_token_validator.h"
 #include "third_party/WebKit/common/service_worker/service_worker.mojom.h"
+#include "third_party/WebKit/common/service_worker/service_worker_client.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_event_status.mojom.h"
 #include "ui/base/mojo/window_open_disposition.mojom.h"
 #include "url/gurl.h"
@@ -570,8 +571,8 @@
     std::set<InflightRequestTimeoutInfo>::iterator timeout_iter;
   };
 
-  using ServiceWorkerClients =
-      std::vector<blink::mojom::ServiceWorkerClientInfo>;
+  using ServiceWorkerClientPtrs =
+      std::vector<blink::mojom::ServiceWorkerClientInfoPtr>;
 
   // The timeout timer interval.
   static constexpr base::TimeDelta kTimeoutTimerDelay =
@@ -619,6 +620,8 @@
                          const std::vector<uint8_t>& data) override;
   void ClearCachedMetadata(const GURL& url) override;
   void ClaimClients(ClaimClientsCallback callback) override;
+  void GetClients(blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
+                  GetClientsCallback callback) override;
 
   void OnSetCachedMetadataFinished(int64_t callback_id,
                                    size_t size,
@@ -630,10 +633,6 @@
   // This corresponds to the spec's get(id) steps.
   void OnGetClient(int request_id, const std::string& client_uuid);
 
-  // This corresponds to the spec's matchAll(options) steps.
-  void OnGetClients(int request_id,
-                    const ServiceWorkerClientQueryOptions& options);
-
   // Currently used for Clients.openWindow() only.
   void OnOpenNewTab(int request_id, const GURL& url);
 
@@ -689,8 +688,8 @@
       int request_id,
       const blink::mojom::ServiceWorkerClientInfo& client_info);
 
-  void OnGetClientsFinished(int request_id,
-                            std::unique_ptr<ServiceWorkerClients> clients);
+  void OnGetClientsFinished(GetClientsCallback callback,
+                            std::unique_ptr<ServiceWorkerClientPtrs> clients);
 
   // The timeout timer periodically calls OnTimeoutTimer, which stops the worker
   // if it is excessively idle or unresponsive to ping.
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 5bbd760..25e1b0e 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -588,7 +588,10 @@
   }
 
 #if defined(OS_WIN)
-  UpdateDWriteFontProxySender(thread_safe_sender());
+  mojom::DWriteFontProxyPtrInfo dwrite_font_proxy;
+  ChildThread::Get()->GetConnector()->BindInterface(
+      mojom::kBrowserServiceName, mojo::MakeRequest(&dwrite_font_proxy));
+  UpdateDWriteFontProxySender(std::move(dwrite_font_proxy));
 #endif
 }
 
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.cc b/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.cc
index 123353a1..da14147 100644
--- a/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.cc
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.cc
@@ -11,11 +11,9 @@
 #include "base/debug/alias.h"
 #include "base/win/iat_patch_function.h"
 #include "base/win/windows_version.h"
-#include "content/child/child_thread_impl.h"
 #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
 #include "content/child/dwrite_font_proxy/font_fallback_win.h"
 #include "content/child/font_warmup_win.h"
-#include "content/child/thread_safe_sender.h"
 #include "skia/ext/fontmgr_default_win.h"
 #include "third_party/WebKit/public/web/win/WebFontRendering.h"
 #include "third_party/skia/include/ports/SkFontMgr.h"
@@ -29,7 +27,8 @@
 
 mswr::ComPtr<DWriteFontCollectionProxy> g_font_collection;
 mswr::ComPtr<FontFallback> g_font_fallback;
-IPC::Sender* g_sender_override = nullptr;
+base::RepeatingCallback<mojom::DWriteFontProxyPtrInfo(void)>*
+    g_connection_callback_override = nullptr;
 
 // Windows-only DirectWrite support. These warm up the DirectWrite paths
 // before sandbox lock down to allow Skia access to the Font Manager service.
@@ -45,11 +44,9 @@
 
 }  // namespace
 
-void UpdateDWriteFontProxySender(IPC::Sender* sender) {
+void UpdateDWriteFontProxySender(mojom::DWriteFontProxyPtrInfo proxy) {
   if (g_font_collection)
-    g_font_collection.Get()->SetSenderOverride(sender);
-  if (g_font_fallback)
-    g_font_fallback.Get()->SetSenderOverride(sender);
+    g_font_collection->SetProxy(std::move(proxy));
 }
 
 void InitializeDWriteFontProxy() {
@@ -57,23 +54,19 @@
 
   CreateDirectWriteFactory(&factory);
 
-  IPC::Sender* sender = g_sender_override;
-
-  // Hack for crbug.com/631254: set the sender if we can get one, so that when
-  // Flash calls into the font proxy from a different thread we will have a
-  // sender available.
-  if (!sender && ChildThreadImpl::current())
-    sender = ChildThreadImpl::current()->thread_safe_sender();
-
   if (!g_font_collection) {
+    mojom::DWriteFontProxyPtrInfo dwrite_font_proxy;
+    if (g_connection_callback_override) {
+      dwrite_font_proxy = g_connection_callback_override->Run();
+    }
     DWriteFontCollectionProxy::Create(&g_font_collection, factory.Get(),
-                                      sender);
+                                      std::move(dwrite_font_proxy));
   }
 
   mswr::ComPtr<IDWriteFactory2> factory2;
 
   if (SUCCEEDED(factory.As(&factory2)) && factory2.Get()) {
-    FontFallback::Create(&g_font_fallback, g_font_collection.Get(), sender);
+    FontFallback::Create(&g_font_fallback, g_font_collection.Get());
   }
 
   sk_sp<SkFontMgr> skia_font_manager = SkFontMgr_New_DirectWrite(
@@ -100,8 +93,17 @@
     g_font_collection->Unregister();
 }
 
-void SetDWriteFontProxySenderForTesting(IPC::Sender* sender) {
-  g_sender_override = sender;
+void SetDWriteFontProxySenderForTesting(
+    base::RepeatingCallback<mojom::DWriteFontProxyPtrInfo(void)> sender) {
+  DCHECK(!g_connection_callback_override);
+  g_connection_callback_override =
+      new base::RepeatingCallback<mojom::DWriteFontProxyPtrInfo(void)>(
+          std::move(sender));
+}
+
+void ClearDWriteFontProxySenderForTesting() {
+  delete g_connection_callback_override;
+  g_connection_callback_override = nullptr;
 }
 
 }  // namespace content
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.h b/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.h
index c987aea..550821e 100644
--- a/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.h
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.h
@@ -7,19 +7,23 @@
 
 #include "base/callback.h"
 #include "content/common/content_export.h"
+#include "content/common/dwrite_font_proxy.mojom.h"
 #include "content/public/child/dwrite_font_proxy_init_win.h"
-#include "ipc/ipc_sender.h"
 
 namespace content {
 
 // Configures the dwrite font proxy to use the specified sender. This can be
 // useful in tests which use a fake render thread which is unable to process
 // font IPC messages. This should only be called when running as a test.
-CONTENT_EXPORT void SetDWriteFontProxySenderForTesting(IPC::Sender* sender);
+CONTENT_EXPORT void SetDWriteFontProxySenderForTesting(
+    base::RepeatingCallback<mojom::DWriteFontProxyPtrInfo(void)> sender);
+
+// Cleans up the fake dwrite font proxy connection factory.
+CONTENT_EXPORT void ClearDWriteFontProxySenderForTesting();
 
 // Allows ChildThreadImpl to register a thread safe sender to DWriteFontProxy
 // so we don't depend on being on the main thread to use DWriteFontProxy.
-CONTENT_EXPORT void UpdateDWriteFontProxySender(IPC::Sender*);
+CONTENT_EXPORT void UpdateDWriteFontProxySender(mojom::DWriteFontProxyPtrInfo);
 
 }  // namespace content
 
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc
index 31937fc..999c250f 100644
--- a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc
@@ -14,12 +14,11 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/win/scoped_handle.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/child/dwrite_font_proxy/dwrite_localized_strings_win.h"
-#include "content/common/dwrite_font_proxy_messages.h"
 #include "content/public/child/child_thread.h"
-#include "ipc/ipc_platform_file.h"
-#include "ipc/ipc_sender.h"
+#include "content/public/common/service_names.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace mswr = Microsoft::WRL;
 
@@ -75,9 +74,9 @@
 
 HRESULT DWriteFontCollectionProxy::Create(DWriteFontCollectionProxy** proxy_out,
                                           IDWriteFactory* dwrite_factory,
-                                          IPC::Sender* sender) {
+                                          mojom::DWriteFontProxyPtrInfo proxy) {
   return Microsoft::WRL::MakeAndInitialize<DWriteFontCollectionProxy>(
-      proxy_out, dwrite_factory, sender);
+      proxy_out, dwrite_factory, std::move(proxy));
 }
 
 DWriteFontCollectionProxy::DWriteFontCollectionProxy() = default;
@@ -102,8 +101,7 @@
     return S_OK;
   }
 
-  if (!GetSender()->Send(
-          new DWriteFontProxyMsg_FindFamily(name, &family_index))) {
+  if (!GetFontProxy().FindFamily(name, &family_index)) {
     LogFontProxyError(FIND_FAMILY_SEND_FAILED);
     return E_FAIL;
   }
@@ -147,8 +145,7 @@
   TRACE_EVENT0("dwrite", "FontProxy::GetFontFamilyCount");
 
   uint32_t family_count = 0;
-  if (!GetSender()->Send(
-          new DWriteFontProxyMsg_GetFamilyCount(&family_count))) {
+  if (!GetFontProxy().GetFamilyCount(&family_count)) {
     LogFontProxyError(GET_FAMILY_COUNT_SEND_FAILED);
     return 0;
   }
@@ -198,29 +195,28 @@
   // If we already loaded the family we should reuse the existing collection.
   DCHECK(!families_[*family_index]->IsLoaded());
 
-  std::vector<base::string16> file_names;
-  std::vector<IPC::PlatformFileForTransit> file_handles;
-  if (!GetSender()->Send(new DWriteFontProxyMsg_GetFontFiles(
-          *family_index, &file_names, &file_handles))) {
+  std::vector<base::FilePath> file_names;
+  std::vector<base::File> file_handles;
+  if (!GetFontProxy().GetFontFiles(*family_index, &file_names, &file_handles)) {
     LogFontProxyError(GET_FONT_FILES_SEND_FAILED);
     return E_FAIL;
   }
 
   std::vector<HANDLE> handles;
   handles.reserve(file_names.size() + file_handles.size());
-  for (const base::string16& file_name : file_names) {
+  for (const base::FilePath& file_name : file_names) {
     // This leaks the handles, since they are used as the reference key to
     // CreateStreamFromKey, and DirectWrite requires the reference keys to
     // remain valid for the lifetime of the loader. The loader is the font
     // collection proxy, which remains alive for the lifetime of the renderer.
     HANDLE handle =
-        CreateFile(file_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
-                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+        CreateFile(file_name.value().c_str(), GENERIC_READ, FILE_SHARE_READ,
+                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
     if (handle != INVALID_HANDLE_VALUE)
       handles.push_back(handle);
   }
-  for (const IPC::PlatformFileForTransit& file_handle : file_handles) {
-    handles.push_back(IPC::PlatformFileForTransitToPlatformFile(file_handle));
+  for (auto& file_handle : file_handles) {
+    handles.push_back(file_handle.TakePlatformFile());
   }
 
   HRESULT hr = mswr::MakeAndInitialize<FontFileEnumerator>(
@@ -264,11 +260,12 @@
 
 HRESULT DWriteFontCollectionProxy::RuntimeClassInitialize(
     IDWriteFactory* factory,
-    IPC::Sender* sender_override) {
+    mojom::DWriteFontProxyPtrInfo proxy) {
   DCHECK(factory);
 
   factory_ = factory;
-  sender_override_ = sender_override;
+  if (proxy)
+    SetProxy(std::move(proxy));
 
   HRESULT hr = factory->RegisterFontCollectionLoader(this);
   DCHECK(SUCCEEDED(hr));
@@ -318,11 +315,14 @@
     IDWriteLocalizedStrings** localized_strings) {
   TRACE_EVENT0("dwrite", "FontProxy::LoadFamilyNames");
 
-  std::vector<std::pair<base::string16, base::string16>> strings;
-  if (!GetSender()->Send(
-          new DWriteFontProxyMsg_GetFamilyNames(family_index, &strings))) {
+  std::vector<mojom::DWriteStringPairPtr> pairs;
+  if (!GetFontProxy().GetFamilyNames(family_index, &pairs)) {
     return false;
   }
+  std::vector<std::pair<base::string16, base::string16>> strings;
+  for (auto& pair : pairs) {
+    strings.emplace_back(std::move(pair->first), std::move(pair->second));
+  }
 
   HRESULT hr = mswr::MakeAndInitialize<DWriteLocalizedStrings>(
       localized_strings, &strings);
@@ -352,8 +352,20 @@
   return true;
 }
 
-IPC::Sender* DWriteFontCollectionProxy::GetSender() {
-  return sender_override_ ? sender_override_ : ChildThread::Get();
+void DWriteFontCollectionProxy::SetProxy(mojom::DWriteFontProxyPtrInfo proxy) {
+  font_proxy_ = mojom::ThreadSafeDWriteFontProxyPtr::Create(
+      std::move(proxy), base::CreateSequencedTaskRunnerWithTraits(
+                            {base::WithBaseSyncPrimitives()}));
+}
+
+mojom::DWriteFontProxy& DWriteFontCollectionProxy::GetFontProxy() {
+  if (!font_proxy_) {
+    mojom::DWriteFontProxyPtrInfo dwrite_font_proxy;
+    ChildThread::Get()->GetConnector()->BindInterface(
+        mojom::kBrowserServiceName, mojo::MakeRequest(&dwrite_font_proxy));
+    SetProxy(std::move(dwrite_font_proxy));
+  }
+  return **font_proxy_;
 }
 
 DWriteFontFamilyProxy::DWriteFontFamilyProxy() = default;
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.h b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.h
index 3d01477d..0b065c65 100644
--- a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.h
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.h
@@ -16,10 +16,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
-
-namespace IPC {
-class Sender;
-}
+#include "content/common/dwrite_font_proxy.mojom.h"
 
 namespace content {
 
@@ -40,7 +37,7 @@
   // Factory method to avoid exporting the class and all it derives from.
   static CONTENT_EXPORT HRESULT Create(DWriteFontCollectionProxy** proxy_out,
                                        IDWriteFactory* dwrite_factory,
-                                       IPC::Sender* sender);
+                                       mojom::DWriteFontProxyPtrInfo proxy);
 
   // Use Create() to construct these objects. Direct calls to the constructor
   // are an error - it is only public because a WRL helper function creates the
@@ -72,7 +69,8 @@
                       IDWriteFontFileStream** font_file_stream) override;
 
   CONTENT_EXPORT HRESULT STDMETHODCALLTYPE
-  RuntimeClassInitialize(IDWriteFactory* factory, IPC::Sender* sender_override);
+  RuntimeClassInitialize(IDWriteFactory* factory,
+                         mojom::DWriteFontProxyPtrInfo proxy);
 
   CONTENT_EXPORT void Unregister();
 
@@ -89,16 +87,16 @@
 
   bool CreateFamily(UINT32 family_index);
 
-  void SetSenderOverride(IPC::Sender* sender) { sender_override_ = sender; }
+  void SetProxy(mojom::DWriteFontProxyPtrInfo);
+
+  mojom::DWriteFontProxy& GetFontProxy();
 
  private:
-  IPC::Sender* GetSender();
-
   Microsoft::WRL::ComPtr<IDWriteFactory> factory_;
   std::vector<Microsoft::WRL::ComPtr<DWriteFontFamilyProxy>> families_;
   std::map<base::string16, UINT32> family_names_;
   UINT32 family_count_ = UINT_MAX;
-  IPC::Sender* sender_override_;
+  scoped_refptr<mojom::ThreadSafeDWriteFontProxyPtr> font_proxy_;
 
   DISALLOW_ASSIGN(DWriteFontCollectionProxy);
 };
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_win_unittest.cc b/content/child/dwrite_font_proxy/dwrite_font_proxy_win_unittest.cc
index 9934295..dbac949 100644
--- a/content/child/dwrite_font_proxy/dwrite_font_proxy_win_unittest.cc
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_win_unittest.cc
@@ -11,11 +11,8 @@
 #include <memory>
 
 #include "base/memory/ref_counted.h"
-#include "content/common/dwrite_font_proxy_messages.h"
-#include "content/common/view_messages.h"
+#include "base/test/scoped_task_environment.h"
 #include "content/test/dwrite_font_fake_sender_win.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_sender.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mswr = Microsoft::WRL;
@@ -27,10 +24,10 @@
 class DWriteFontProxyUnitTest : public testing::Test {
  public:
   DWriteFontProxyUnitTest() {
-    fake_collection_ = new FakeFontCollection();
+    fake_collection_ = std::make_unique<FakeFontCollection>();
     SetupFonts(fake_collection_.get());
     DWriteFontCollectionProxy::Create(&collection_, factory.Get(),
-                                      fake_collection_->GetTrackingSender());
+                                      fake_collection_->CreatePtr());
     EXPECT_TRUE(collection_.Get());
   }
 
@@ -43,14 +40,14 @@
     fonts->AddFont(L"Aardvark")
         .AddFamilyName(L"en-us", L"Aardvark")
         .AddFamilyName(L"de-de", L"Erdferkel")
-        .AddFilePath(L"X:\\Nonexistent\\Folder\\Aardvark.ttf");
+        .AddFilePath(base::FilePath(L"X:\\Nonexistent\\Folder\\Aardvark.ttf"));
     FakeFont& arial =
         fonts->AddFont(L"Arial").AddFamilyName(L"en-us", L"Arial");
     for (auto& path : arial_font_files)
-      arial.AddFilePath(path);
+      arial.AddFilePath(base::FilePath(path));
     fonts->AddFont(L"Times New Roman")
         .AddFamilyName(L"en-us", L"Times New Roman")
-        .AddFilePath(L"X:\\Nonexistent\\Folder\\Times.ttf");
+        .AddFilePath(base::FilePath(L"X:\\Nonexistent\\Folder\\Times.ttf"));
   }
 
   static void SetUpTestCase() {
@@ -70,7 +67,8 @@
   }
 
  protected:
-  scoped_refptr<FakeFontCollection> fake_collection_;
+  base::test::ScopedTaskEnvironment task_environment;
+  std::unique_ptr<FakeFontCollection> fake_collection_;
   mswr::ComPtr<DWriteFontCollectionProxy> collection_;
 
   static std::vector<base::string16> arial_font_files;
@@ -84,8 +82,8 @@
 
   EXPECT_EQ(3u, family_count);
   ASSERT_EQ(1u, fake_collection_->MessageCount());
-  EXPECT_EQ(static_cast<uint32_t>(DWriteFontProxyMsg_GetFamilyCount::ID),
-            fake_collection_->GetIpcMessage(0)->type());
+  EXPECT_EQ(FakeFontCollection::MessageType::kGetFamilyCount,
+            fake_collection_->GetMessageType(0));
 
   // Calling again should not cause another message to be sent.
   family_count = collection_->GetFontFamilyCount();
@@ -104,10 +102,10 @@
   EXPECT_EQ(1u, index);
   EXPECT_TRUE(exists);
   ASSERT_EQ(2u, fake_collection_->MessageCount());
-  EXPECT_EQ(static_cast<uint32_t>(DWriteFontProxyMsg_FindFamily::ID),
-            fake_collection_->GetIpcMessage(0)->type());
-  EXPECT_EQ(static_cast<uint32_t>(DWriteFontProxyMsg_GetFamilyCount::ID),
-            fake_collection_->GetIpcMessage(1)->type());
+  EXPECT_EQ(FakeFontCollection::MessageType::kFindFamily,
+            fake_collection_->GetMessageType(0));
+  EXPECT_EQ(FakeFontCollection::MessageType::kGetFamilyCount,
+            fake_collection_->GetMessageType(1));
 }
 
 TEST_F(DWriteFontProxyUnitTest, FindFamilyNameShouldReturnUINTMAXWhenNotFound) {
@@ -121,8 +119,8 @@
   EXPECT_EQ(UINT32_MAX, index);
   EXPECT_FALSE(exists);
   ASSERT_EQ(1u, fake_collection_->MessageCount());
-  EXPECT_EQ(static_cast<uint32_t>(DWriteFontProxyMsg_FindFamily::ID),
-            fake_collection_->GetIpcMessage(0)->type());
+  EXPECT_EQ(FakeFontCollection::MessageType::kFindFamily,
+            fake_collection_->GetMessageType(0));
 }
 
 TEST_F(DWriteFontProxyUnitTest, FindFamilyNameShouldNotSendDuplicateIPC) {
@@ -202,8 +200,8 @@
   hr = family->GetFamilyNames(&names);
   EXPECT_EQ(S_OK, hr);
   EXPECT_EQ(3u, fake_collection_->MessageCount());
-  EXPECT_EQ(static_cast<uint32_t>(DWriteFontProxyMsg_GetFamilyNames::ID),
-            fake_collection_->GetIpcMessage(2)->type());
+  EXPECT_EQ(FakeFontCollection::MessageType::kGetFamilyNames,
+            fake_collection_->GetMessageType(2));
 
   EXPECT_EQ(2u, names->GetCount());
   UINT32 locale_index = 0;
@@ -288,8 +286,8 @@
   UINT32 font_count = family->GetFontCount();
   EXPECT_LT(0u, font_count);
   EXPECT_EQ(3u, fake_collection_->MessageCount());
-  EXPECT_EQ(static_cast<uint32_t>(DWriteFontProxyMsg_GetFontFiles::ID),
-            fake_collection_->GetIpcMessage(2)->type());
+  EXPECT_EQ(FakeFontCollection::MessageType::kGetFontFiles,
+            fake_collection_->GetMessageType(2));
   mswr::ComPtr<IDWriteFont> font;
   hr = family->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL,
                                     DWRITE_FONT_STRETCH_NORMAL,
@@ -335,17 +333,17 @@
 }
 
 TEST_F(DWriteFontProxyUnitTest, TestCustomFontFiles) {
-  scoped_refptr<FakeFontCollection> fonts = new FakeFontCollection();
-  FakeFont& arial = fonts->AddFont(L"Arial").AddFamilyName(L"en-us", L"Arial");
+  FakeFontCollection fonts;
+  FakeFont& arial = fonts.AddFont(L"Arial").AddFamilyName(L"en-us", L"Arial");
   for (auto& path : arial_font_files) {
     base::File file(base::FilePath(path), base::File::FLAG_OPEN |
                                               base::File::FLAG_READ |
                                               base::File::FLAG_EXCLUSIVE_WRITE);
-    arial.AddFileHandle(IPC::TakePlatformFileForTransit(std::move(file)));
+    arial.AddFileHandle(std::move(file));
   }
   mswr::ComPtr<DWriteFontCollectionProxy> collection;
   DWriteFontCollectionProxy::Create(&collection, factory.Get(),
-                                    fonts->GetTrackingSender());
+                                    fonts.CreatePtr());
 
   // Check that we can get the font family and match a font.
   UINT32 index = UINT_MAX;
diff --git a/content/child/dwrite_font_proxy/font_fallback_win.cc b/content/child/dwrite_font_proxy/font_fallback_win.cc
index d8642401..25dbef98 100644
--- a/content/child/dwrite_font_proxy/font_fallback_win.cc
+++ b/content/child/dwrite_font_proxy/font_fallback_win.cc
@@ -12,9 +12,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
-#include "content/common/dwrite_font_proxy_messages.h"
-#include "content/public/child/child_thread.h"
-#include "ipc/ipc_sender.h"
 
 namespace mswr = Microsoft::WRL;
 
@@ -44,10 +41,9 @@
 }  // namespace
 
 HRESULT FontFallback::Create(FontFallback** font_fallback_out,
-                             DWriteFontCollectionProxy* collection,
-                             IPC::Sender* sender) {
+                             DWriteFontCollectionProxy* collection) {
   return Microsoft::WRL::MakeAndInitialize<FontFallback>(font_fallback_out,
-                                                         collection, sender);
+                                                         collection);
 }
 
 FontFallback::FontFallback() = default;
@@ -102,18 +98,13 @@
 
   locale = locale ? locale : L"";
 
-  DWriteFontStyle style;
-  style.font_weight = base_weight;
-  style.font_slant = base_style;
-  style.font_stretch = base_stretch;
+  mojom::MapCharactersResultPtr result;
 
-  MapCharactersResult result;
-
-  IPC::Sender* sender =
-      sender_override_ ? sender_override_ : ChildThread::Get();
-  if (!sender->Send(new DWriteFontProxyMsg_MapCharacters(
-          text_chunk, style, locale, source->GetParagraphReadingDirection(),
-          base_family_name, &result))) {
+  if (!GetFontProxy().MapCharacters(
+          text_chunk,
+          mojom::DWriteFontStyle::New(base_weight, base_style, base_stretch),
+          locale, source->GetParagraphReadingDirection(), base_family_name,
+          &result)) {
     DCHECK(false);
     return E_FAIL;
   }
@@ -123,10 +114,10 @@
   // to consider whether it's worth doing the work to plumb it through.
   DCHECK(fabs(*scale - 1.0f) < 0.00001);
 
-  *mapped_length = result.mapped_length;
-  *scale = result.scale;
+  *mapped_length = result->mapped_length;
+  *scale = result->scale;
 
-  if (result.family_index == UINT32_MAX) {
+  if (result->family_index == UINT32_MAX) {
     LogFallbackResult(FAILED_NO_FONT);
     return S_OK;
   }
@@ -137,16 +128,16 @@
   // I can't find a way to get QueryInterface to return the actual class when
   // using mswr::RuntimeClass. If we could use QI, we can fallback on
   // FindFontFamily if the proxy is not available.
-  if (!collection_->GetFontFamily(result.family_index, result.family_name,
+  if (!collection_->GetFontFamily(result->family_index, result->family_name,
                                   &family)) {
     DCHECK(false);
     return E_FAIL;
   }
 
   if (FAILED(family->GetFirstMatchingFont(
-          static_cast<DWRITE_FONT_WEIGHT>(result.font_style.font_weight),
-          static_cast<DWRITE_FONT_STRETCH>(result.font_style.font_stretch),
-          static_cast<DWRITE_FONT_STYLE>(result.font_style.font_slant),
+          static_cast<DWRITE_FONT_WEIGHT>(result->font_style->font_weight),
+          static_cast<DWRITE_FONT_STRETCH>(result->font_style->font_stretch),
+          static_cast<DWRITE_FONT_STYLE>(result->font_style->font_slant),
           mapped_font))) {
     DCHECK(false);
     return E_FAIL;
@@ -159,9 +150,7 @@
 }
 
 HRESULT STDMETHODCALLTYPE
-FontFallback::RuntimeClassInitialize(DWriteFontCollectionProxy* collection,
-                                     IPC::Sender* sender_override) {
-  sender_override_ = sender_override;
+FontFallback::RuntimeClassInitialize(DWriteFontCollectionProxy* collection) {
   collection_ = collection;
   return S_OK;
 }
@@ -233,4 +222,8 @@
     family_list.pop_back();
 }
 
+mojom::DWriteFontProxy& FontFallback::GetFontProxy() {
+  return collection_->GetFontProxy();
+}
+
 }  // namespace content
diff --git a/content/child/dwrite_font_proxy/font_fallback_win.h b/content/child/dwrite_font_proxy/font_fallback_win.h
index 3277482..ca22abc 100644
--- a/content/child/dwrite_font_proxy/font_fallback_win.h
+++ b/content/child/dwrite_font_proxy/font_fallback_win.h
@@ -14,7 +14,7 @@
 
 #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
 #include "content/common/content_export.h"
-#include "ipc/ipc_sender.h"
+#include "content/common/dwrite_font_proxy.mojom.h"
 
 namespace content {
 
@@ -27,8 +27,7 @@
  public:
   // Factory method to avoid exporting the class and all it derives from.
   static CONTENT_EXPORT HRESULT Create(FontFallback** font_fallback_out,
-                                       DWriteFontCollectionProxy* collection,
-                                       IPC::Sender* sender);
+                                       DWriteFontCollectionProxy* collection);
 
   // Use Create() to construct these objects. Direct calls to the constructor
   // are an error - it is only public because a WRL helper function creates the
@@ -49,10 +48,7 @@
                 FLOAT* scale) override;
 
   HRESULT STDMETHODCALLTYPE
-  RuntimeClassInitialize(DWriteFontCollectionProxy* collection,
-                         IPC::Sender* sender_override);
-
-  void SetSenderOverride(IPC::Sender* sender) { sender_override_ = sender; }
+  RuntimeClassInitialize(DWriteFontCollectionProxy* collection);
 
  protected:
   ~FontFallback() override;
@@ -69,7 +65,8 @@
                        const wchar_t* base_family_name);
 
  private:
-  IPC::Sender* sender_override_;
+  mojom::DWriteFontProxy& GetFontProxy();
+
   Microsoft::WRL::ComPtr<DWriteFontCollectionProxy> collection_;
 
   // |fallback_family_cache_| keeps a mapping from base family name to a list
diff --git a/content/child/dwrite_font_proxy/font_fallback_win_unittest.cc b/content/child/dwrite_font_proxy/font_fallback_win_unittest.cc
index 64b54ff..56e4f00d 100644
--- a/content/child/dwrite_font_proxy/font_fallback_win_unittest.cc
+++ b/content/child/dwrite_font_proxy/font_fallback_win_unittest.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
+#include "base/test/scoped_task_environment.h"
 #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
 #include "content/test/dwrite_font_fake_sender_win.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -36,19 +37,20 @@
     font_path.resize(MAX_PATH);
     SHGetSpecialFolderPath(nullptr /* hwndOwner - reserved */, font_path.data(),
                            CSIDL_FONTS, FALSE /* fCreate*/);
-    base::string16 segoe_path;
-    segoe_path.append(font_path.data()).append(L"\\seguisym.ttf");
+    base::FilePath segoe_path = base::FilePath(base::string16(font_path.data()))
+                                    .Append(L"\\seguisym.ttf");
 
-    fake_collection_ = new FakeFontCollection();
+    fake_collection_ = std::make_unique<FakeFontCollection>();
     fake_collection_->AddFont(L"Segoe UI Symbol")
         .AddFamilyName(L"en-us", L"Segoe UI Symbol")
         .AddFilePath(segoe_path);
 
     DWriteFontCollectionProxy::Create(&collection_, factory_.Get(),
-                                      fake_collection_->GetSender());
+                                      fake_collection_->CreatePtr());
   }
 
-  scoped_refptr<FakeFontCollection> fake_collection_;
+  base::test::ScopedTaskEnvironment task_environment;
+  std::unique_ptr<FakeFontCollection> fake_collection_;
   mswr::ComPtr<IDWriteFactory> factory_;
   mswr::ComPtr<DWriteFontCollectionProxy> collection_;
   mswr::ComPtr<IDWriteNumberSubstitution> number_substitution_;
@@ -56,8 +58,7 @@
 
 TEST_F(FontFallbackUnitTest, MapCharacters) {
   mswr::ComPtr<FontFallback> fallback;
-  FontFallback::Create(&fallback, collection_.Get(),
-                       fake_collection_->GetSender());
+  FontFallback::Create(&fallback, collection_.Get());
 
   mswr::ComPtr<IDWriteFont> font;
   UINT32 mapped_length = 0;
@@ -78,8 +79,7 @@
 
 TEST_F(FontFallbackUnitTest, DuplicateCallsShouldNotRepeatIPC) {
   mswr::ComPtr<FontFallback> fallback;
-  FontFallback::Create(&fallback, collection_.Get(),
-                       fake_collection_->GetTrackingSender());
+  FontFallback::Create(&fallback, collection_.Get());
 
   mswr::ComPtr<IDWriteFont> font;
   UINT32 mapped_length = 0;
@@ -99,14 +99,20 @@
                           DWRITE_FONT_STRETCH_NORMAL, &mapped_length, &font,
                           &scale);
 
-  EXPECT_EQ(1u, fake_collection_->MessageCount());
+  EXPECT_EQ(3u, fake_collection_->MessageCount());
+
+  EXPECT_EQ(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(0));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(1));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(2));
   EXPECT_EQ(5u, mapped_length);
 }
 
 TEST_F(FontFallbackUnitTest, DifferentFamilyShouldNotReuseCache) {
   mswr::ComPtr<FontFallback> fallback;
-  FontFallback::Create(&fallback, collection_.Get(),
-                       fake_collection_->GetTrackingSender());
+  FontFallback::Create(&fallback, collection_.Get());
 
   mswr::ComPtr<IDWriteFont> font;
   UINT32 mapped_length = 0;
@@ -125,13 +131,20 @@
                           DWRITE_FONT_STRETCH_NORMAL, &mapped_length, &font,
                           &scale);
 
-  EXPECT_EQ(2u, fake_collection_->MessageCount());
+  EXPECT_EQ(4u, fake_collection_->MessageCount());
+  EXPECT_EQ(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(0));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(1));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(2));
+  EXPECT_EQ(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(3));
 }
 
 TEST_F(FontFallbackUnitTest, CacheMissShouldRepeatIPC) {
   mswr::ComPtr<FontFallback> fallback;
-  FontFallback::Create(&fallback, collection_.Get(),
-                       fake_collection_->GetTrackingSender());
+  FontFallback::Create(&fallback, collection_.Get());
 
   mswr::ComPtr<IDWriteFont> font;
   UINT32 mapped_length = 0;
@@ -154,13 +167,20 @@
                           DWRITE_FONT_STRETCH_NORMAL, &mapped_length, &font,
                           &scale);
 
-  EXPECT_EQ(2u, fake_collection_->MessageCount());
+  EXPECT_EQ(4u, fake_collection_->MessageCount());
+  EXPECT_EQ(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(0));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(1));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(2));
+  EXPECT_EQ(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(3));
 }
 
 TEST_F(FontFallbackUnitTest, SurrogatePairCacheHit) {
   mswr::ComPtr<FontFallback> fallback;
-  FontFallback::Create(&fallback, collection_.Get(),
-                       fake_collection_->GetTrackingSender());
+  FontFallback::Create(&fallback, collection_.Get());
 
   mswr::ComPtr<IDWriteFont> font;
   UINT32 mapped_length = 0;
@@ -183,7 +203,13 @@
                           DWRITE_FONT_STRETCH_NORMAL, &mapped_length, &font,
                           &scale);
 
-  EXPECT_EQ(1u, fake_collection_->MessageCount());
+  EXPECT_EQ(3u, fake_collection_->MessageCount());
+  EXPECT_EQ(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(0));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(1));
+  EXPECT_NE(FakeFontCollection::MessageType::kMapCharacters,
+            fake_collection_->GetMessageType(2));
   EXPECT_EQ(2u, mapped_length);
 }
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 2a238646..996530af 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -118,7 +118,6 @@
     "drag_event_source_info.h",
     "drag_messages.h",
     "drag_traits.h",
-    "dwrite_font_proxy_messages.h",
     "edit_command.h",
     "fileapi/file_system_messages.h",
     "fileapi/webblob_messages.h",
@@ -578,7 +577,10 @@
   ]
 
   if (is_win) {
-    sources += [ "font_cache_win.mojom" ]
+    sources += [
+      "dwrite_font_proxy.mojom",
+      "font_cache_win.mojom",
+    ]
   }
 
   import_dirs = [ "//mojo/services" ]
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h
index 73c2ddb..d1505e7 100644
--- a/content/common/content_message_generator.h
+++ b/content/common/content_message_generator.h
@@ -165,11 +165,3 @@
     "Failed to include content/common/media/surface_view_manager_messages_android.h"
 #endif
 #endif  // defined(OS_ANDROID)
-
-#if defined(OS_WIN)
-#undef CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-#include "content/common/dwrite_font_proxy_messages.h"
-#ifndef CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-#error "Failed to include content/common/dwrite_font_proxy_messages.h"
-#endif
-#endif  // defined(OS_WIN)
diff --git a/content/common/dwrite_font_proxy.mojom b/content/common/dwrite_font_proxy.mojom
new file mode 100644
index 0000000..da59c04
--- /dev/null
+++ b/content/common/dwrite_font_proxy.mojom
@@ -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.
+
+module content.mojom;
+
+import "mojo/common/file.mojom";
+import "mojo/common/file_path.mojom";
+import "mojo/common/string16.mojom";
+
+struct DWriteStringPair {
+  mojo.common.mojom.String16 first;
+  mojo.common.mojom.String16 second;
+};
+
+struct DWriteFontStyle {
+  uint16 font_weight;
+  uint8 font_slant;
+  uint8 font_stretch;
+};
+
+struct MapCharactersResult {
+  uint32 family_index;
+  mojo.common.mojom.String16 family_name;
+  uint32 mapped_length;
+  float scale;
+  DWriteFontStyle font_style;
+};
+
+interface DWriteFontProxy {
+  // Locates the index of the specified font family within the system
+  // collection.
+  [Sync]
+  FindFamily(mojo.common.mojom.String16 family_name) => (uint32 out_index);
+
+  // Returns the number of font families in the system collection.
+  [Sync]
+  GetFamilyCount() => (uint32 out_count);
+
+  // Returns the list of locale and family name pairs for the font family at the
+  // specified index.
+  [Sync]
+  GetFamilyNames(uint32 family_index)
+      => (array<DWriteStringPair> out_family_names);
+
+  // Returns the list of font file paths in the system font directory that
+  // contain font data for the font family at the specified index.
+  [Sync]
+  GetFontFiles(uint32 family_index)
+     => (array<mojo.common.mojom.FilePath> file_paths,
+         array<mojo.common.mojom.File> file_handles);
+
+  // Locates a font family that is able to render the specified text using the
+  // specified style. If successful, the family_index and family_name will
+  // indicate which family in the system font collection can render the
+  // requested text and the mapped_length will indicate how many characters can
+  // be rendered. If no font exists that can render the text, family_index will
+  // be UINT32_MAX and mapped_length will indicate how many characters cannot be
+  // rendered by any installed font.
+  [Sync]
+  MapCharacters(mojo.common.mojom.String16 text,
+                DWriteFontStyle font_style,
+                mojo.common.mojom.String16 locale_name,
+                uint32 reading_direction,
+                mojo.common.mojom.String16 base_family_name)
+      => (MapCharactersResult out);
+};
diff --git a/content/common/dwrite_font_proxy_messages.h b/content/common/dwrite_font_proxy_messages.h
deleted file mode 100644
index e8534eb..0000000
--- a/content/common/dwrite_font_proxy_messages.h
+++ /dev/null
@@ -1,83 +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 CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-#define CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-
-#include <stdint.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "content/common/content_export.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_platform_file.h"
-
-#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
-#define IPC_MESSAGE_START DWriteFontProxyMsgStart
-
-#ifndef INTERNAL_CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-#define INTERNAL_CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-
-// The macros can't handle a complex template declaration, so we typedef it.
-typedef std::pair<base::string16, base::string16> DWriteStringPair;
-
-#endif  // INTERNAL_CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
-
-IPC_STRUCT_BEGIN(DWriteFontStyle)
-  IPC_STRUCT_MEMBER(uint16_t, font_weight)
-  IPC_STRUCT_MEMBER(uint8_t, font_slant)
-  IPC_STRUCT_MEMBER(uint8_t, font_stretch)
-IPC_STRUCT_END()
-
-IPC_STRUCT_BEGIN(MapCharactersResult)
-  IPC_STRUCT_MEMBER(uint32_t, family_index)
-  IPC_STRUCT_MEMBER(base::string16, family_name)
-  IPC_STRUCT_MEMBER(uint32_t, mapped_length)
-  IPC_STRUCT_MEMBER(float, scale)
-  IPC_STRUCT_MEMBER(DWriteFontStyle, font_style)
-IPC_STRUCT_END()
-
-// Locates the index of the specified font family within the system collection.
-IPC_SYNC_MESSAGE_CONTROL1_1(DWriteFontProxyMsg_FindFamily,
-                            base::string16 /* family_name */,
-                            uint32_t /* out index */)
-
-// Returns the number of font families in the system collection.
-IPC_SYNC_MESSAGE_CONTROL0_1(DWriteFontProxyMsg_GetFamilyCount,
-                            uint32_t /* out count */)
-
-// Returns the list of locale and family name pairs for the font family at the
-// specified index.
-IPC_SYNC_MESSAGE_CONTROL1_1(
-    DWriteFontProxyMsg_GetFamilyNames,
-    uint32_t /* family_index */,
-    std::vector<DWriteStringPair> /* out family_names */)
-
-// Returns the list of font file paths in the system font directory that contain
-// font data for the font family at the specified index.
-IPC_SYNC_MESSAGE_CONTROL1_2(
-    DWriteFontProxyMsg_GetFontFiles,
-    uint32_t /* family_index */,
-    std::vector<base::string16> /* out file_paths */,
-    std::vector<IPC::PlatformFileForTransit> /* out file_handles*/)
-
-// Locates a font family that is able to render the specified text using the
-// specified style. If successful, the family_index and family_name will
-// indicate which family in the system font collection can render the requested
-// text and the mapped_length will indicate how many characters can be
-// rendered. If no font exists that can render the text, family_index will be
-// UINT32_MAX and mapped_length will indicate how many characters cannot be
-// rendered by any installed font.
-IPC_SYNC_MESSAGE_CONTROL5_1(DWriteFontProxyMsg_MapCharacters,
-                            base::string16 /* text */,
-                            DWriteFontStyle /* font_style */,
-                            base::string16 /* locale_name */,
-                            uint32_t /* reading_direction */,
-                            base::string16 /* base_family_name - optional */,
-                            MapCharactersResult /* out */)
-
-#endif  // CONTENT_COMMON_DWRITE_FONT_PROXY_MESSAGES_H_
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index dd12051..90a8ca13 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -96,11 +96,6 @@
   IPC_STRUCT_TRAITS_MEMBER(client_type)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerClientQueryOptions)
-  IPC_STRUCT_TRAITS_MEMBER(client_type)
-  IPC_STRUCT_TRAITS_MEMBER(include_uncontrolled)
-IPC_STRUCT_TRAITS_END()
-
 IPC_STRUCT_TRAITS_BEGIN(content::PushEventPayload)
   IPC_STRUCT_TRAITS_MEMBER(data)
   IPC_STRUCT_TRAITS_MEMBER(is_null)
@@ -136,11 +131,6 @@
                     int /* request_id */,
                     std::string /* client_uuid */)
 
-// Asks the browser to retrieve clients of the sender ServiceWorker.
-IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_GetClients,
-                    int /* request_id */,
-                    content::ServiceWorkerClientQueryOptions)
-
 // Sends MessageEvent to a client (renderer->browser).
 IPC_MESSAGE_ROUTED3(
     ServiceWorkerHostMsg_PostMessageToClient,
@@ -196,11 +186,6 @@
                      int /* request_id */,
                      blink::mojom::ServiceWorkerClientInfo)
 
-// Sent via EmbeddedWorker as a response of GetClients.
-IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClients,
-                     int /* request_id */,
-                     std::vector<blink::mojom::ServiceWorkerClientInfo>)
-
 // Sent via EmbeddedWorker as a response of OpenWindow.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_OpenWindowResponse,
                      int /* request_id */,
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc
index e046830..31945d7 100644
--- a/content/common/service_worker/service_worker_types.cc
+++ b/content/common/service_worker/service_worker_types.cc
@@ -147,8 +147,4 @@
   return size;
 }
 
-ServiceWorkerClientQueryOptions::ServiceWorkerClientQueryOptions()
-    : client_type(blink::mojom::ServiceWorkerClientType::kWindow),
-      include_uncontrolled(false) {}
-
 }  // namespace content
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h
index 60d4c5d8..f1ed5367 100644
--- a/content/common/service_worker/service_worker_types.h
+++ b/content/common/service_worker/service_worker_types.h
@@ -182,12 +182,6 @@
   int changed_;
 };
 
-struct ServiceWorkerClientQueryOptions {
-  ServiceWorkerClientQueryOptions();
-  blink::mojom::ServiceWorkerClientType client_type;
-  bool include_uncontrolled;
-};
-
 }  // namespace content
 
 #endif  // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_TYPES_H_
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentView.java b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
index f47f7884..0c25c02 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
@@ -268,11 +268,6 @@
     }
 
     @Override
-    public boolean awakenScrollBars() {
-        return super.awakenScrollBars();
-    }
-
-    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mContentViewCore.onAttachedToWindow();
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index f29745f9..54faae9 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -86,11 +86,6 @@
         void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
 
         /**
-         * @see View#awakenScrollBars()
-         */
-        boolean awakenScrollBars();
-
-        /**
          * @see View#awakenScrollBars(int, boolean)
          */
         boolean super_awakenScrollBars(int startDelay, boolean invalidate);
@@ -226,11 +221,6 @@
     int getViewportHeightPix();
 
     /**
-     * @return The number of pixels (DIPs) each tick of the mouse wheel should scroll.
-     */
-    float getMouseWheelTickMultiplier();
-
-    /**
      * @return Whether the current focused node is editable.
      */
     boolean isFocusedNodeEditable();
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index 855e50a..d0129086 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -526,9 +526,11 @@
         return mContainerView.getHeight();
     }
 
-    @Override
+    /**
+     * @return The number of pixels (DIPs) each tick of the mouse wheel should scroll.
+     */
     @CalledByNative
-    public float getMouseWheelTickMultiplier() {
+    private float getMouseWheelTickMultiplier() {
         return mRenderCoordinates.getWheelScrollFactor()
                 / mRenderCoordinates.getDeviceScaleFactor();
     }
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
index ac6e239..e8d32a8 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
@@ -294,6 +294,9 @@
             // Device is not provisioned, don't trigger SelectionClient logic at all.
             boolean blockSelectionClient = !ApiCompatibilityUtils.isDeviceProvisioned(mContext);
 
+            // Disable SelectionClient logic if it's incognito.
+            blockSelectionClient |= isIncognito();
+
             if (!blockSelectionClient && mSelectionMetricsLogger != null) {
                 switch (sourceType) {
                     case MenuSourceType.MENU_SOURCE_ADJUST_SELECTION:
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
index 253406b..f3e1c23 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
@@ -79,11 +79,6 @@
         }
 
         @Override
-        public boolean awakenScrollBars() {
-            return false;
-        }
-
-        @Override
         public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
             return false;
         }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/SelectionPopupControllerTest.java b/content/public/android/junit/src/org/chromium/content/browser/SelectionPopupControllerTest.java
index 1ce7a7f..284cfb5 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/SelectionPopupControllerTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/SelectionPopupControllerTest.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -415,6 +416,46 @@
     }
 
     @Test
+    @Feature({"TextInput", "SmartSelection"})
+    public void testBlockSelectionClientWhenUnprovisioned() {
+        // Device is not provisioned.
+        Settings.System.putInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0);
+
+        TestSelectionClient client = Mockito.mock(TestSelectionClient.class);
+        InOrder order = inOrder(mLogger, client);
+        mController.setSelectionClient(client);
+
+        // Long press triggered showSelectionMenu() call.
+        mController.showSelectionMenu(0, 0, 0, 0, 0, /* isEditable = */ true,
+                /* isPasswordType = */ false, AMPHITHEATRE, /* selectionOffset = */ 5,
+                /* canSelectAll = */ true,
+                /* canRichlyEdit = */ true, /* shouldSuggest = */ true,
+                MenuSourceType.MENU_SOURCE_LONG_PRESS);
+        order.verify(mLogger, never()).logSelectionStarted(anyString(), anyInt(), anyBoolean());
+        order.verify(client, never()).requestSelectionPopupUpdates(anyBoolean());
+    }
+
+    @Test
+    @Feature({"TextInput", "SmartSelection"})
+    public void testBlockSelectionClientWhenIncognito() {
+        // Incognito.
+        when(mWebContents.isIncognito()).thenReturn(true);
+
+        TestSelectionClient client = Mockito.mock(TestSelectionClient.class);
+        InOrder order = inOrder(mLogger, client);
+        mController.setSelectionClient(client);
+
+        // Long press triggered showSelectionMenu() call.
+        mController.showSelectionMenu(0, 0, 0, 0, 0, /* isEditable = */ true,
+                /* isPasswordType = */ false, AMPHITHEATRE, /* selectionOffset = */ 5,
+                /* canSelectAll = */ true,
+                /* canRichlyEdit = */ true, /* shouldSuggest = */ true,
+                MenuSourceType.MENU_SOURCE_LONG_PRESS);
+        order.verify(mLogger, never()).logSelectionStarted(anyString(), anyInt(), anyBoolean());
+        order.verify(client, never()).requestSelectionPopupUpdates(anyBoolean());
+    }
+
+    @Test
     @Feature({"TextInput", "HandleObserver"})
     public void testHandleObserverSelectionHandle() {
         SelectionInsertionHandleObserver handleObserver =
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 52469c6..45e2d8b 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -9,6 +9,9 @@
           "discardable_memory::mojom::DiscardableSharedMemoryManager",
           "memory_instrumentation::mojom::Coordinator"
         ],
+        "dwrite_font_proxy": [
+          "content::mojom::DWriteFontProxy"
+        ],
         "field_trials": [
           "content::mojom::FieldTrialRecorder"
         ],
diff --git a/content/public/app/mojo/content_gpu_manifest.json b/content/public/app/mojo/content_gpu_manifest.json
index 77212945..863f9da2 100644
--- a/content/public/app/mojo/content_gpu_manifest.json
+++ b/content/public/app/mojo/content_gpu_manifest.json
@@ -21,6 +21,7 @@
       "requires": {
         "*": [ "app" ],
         "content_browser": [
+          "dwrite_font_proxy",
           "field_trials",
           "gpu"
         ],
diff --git a/content/public/app/mojo/content_plugin_manifest.json b/content/public/app/mojo/content_plugin_manifest.json
index b184bac..50d46302 100644
--- a/content/public/app/mojo/content_plugin_manifest.json
+++ b/content/public/app/mojo/content_plugin_manifest.json
@@ -18,6 +18,7 @@
       "requires": {
         "*": [ "app" ],
         "content_browser": [
+          "dwrite_font_proxy",
           "field_trials",
           "font_cache",
           "plugin"
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index a9b82ba0..5efdd84 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -28,6 +28,7 @@
       "requires": {
         "*": [ "app" ],
         "content_browser": [
+          "dwrite_font_proxy",
           "field_trials",
           "renderer"
         ],
diff --git a/content/public/app/mojo/content_utility_manifest.json b/content/public/app/mojo/content_utility_manifest.json
index 090b5632..cf41b5a 100644
--- a/content/public/app/mojo/content_utility_manifest.json
+++ b/content/public/app/mojo/content_utility_manifest.json
@@ -21,6 +21,7 @@
       "requires": {
         "*": [ "app" ],
         "content_browser": [
+          "dwrite_font_proxy",
           "field_trials"
         ],
         "device": [
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 5bb4fc4..920207f 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -331,6 +331,7 @@
     "//device/geolocation",
     "//device/usb/public/interfaces",
     "//gpu",
+    "//gpu/command_buffer/service:gles2",
     "//media",
     "//net",
     "//ppapi/c",
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
index 4fc1761..e3dd113 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
@@ -144,11 +144,6 @@
     }
 
     @Override
-    public float getMouseWheelTickMultiplier() {
-        return 0.f;
-    }
-
-    @Override
     public String getSelectedText() {
         return null;
     }
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 88a7a50..dc89303 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -343,6 +343,10 @@
   // (http://crbug.com/21508).
   base::RunLoop().RunUntilIdle();
 
+#if defined(OS_WIN)
+  ClearDWriteFontProxySenderForTesting();
+#endif
+
 #if defined(OS_MACOSX)
   autorelease_pool_.reset();
 #endif
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 03d4f15f..371a181 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -385,8 +385,6 @@
 // Holding data that needs to be bound to the worker context on the
 // worker thread.
 struct ServiceWorkerContextClient::WorkerContextData {
-  using ClientsCallbacksMap =
-      base::IDMap<std::unique_ptr<blink::WebServiceWorkerClientsCallbacks>>;
   using ClientCallbacksMap =
       base::IDMap<std::unique_ptr<blink::WebServiceWorkerClientCallbacks>>;
   using SkipWaitingCallbacksMap =
@@ -413,9 +411,6 @@
   scoped_refptr<blink::mojom::ThreadSafeServiceWorkerHostAssociatedPtr>
       service_worker_host;
 
-  // Pending callbacks for GetClientDocuments().
-  ClientsCallbacksMap clients_callbacks;
-
   // Pending callbacks for OpenWindow() and FocusClient().
   ClientCallbacksMap client_callbacks;
 
@@ -692,7 +687,6 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerContextClient, message)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClient, OnDidGetClient)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClients, OnDidGetClients)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowResponse,
                         OnOpenWindowResponse)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowError,
@@ -722,12 +716,16 @@
     const blink::WebServiceWorkerClientQueryOptions& weboptions,
     std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks) {
   DCHECK(callbacks);
-  int request_id = context_->clients_callbacks.Add(std::move(callbacks));
-  ServiceWorkerClientQueryOptions options;
-  options.client_type = weboptions.client_type;
-  options.include_uncontrolled = weboptions.include_uncontrolled;
-  Send(new ServiceWorkerHostMsg_GetClients(
-      GetRoutingID(), request_id, options));
+  auto options = blink::mojom::ServiceWorkerClientQueryOptions::New(
+      weboptions.include_uncontrolled, weboptions.client_type);
+  // base::Unretained(this) is safe because the callback passed to
+  // GetClients() is owned by |context_->service_worker_host|, whose only
+  // owner is |this| and won't outlive |this|.
+  (*context_->service_worker_host)
+      ->GetClients(
+          std::move(options),
+          base::BindOnce(&ServiceWorkerContextClient::OnDidGetClients,
+                         base::Unretained(this), std::move(callbacks)));
 }
 
 void ServiceWorkerContextClient::OpenNewTab(
@@ -1661,24 +1659,17 @@
 }
 
 void ServiceWorkerContextClient::OnDidGetClients(
-    int request_id,
-    const std::vector<blink::mojom::ServiceWorkerClientInfo>& clients) {
+    std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks,
+    std::vector<blink::mojom::ServiceWorkerClientInfoPtr> clients) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::OnDidGetClients");
-  blink::WebServiceWorkerClientsCallbacks* callbacks =
-      context_->clients_callbacks.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
   blink::WebServiceWorkerClientsInfo info;
-  blink::WebVector<blink::WebServiceWorkerClientInfo> convertedClients(
+  blink::WebVector<blink::WebServiceWorkerClientInfo> web_clients(
       clients.size());
   for (size_t i = 0; i < clients.size(); ++i)
-    convertedClients[i] = ToWebServiceWorkerClientInfo(clients[i]);
-  info.clients.Swap(convertedClients);
+    web_clients[i] = ToWebServiceWorkerClientInfo(*(clients[i]));
+  info.clients.Swap(web_clients);
   callbacks->OnSuccess(info);
-  context_->clients_callbacks.Remove(request_id);
 }
 
 void ServiceWorkerContextClient::OnOpenWindowResponse(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index c224fbb..e96072b0 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -365,8 +365,8 @@
   void OnDidGetClient(int request_id,
                       const blink::mojom::ServiceWorkerClientInfo& client);
   void OnDidGetClients(
-      int request_id,
-      const std::vector<blink::mojom::ServiceWorkerClientInfo>& clients);
+      std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks,
+      std::vector<blink::mojom::ServiceWorkerClientInfoPtr> clients);
   void OnOpenWindowResponse(
       int request_id,
       const blink::mojom::ServiceWorkerClientInfo& client);
diff --git a/content/test/dwrite_font_fake_sender_win.cc b/content/test/dwrite_font_fake_sender_win.cc
index 66af5f5..b962bbe 100644
--- a/content/test/dwrite_font_fake_sender_win.cc
+++ b/content/test/dwrite_font_fake_sender_win.cc
@@ -7,39 +7,45 @@
 #include <dwrite.h>
 #include <shlobj.h>
 
-#include "content/common/dwrite_font_proxy_messages.h"
-
 namespace content {
 
-void AddFamily(const base::string16& font_path,
+void AddFamily(const base::FilePath& font_path,
                const base::string16& family_name,
                const base::string16& base_family_name,
                FakeFontCollection* collection) {
   collection->AddFont(family_name)
       .AddFamilyName(L"en-us", family_name)
-      .AddFilePath(font_path + L"\\" + base_family_name + L".ttf")
-      .AddFilePath(font_path + L"\\" + base_family_name + L"bd.ttf")
-      .AddFilePath(font_path + L"\\" + base_family_name + L"bi.ttf")
-      .AddFilePath(font_path + L"\\" + base_family_name + L"i.ttf");
+      .AddFilePath(font_path.Append(L"\\" + base_family_name + L".ttf"))
+      .AddFilePath(font_path.Append(L"\\" + base_family_name + L"bd.ttf"))
+      .AddFilePath(font_path.Append(L"\\" + base_family_name + L"bi.ttf"))
+      .AddFilePath(font_path.Append(L"\\" + base_family_name + L"i.ttf"));
 }
 
-IPC::Sender* CreateFakeCollectionSender() {
+mojom::DWriteFontProxyPtrInfo CreateFakeCollectionPtr(
+    const std::unique_ptr<FakeFontCollection>& collection) {
+  return collection->CreatePtr();
+}
+
+base::RepeatingCallback<mojom::DWriteFontProxyPtrInfo(void)>
+CreateFakeCollectionSender() {
   std::vector<base::char16> font_path_chars;
   font_path_chars.resize(MAX_PATH);
-  SHGetSpecialFolderPath(nullptr /* hwndOwner - reserved */,
+  SHGetSpecialFolderPath(nullptr /*hwndOwner - reserved*/,
                          font_path_chars.data(), CSIDL_FONTS,
-                         FALSE /* fCreate */);
-  base::string16 font_path(font_path_chars.data());
-  scoped_refptr<FakeFontCollection> fake_collection = new FakeFontCollection();
+                         FALSE /*fCreate*/);
+  base::FilePath font_path(base::string16(font_path_chars.data()));
+  std::unique_ptr<FakeFontCollection> fake_collection =
+      std::make_unique<FakeFontCollection>();
   AddFamily(font_path, L"Arial", L"arial", fake_collection.get());
   AddFamily(font_path, L"Courier New", L"cour", fake_collection.get());
   AddFamily(font_path, L"Times New Roman", L"times", fake_collection.get());
-  return fake_collection->GetSender();
+  return base::BindRepeating(&CreateFakeCollectionPtr,
+                             std::move(fake_collection));
 }
 
 FakeFont::FakeFont(const base::string16& name) : font_name_(name) {}
 
-FakeFont::FakeFont(const FakeFont& other) = default;
+FakeFont::FakeFont(FakeFont&& other) = default;
 
 FakeFont::~FakeFont() = default;
 
@@ -50,156 +56,74 @@
   return fonts_.back();
 }
 
+mojom::DWriteFontProxyPtrInfo FakeFontCollection::CreatePtr() {
+  mojom::DWriteFontProxyPtrInfo ptr;
+  bindings_.AddBinding(this, mojo::MakeRequest(&ptr));
+  return ptr;
+}
+
 size_t FakeFontCollection::MessageCount() {
-  return messages_.size();
+  return message_types_.size();
 }
 
-IPC::Message* FakeFontCollection::GetIpcMessage(size_t index) {
-  return messages_[index].get();
+FakeFontCollection::MessageType FakeFontCollection::GetMessageType(size_t id) {
+  return message_types_[id];
 }
 
-IPC::Sender* FakeFontCollection::GetSender() {
-  return new FakeSender(this, false /* track_messages */);
-}
-
-IPC::Sender* FakeFontCollection::GetTrackingSender() {
-  return new FakeSender(this, true /* track_messages */);
-}
-
-FakeFontCollection::ReplySender::ReplySender(FakeFontCollection* collection)
-    : collection_(collection) {}
-
-FakeFontCollection::ReplySender::~ReplySender() = default;
-
-std::unique_ptr<IPC::Message>&
-FakeFontCollection::ReplySender::OnMessageReceived(const IPC::Message& msg) {
-  reply_.reset();
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ReplySender, msg)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_FindFamily, OnFindFamily)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_GetFamilyCount, OnGetFamilyCount)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_GetFamilyNames, OnGetFamilyNames)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_GetFontFiles, OnGetFontFiles)
-    IPC_MESSAGE_HANDLER(DWriteFontProxyMsg_MapCharacters, OnMapCharacters)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return reply_;
-}
-
-bool FakeFontCollection::ReplySender::Send(IPC::Message* msg) {
-  reply_.reset(msg);
-  return true;
-}
-
-void FakeFontCollection::ReplySender::OnFindFamily(
-    const base::string16& family_name,
-    uint32_t* index) {
-  collection_->OnFindFamily(family_name, index);
-}
-
-void FakeFontCollection::ReplySender::OnGetFamilyCount(uint32_t* count) {
-  collection_->OnGetFamilyCount(count);
-}
-
-void FakeFontCollection::ReplySender::OnGetFamilyNames(
-    uint32_t family_index,
-    std::vector<DWriteStringPair>* family_names) {
-  collection_->OnGetFamilyNames(family_index, family_names);
-}
-
-void FakeFontCollection::ReplySender::OnGetFontFiles(
-    uint32_t family_index,
-    std::vector<base::string16>* file_paths,
-    std::vector<IPC::PlatformFileForTransit>* file_handles) {
-  collection_->OnGetFontFiles(family_index, file_paths, file_handles);
-}
-
-void FakeFontCollection::ReplySender::OnMapCharacters(
-    const base::string16& text,
-    const DWriteFontStyle& font_style,
-    const base::string16& locale_name,
-    uint32_t reading_direction,
-    const base::string16& base_family_name,
-    MapCharactersResult* result) {
-  collection_->OnMapCharacters(text, font_style, locale_name, reading_direction,
-                               base_family_name, result);
-}
-
-FakeFontCollection::FakeSender::FakeSender(FakeFontCollection* collection,
-                                           bool track_messages)
-    : track_messages_(track_messages), collection_(collection) {}
-
-FakeFontCollection::FakeSender::~FakeSender() = default;
-
-bool FakeFontCollection::FakeSender::Send(IPC::Message* message) {
-  std::unique_ptr<IPC::Message> incoming_message;
-  if (track_messages_)
-    collection_->messages_.emplace_back(message);
-  else
-    incoming_message.reset(message);  // Ensure message is deleted.
-  std::unique_ptr<ReplySender> sender = collection_->GetReplySender();
-  std::unique_ptr<IPC::Message> reply;
-  reply.swap(sender->OnMessageReceived(*message));
-
-  IPC::SyncMessage* sync_message = reinterpret_cast<IPC::SyncMessage*>(message);
-  std::unique_ptr<IPC::MessageReplyDeserializer> serializer(
-      sync_message->GetReplyDeserializer());
-  serializer->SerializeOutputParameters(*(reply.get()));
-  return true;
-}
-
-void FakeFontCollection::OnFindFamily(const base::string16& family_name,
-                                      uint32_t* index) {
+void FakeFontCollection::FindFamily(const base::string16& family_name,
+                                    FindFamilyCallback callback) {
+  message_types_.push_back(MessageType::kFindFamily);
   for (size_t n = 0; n < fonts_.size(); n++) {
     if (_wcsicmp(family_name.data(), fonts_[n].font_name_.data()) == 0) {
-      *index = n;
+      std::move(callback).Run(n);
       return;
     }
   }
-  *index = UINT32_MAX;
+  std::move(callback).Run(UINT32_MAX);
 }
 
-void FakeFontCollection::OnGetFamilyCount(uint32_t* count) {
-  *count = fonts_.size();
+void FakeFontCollection::GetFamilyCount(GetFamilyCountCallback callback) {
+  message_types_.push_back(MessageType::kGetFamilyCount);
+  std::move(callback).Run(fonts_.size());
 }
 
-void FakeFontCollection::OnGetFamilyNames(
-    uint32_t family_index,
-    std::vector<DWriteStringPair>* family_names) {
-  if (family_index >= fonts_.size())
-    return;
-  *family_names = fonts_[family_index].family_names_;
+void FakeFontCollection::GetFamilyNames(uint32_t family_index,
+                                        GetFamilyNamesCallback callback) {
+  message_types_.push_back(MessageType::kGetFamilyNames);
+  std::vector<mojom::DWriteStringPairPtr> family_names;
+  if (family_index < fonts_.size()) {
+    for (const auto& name : fonts_[family_index].family_names_) {
+      family_names.emplace_back(base::in_place, name.first, name.second);
+    }
+  }
+  std::move(callback).Run(std::move(family_names));
 }
 
-void FakeFontCollection::OnGetFontFiles(
-    uint32_t family_index,
-    std::vector<base::string16>* file_paths,
-    std::vector<IPC::PlatformFileForTransit>* file_handles) {
-  if (family_index >= fonts_.size())
-    return;
-  *file_paths = fonts_[family_index].file_paths_;
-  *file_handles = fonts_[family_index].file_handles_;
+void FakeFontCollection::GetFontFiles(uint32_t family_index,
+                                      GetFontFilesCallback callback) {
+  message_types_.push_back(MessageType::kGetFontFiles);
+  std::vector<base::FilePath> file_paths;
+  std::vector<base::File> file_handles;
+  if (family_index < fonts_.size()) {
+    file_paths = fonts_[family_index].file_paths_;
+    for (auto& file : fonts_[family_index].file_handles_)
+      file_handles.emplace_back(file.Duplicate());
+  }
+  std::move(callback).Run(file_paths, std::move(file_handles));
 }
 
-void FakeFontCollection::OnMapCharacters(const base::string16& text,
-                                         const DWriteFontStyle& font_style,
-                                         const base::string16& locale_name,
-                                         uint32_t reading_direction,
-                                         const base::string16& base_family_name,
-                                         MapCharactersResult* result) {
-  result->family_index = 0;
-  result->family_name = fonts_[0].font_name();
-  result->mapped_length = 1;
-  result->scale = 1.0;
-  result->font_style.font_weight = DWRITE_FONT_WEIGHT_NORMAL;
-  result->font_style.font_slant = DWRITE_FONT_STYLE_NORMAL;
-  result->font_style.font_stretch = DWRITE_FONT_STRETCH_NORMAL;
-}
-
-std::unique_ptr<FakeFontCollection::ReplySender>
-FakeFontCollection::GetReplySender() {
-  return std::unique_ptr<FakeFontCollection::ReplySender>(
-      new FakeFontCollection::ReplySender(this));
+void FakeFontCollection::MapCharacters(const base::string16& text,
+                                       mojom::DWriteFontStylePtr font_style,
+                                       const base::string16& locale_name,
+                                       uint32_t reading_direction,
+                                       const base::string16& base_family_name,
+                                       MapCharactersCallback callback) {
+  message_types_.push_back(MessageType::kMapCharacters);
+  std::move(callback).Run(mojom::MapCharactersResult::New(
+      0, fonts_[0].font_name(), 1, 1.0,
+      mojom::DWriteFontStyle::New(DWRITE_FONT_WEIGHT_NORMAL,
+                                  DWRITE_FONT_STYLE_NORMAL,
+                                  DWRITE_FONT_STRETCH_NORMAL)));
 }
 
 FakeFontCollection::~FakeFontCollection() = default;
diff --git a/content/test/dwrite_font_fake_sender_win.h b/content/test/dwrite_font_fake_sender_win.h
index 3a682ae..3684265 100644
--- a/content/test/dwrite_font_fake_sender_win.h
+++ b/content/test/dwrite_font_fake_sender_win.h
@@ -13,15 +13,11 @@
 #include <utility>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_platform_file.h"
-#include "ipc/ipc_sender.h"
-
-struct DWriteFontStyle;
-struct MapCharactersResult;
+#include "content/common/dwrite_font_proxy.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 
 namespace content {
 
@@ -29,24 +25,25 @@
 
 // Creates a new FakeFontCollection, seeded with some basic data, and returns a
 // Sender that can be used to interact with the collection.
-IPC::Sender* CreateFakeCollectionSender();
+base::RepeatingCallback<mojom::DWriteFontProxyPtrInfo(void)>
+CreateFakeCollectionSender();
 
 // Helper class for describing a font object. Use FakeFontCollection instead.
 class FakeFont {
  public:
   explicit FakeFont(const base::string16& name);
 
-  FakeFont(const FakeFont& other);
+  FakeFont(FakeFont&& other);
 
   ~FakeFont();
 
-  FakeFont& AddFilePath(const base::string16& file_path) {
+  FakeFont& AddFilePath(const base::FilePath& file_path) {
     file_paths_.push_back(file_path);
     return *this;
   }
 
-  FakeFont& AddFileHandle(IPC::PlatformFileForTransit handle) {
-    file_handles_.push_back(handle);
+  FakeFont& AddFileHandle(base::File handle) {
+    file_handles_.push_back(std::move(handle));
     return *this;
   }
 
@@ -61,8 +58,8 @@
  private:
   friend FakeFontCollection;
   base::string16 font_name_;
-  std::vector<base::string16> file_paths_;
-  std::vector<IPC::PlatformFileForTransit> file_handles_;
+  std::vector<base::FilePath> file_paths_;
+  std::vector<base::File> file_handles_;
   std::vector<std::pair<base::string16, base::string16>> family_names_;
 
   DISALLOW_ASSIGN(FakeFont);
@@ -88,102 +85,47 @@
 //       internally call ReplySender::On*() and ReplySender::Send()
 //   ReplySender::Send() will save the reply message, to be used later.
 //   FakeSender::Send() will retrieve the reply message and save the output.
-class FakeFontCollection : public base::RefCounted<FakeFontCollection> {
+class FakeFontCollection : public mojom::DWriteFontProxy {
  public:
+  enum class MessageType {
+    kFindFamily,
+    kGetFamilyCount,
+    kGetFamilyNames,
+    kGetFontFiles,
+    kMapCharacters
+  };
   FakeFontCollection();
+  ~FakeFontCollection() override;
 
   FakeFont& AddFont(const base::string16& font_name);
 
   size_t MessageCount();
+  MessageType GetMessageType(size_t id);
 
-  IPC::Message* GetIpcMessage(size_t index);
-
-  IPC::Sender* GetSender();
-
-  // Like GetSender(), but will keep track of all sent messages for inspection.
-  IPC::Sender* GetTrackingSender();
+  mojom::DWriteFontProxyPtrInfo CreatePtr();
 
  protected:
-  // This class handles sending the reply message back to the "renderer"
-  class ReplySender : public IPC::Sender {
-   public:
-    explicit ReplySender(FakeFontCollection* collection);
-
-    ~ReplySender() override;
-
-    std::unique_ptr<IPC::Message>& OnMessageReceived(const IPC::Message& msg);
-
-    bool Send(IPC::Message* msg) override;
-
-   private:
-    void OnFindFamily(const base::string16& family_name, uint32_t* index);
-
-    void OnGetFamilyCount(uint32_t* count);
-
-    void OnGetFamilyNames(
-        uint32_t family_index,
-        std::vector<std::pair<base::string16, base::string16>>* family_names);
-    void OnGetFontFiles(uint32_t family_index,
-                        std::vector<base::string16>* file_paths,
-                        std::vector<IPC::PlatformFileForTransit>* file_handles);
-
-    void OnMapCharacters(const base::string16& text,
-                         const DWriteFontStyle& font_style,
-                         const base::string16& locale_name,
-                         uint32_t reading_direction,
-                         const base::string16& base_family_name,
-                         MapCharactersResult* result);
-
-   private:
-    scoped_refptr<FakeFontCollection> collection_;
-    std::unique_ptr<IPC::Message> reply_;
-
-    DISALLOW_COPY_AND_ASSIGN(ReplySender);
-  };
-
-  // This class can be used by the "renderer" to send messages to the "browser"
-  class FakeSender : public IPC::Sender {
-   public:
-    FakeSender(FakeFontCollection* collection, bool track_messages);
-
-    ~FakeSender() override;
-
-    bool Send(IPC::Message* message) override;
-
-   private:
-    bool track_messages_;
-    scoped_refptr<FakeFontCollection> collection_;
-
-    DISALLOW_COPY_AND_ASSIGN(FakeSender);
-  };
-
-  void OnFindFamily(const base::string16& family_name, uint32_t* index);
-
-  void OnGetFamilyCount(uint32_t* count);
-
-  void OnGetFamilyNames(
-      uint32_t family_index,
-      std::vector<std::pair<base::string16, base::string16>>* family_names);
-
-  void OnGetFontFiles(uint32_t family_index,
-                      std::vector<base::string16>* file_paths,
-                      std::vector<IPC::PlatformFileForTransit>* file_handles);
-
-  void OnMapCharacters(const base::string16& text,
-                       const DWriteFontStyle& font_style,
-                       const base::string16& locale_name,
-                       uint32_t reading_direction,
-                       const base::string16& base_family_name,
-                       MapCharactersResult* result);
-
-  std::unique_ptr<ReplySender> GetReplySender();
+  // mojom::DWriteFontProxy:
+  void FindFamily(const base::string16& family_name,
+                  FindFamilyCallback callback) override;
+  void GetFamilyCount(GetFamilyCountCallback callback) override;
+  void GetFamilyNames(uint32_t family_index,
+                      GetFamilyNamesCallback callback) override;
+  void GetFontFiles(uint32_t family_index,
+                    GetFontFilesCallback callback) override;
+  void MapCharacters(const base::string16& text,
+                     mojom::DWriteFontStylePtr font_style,
+                     const base::string16& locale_name,
+                     uint32_t reading_direction,
+                     const base::string16& base_family_name,
+                     MapCharactersCallback callback) override;
 
  private:
-  friend class base::RefCounted<FakeFontCollection>;
-  ~FakeFontCollection();
-
   std::vector<FakeFont> fonts_;
-  std::vector<std::unique_ptr<IPC::Message>> messages_;
+
+  std::vector<MessageType> message_types_;
+
+  mojo::BindingSet<mojom::DWriteFontProxy> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeFontCollection);
 };
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index 66f77081..f9d5376 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -44,6 +44,11 @@
   return false;
 }
 
+bool ExtensionsAPIClient::ShouldHideBrowserNetworkRequest(
+    const GURL& url) const {
+  return false;
+}
+
 AppViewGuestDelegate* ExtensionsAPIClient::CreateAppViewGuestDelegate() const {
   return NULL;
 }
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index f9ce48e..c5e4a6d 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -94,6 +94,10 @@
   virtual bool ShouldHideResponseHeader(const GURL& url,
                                         const std::string& header_name) const;
 
+  // Returns true if a request from the given URL from the browser context
+  // should be hidden from extensions.
+  virtual bool ShouldHideBrowserNetworkRequest(const GURL& url) const;
+
   // Creates the AppViewGuestDelegate.
   virtual AppViewGuestDelegate* CreateAppViewGuestDelegate() const;
 
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc
index a49e5e9..8af95b1 100644
--- a/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -10,6 +10,7 @@
 #include "chromeos/login/login_state.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/resource_request_info.h"
+#include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
@@ -94,6 +95,14 @@
                             base::StartsWith(url.path_piece(), "/webstore",
                                              base::CompareCase::SENSITIVE));
   }
+
+  if (is_request_from_browser_or_webui_renderer) {
+    sensitive_chrome_url =
+        sensitive_chrome_url ||
+        extensions::ExtensionsAPIClient::Get()->ShouldHideBrowserNetworkRequest(
+            url);
+  }
+
   return sensitive_chrome_url || extension_urls::IsWebstoreUpdateUrl(url) ||
          extension_urls::IsBlacklistUpdateUrl(url) ||
          extension_urls::IsSafeBrowsingUrl(origin, url.path_piece());
@@ -114,7 +123,14 @@
 
   // Requests from the browser and webui get special protection for
   // clients*.google.com URLs.
-  bool is_request_from_browser = request.render_process_id == -1;
+  bool is_request_from_browser =
+      request.render_process_id == -1 &&
+      // Browser requests are often of the "other" resource type.
+      // Main frame requests are not unconditionally seen as a sensitive browser
+      // request, because a request can also be browser-driven if there is no
+      // process to associate the request with. E.g. navigations via the
+      // chrome.tabs.update extension API.
+      request.type != content::RESOURCE_TYPE_MAIN_FRAME;
   bool is_request_from_webui_renderer = false;
   if (!is_request_from_browser) {
     // Requests from guest processes are never hidden.
diff --git a/extensions/browser/api/web_request/web_request_permissions_unittest.cc b/extensions/browser/api/web_request/web_request_permissions_unittest.cc
index 3beaf91..1bb7db6b 100644
--- a/extensions/browser/api/web_request/web_request_permissions_unittest.cc
+++ b/extensions/browser/api/web_request/web_request_permissions_unittest.cc
@@ -4,12 +4,14 @@
 
 #include "extensions/browser/api/web_request/web_request_permissions.h"
 
+#include "extensions/browser/api/extensions_api_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 namespace extensions {
 
 TEST(ExtensionWebRequestPermissions, IsSensitiveURL) {
+  ExtensionsAPIClient api_client;
   struct TestCase {
     const char* url;
     bool is_sensitive_if_request_from_common_renderer;
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 93c5a483..b19829a 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1270,6 +1270,7 @@
   AUTOTESTPRIVATE_GETPRINTERLIST,
   DEVELOPERPRIVATE_GETEXTENSIONSIZE,
   CRYPTOTOKENPRIVATE_ISAPPIDHASHINENTERPRISECONTEXT,
+  CRYPTOTOKENPRIVATE_CANAPPIDGETATTESTATION,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
index a953822..4be89874 100644
--- a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
+++ b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
@@ -50,7 +50,8 @@
   fetcher_->SetRequestContext(
       content::BrowserContext::GetDefaultStoragePartition(context_)->
           GetURLRequestContext());
-  fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
+  fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+                         net::LOAD_DO_NOT_SEND_COOKIES);
 
   content::AssociateURLFetcherWithRenderFrame(
       fetcher_.get(), url::Origin::Create(url_), render_process_id_,
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index dfa6ab8d..6d5966a 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -292,6 +292,7 @@
       # http://crbug.com/162530
       "//chrome:resources",
       "//components/crx_file",
+      "//components/nacl/common:features",
       "//components/url_matcher",
       "//crypto",
       "//device/bluetooth",
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 8352b5b..4b51ca8 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -11,6 +11,10 @@
   defines = [ "GPU_IMPLEMENTATION" ]
 }
 
+config("gpu_gles2_implementation") {
+  defines = [ "GPU_GLES2_IMPLEMENTATION" ]
+}
+
 config("gpu_util_implementation") {
   defines = [ "GPU_UTIL_IMPLEMENTATION" ]
 }
@@ -18,10 +22,7 @@
 component("gpu") {
   public_deps = [
     "//gpu/command_buffer/client:client_sources",
-    "//gpu/command_buffer/client:gles2_cmd_helper_sources",
     "//gpu/command_buffer/common:common_sources",
-    "//gpu/command_buffer/common:gles2_sources",
-    "//gpu/command_buffer/service:gles2_sources",
     "//gpu/command_buffer/service:service_sources",
     "//gpu/config:config_sources",
     "//gpu/ipc/client:ipc_client_sources",
@@ -29,6 +30,14 @@
   ]
 }
 
+component("gles2") {
+  public_deps = [
+    "//gpu/command_buffer/client:gles2_cmd_helper_sources",
+    "//gpu/command_buffer/common:gles2_sources",
+    "//gpu/command_buffer/service:gles2_sources",
+  ]
+}
+
 component("gpu_util") {
   public_deps = [
     "//gpu/ipc/common:gpu_preferences_util_sources",
@@ -59,7 +68,9 @@
       "//base",
       "//build/config:exe_and_shlib_deps",
       "//gpu/command_buffer/client:gles2_c_lib",
+      "//gpu/command_buffer/client:gles2_cmd_helper",
       "//gpu/command_buffer/client:gles2_implementation",
+      "//gpu/command_buffer/service:gles2",
       "//ui/gl",
       "//ui/gl/init",
     ]
@@ -129,6 +140,7 @@
   ]
 
   public_deps = [
+    ":gles2",
     ":gpu",
     "//gpu/command_buffer/client:gles2_interface",
   ]
@@ -202,6 +214,7 @@
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
   deps = [
+    ":gles2",
     ":gpu",
     ":test_support",
     "//base",
@@ -385,6 +398,7 @@
   configs += [ "//build/config:precompiled_headers" ]
 
   deps = [
+    ":gles2",
     ":gpu",
     ":test_support",
     "//base",
@@ -468,7 +482,9 @@
     ":gpu",
     "//base",
     "//base/test:test_support",
+    "//gpu/command_buffer/client:gles2_cmd_helper",
     "//gpu/command_buffer/client:gles2_implementation",
+    "//gpu/command_buffer/service:gles2",
     "//testing/gtest",
     "//testing/perf",
     "//ui/gfx/geometry",
@@ -494,6 +510,7 @@
   ]
 
   deps = [
+    ":gles2",
     ":gpu",
     "//base",
     "//base/third_party/dynamic_annotations",
@@ -514,6 +531,7 @@
     defines = [ "GPU_FUZZER_USE_ANGLE" ]
 
     deps = [
+      ":gles2",
       ":gpu",
       "//base",
       "//base/third_party/dynamic_annotations",
@@ -536,6 +554,7 @@
     ]
 
     deps = [
+      ":gles2",
       ":gpu",
       "//base",
       "//base/third_party/dynamic_annotations",
@@ -555,6 +574,7 @@
     defines = [ "GPU_FUZZER_USE_SWIFTSHADER" ]
 
     deps = [
+      ":gles2",
       ":gpu",
       "//base",
       "//base/third_party/dynamic_annotations",
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn
index 2bc585f..bdfa5d7 100644
--- a/gpu/command_buffer/client/BUILD.gn
+++ b/gpu/command_buffer/client/BUILD.gn
@@ -20,7 +20,7 @@
 group("gles2_cmd_helper") {
   if (is_component_build) {
     public_deps = [
-      "//gpu",
+      "//gpu:gles2",
     ]
   } else {
     public_deps = [
@@ -81,12 +81,12 @@
     "gles2_cmd_helper_autogen.h",
   ]
 
-  configs += [ "//gpu:gpu_implementation" ]
+  configs += [ "//gpu:gpu_gles2_implementation" ]
 
   deps = [
-    ":client_sources",
+    ":client",
     "//base",
-    "//gpu/command_buffer/common:common_sources",
+    "//gpu/command_buffer/common",
     "//gpu/command_buffer/common:gles2_sources",
   ]
 }
diff --git a/gpu/command_buffer/client/gles2_cmd_helper.h b/gpu/command_buffer/client/gles2_cmd_helper.h
index bbcb89e5..4c31d1e 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper.h
@@ -10,13 +10,13 @@
 #include "base/macros.h"
 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
 
 // A class that helps write GL command buffers.
-class GPU_EXPORT GLES2CmdHelper : public CommandBufferHelper {
+class GPU_GLES2_EXPORT GLES2CmdHelper : public CommandBufferHelper {
  public:
   explicit GLES2CmdHelper(CommandBuffer* command_buffer);
   ~GLES2CmdHelper() override;
diff --git a/gpu/command_buffer/common/BUILD.gn b/gpu/command_buffer/common/BUILD.gn
index 2262fda..eec7989 100644
--- a/gpu/command_buffer/common/BUILD.gn
+++ b/gpu/command_buffer/common/BUILD.gn
@@ -22,7 +22,7 @@
 group("gles2") {
   if (is_component_build) {
     public_deps = [
-      "//gpu",
+      "//gpu:gles2",
     ]
   } else {
     public_deps = [
@@ -103,14 +103,14 @@
     "gles2_cmd_ids_autogen.h",
   ]
 
-  configs += [ "//gpu:gpu_implementation" ]
+  configs += [ "//gpu:gpu_gles2_implementation" ]
 
   deps = [
     ":gles2_utils",
     "//base",
   ]
   public_deps = [
-    ":common_sources",
+    ":common",
   ]
 }
 
diff --git a/gpu/command_buffer/common/debug_marker_manager.h b/gpu/command_buffer/common/debug_marker_manager.h
index 810352c..6d8b1a771 100644
--- a/gpu/command_buffer/common/debug_marker_manager.h
+++ b/gpu/command_buffer/common/debug_marker_manager.h
@@ -8,13 +8,13 @@
 #include <string>
 
 #include "base/containers/stack.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
 
 // Tracks debug marker.
-class GPU_EXPORT DebugMarkerManager {
+class GPU_GLES2_EXPORT DebugMarkerManager {
  public:
    DebugMarkerManager();
    ~DebugMarkerManager();
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 4efedd9..d8f56fd 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -20,7 +20,7 @@
 group("gles2") {
   if (is_component_build) {
     public_deps = [
-      "//gpu",
+      "//gpu:gles2",
     ]
   } else {
     public_deps = [
@@ -41,10 +41,13 @@
 
   sources = [
     "async_api_interface.h",
+    "command_buffer_direct.cc",
+    "command_buffer_direct.h",
     "command_buffer_service.cc",
     "command_buffer_service.h",
     "common_decoder.cc",
     "common_decoder.h",
+    "decoder_client.h",
     "gpu_preferences.cc",
     "gpu_preferences.h",
     "gpu_switches.cc",
@@ -106,15 +109,12 @@
     "buffer_manager.cc",
     "buffer_manager.h",
     "client_service_map.h",
-    "command_buffer_direct.cc",
-    "command_buffer_direct.h",
     "context_group.cc",
     "context_group.h",
     "context_state.cc",
     "context_state.h",
     "context_state_autogen.h",
     "context_state_impl_autogen.h",
-    "decoder_client.h",
     "decoder_context.h",
     "error_state.cc",
     "error_state.h",
@@ -215,7 +215,7 @@
 
   configs += [
     "//build/config:precompiled_headers",
-    "//gpu:gpu_implementation",
+    "//gpu:gpu_gles2_implementation",
     "//third_party/khronos:khronos_headers",
   ]
 
@@ -223,18 +223,18 @@
   include_dirs = [ "//third_party/mesa/src/include" ]
 
   public_deps = [
-    "//gpu/command_buffer/common:common_sources",
+    "//gpu/command_buffer/common",
     "//gpu/command_buffer/common:gles2_sources",
   ]
   deps = [
     ":disk_cache_proto",
-    ":service_sources",
+    ":service",
     "//base",
     "//base/third_party/dynamic_annotations",
     "//cc/paint",
-    "//gpu/command_buffer/client:client_sources",
+    "//gpu/command_buffer/client",
     "//gpu/command_buffer/common:gles2_utils",
-    "//gpu/config:config_sources",
+    "//gpu/config",
     "//gpu/ipc/common:surface_handle_type",
     "//third_party/angle:angle_image_util",
     "//third_party/angle:commit_id",
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h
index d32f37a1b..7b754cf 100644
--- a/gpu/command_buffer/service/buffer_manager.h
+++ b/gpu/command_buffer/service/buffer_manager.h
@@ -20,7 +20,7 @@
 #include "gpu/command_buffer/common/buffer.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -33,7 +33,7 @@
 class TestHelper;
 
 // Info about Buffers currently in the system.
-class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
+class GPU_GLES2_EXPORT Buffer : public base::RefCounted<Buffer> {
  public:
   struct MappedRange {
     GLintptr offset;
@@ -215,7 +215,8 @@
 //
 // NOTE: To support shared resources an instance of this class will need to be
 // shared by multiple GLES2Decoders.
-class GPU_EXPORT BufferManager : public base::trace_event::MemoryDumpProvider {
+class GPU_GLES2_EXPORT BufferManager
+    : public base::trace_event::MemoryDumpProvider {
  public:
   BufferManager(MemoryTracker* memory_tracker, FeatureInfo* feature_info);
   ~BufferManager() override;
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index bfb0ba54..3829eeac 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -22,7 +22,7 @@
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/shader_translator_cache.h"
 #include "gpu/config/gpu_feature_info.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -56,7 +56,7 @@
 
 // A Context Group helps manage multiple DecoderContexts that share
 // resources.
-class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> {
+class GPU_GLES2_EXPORT ContextGroup : public base::RefCounted<ContextGroup> {
  public:
   ContextGroup(const GpuPreferences& gpu_preferences,
                bool supports_passthrough_command_decoders,
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index bdb1a86..6a0712b6 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -17,7 +17,7 @@
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -33,7 +33,7 @@
 class TransformFeedback;
 
 // State associated with each texture unit.
-struct GPU_EXPORT TextureUnit {
+struct GPU_GLES2_EXPORT TextureUnit {
   TextureUnit();
   TextureUnit(const TextureUnit& other);
   ~TextureUnit();
@@ -140,7 +140,7 @@
   }
 };
 
-class GPU_EXPORT Vec4 {
+class GPU_GLES2_EXPORT Vec4 {
  public:
   Vec4() {
     v_[0].float_value = 0.0f;
@@ -174,20 +174,20 @@
 };
 
 template <>
-GPU_EXPORT void Vec4::GetValues<GLfloat>(GLfloat* values) const;
+GPU_GLES2_EXPORT void Vec4::GetValues<GLfloat>(GLfloat* values) const;
 template <>
-GPU_EXPORT void Vec4::GetValues<GLint>(GLint* values) const;
+GPU_GLES2_EXPORT void Vec4::GetValues<GLint>(GLint* values) const;
 template <>
-GPU_EXPORT void Vec4::GetValues<GLuint>(GLuint* values) const;
+GPU_GLES2_EXPORT void Vec4::GetValues<GLuint>(GLuint* values) const;
 
 template <>
-GPU_EXPORT void Vec4::SetValues<GLfloat>(const GLfloat* values);
+GPU_GLES2_EXPORT void Vec4::SetValues<GLfloat>(const GLfloat* values);
 template <>
-GPU_EXPORT void Vec4::SetValues<GLint>(const GLint* values);
+GPU_GLES2_EXPORT void Vec4::SetValues<GLint>(const GLint* values);
 template <>
-GPU_EXPORT void Vec4::SetValues<GLuint>(const GLuint* values);
+GPU_GLES2_EXPORT void Vec4::SetValues<GLuint>(const GLuint* values);
 
-struct GPU_EXPORT ContextState {
+struct GPU_GLES2_EXPORT ContextState {
   enum Dimension {
     k2D,
     k3D
diff --git a/gpu/command_buffer/service/decoder_context.h b/gpu/command_buffer/service/decoder_context.h
index d960712..03939895f 100644
--- a/gpu/command_buffer/service/decoder_context.h
+++ b/gpu/command_buffer/service/decoder_context.h
@@ -16,7 +16,7 @@
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/command_buffer/service/async_api_interface.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gl {
 class GLContext;
@@ -40,7 +40,7 @@
 // Abstract interface implemented by {Raster,GLES2}Decoder. It is called a
 // DecoderContext because all methods are about decoding commands or
 // accessing context/state generated by decoded commands.
-class GPU_EXPORT DecoderContext : public AsyncAPIInterface {
+class GPU_GLES2_EXPORT DecoderContext : public AsyncAPIInterface {
  public:
   DecoderContext() = default;
   ~DecoderContext() override = default;
diff --git a/gpu/command_buffer/service/error_state.h b/gpu/command_buffer/service/error_state.h
index 9681565..3f91eaf 100644
--- a/gpu/command_buffer/service/error_state.h
+++ b/gpu/command_buffer/service/error_state.h
@@ -11,7 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -57,14 +57,14 @@
 #define ERRORSTATE_CLEAR_REAL_GL_ERRORS(error_state, function_name) \
     error_state->ClearRealGLErrors(__FILE__, __LINE__, function_name)
 
-class GPU_EXPORT ErrorStateClient {
+class GPU_GLES2_EXPORT ErrorStateClient {
  public:
   virtual void OnContextLostError() = 0;
   // GL_OUT_OF_MEMORY can cause side effects such as losing the context.
   virtual void OnOutOfMemoryError() = 0;
 };
 
-class GPU_EXPORT ErrorState {
+class GPU_GLES2_EXPORT ErrorState {
  public:
   virtual ~ErrorState();
 
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 24e2c75b..2548add 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -14,7 +14,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gles2_cmd_validation.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "ui/gl/extension_set.h"
 
 namespace base {
@@ -29,7 +29,7 @@
 namespace gles2 {
 
 // FeatureInfo records the features that are available for a ContextGroup.
-class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
+class GPU_GLES2_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
  public:
   struct FeatureFlags {
     FeatureFlags();
diff --git a/gpu/command_buffer/service/framebuffer_completeness_cache.h b/gpu/command_buffer/service/framebuffer_completeness_cache.h
index dd26bf69..05be906b 100644
--- a/gpu/command_buffer/service/framebuffer_completeness_cache.h
+++ b/gpu/command_buffer/service/framebuffer_completeness_cache.h
@@ -9,7 +9,7 @@
 
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -17,7 +17,7 @@
 // Refcounted wrapper for a hash_set of framebuffer format signatures
 // representing framebuffer configurations that are reported by the GL
 // driver as complete according to glCheckFramebufferStatusEXT.
-class GPU_EXPORT FramebufferCompletenessCache {
+class GPU_GLES2_EXPORT FramebufferCompletenessCache {
  public:
   FramebufferCompletenessCache();
   ~FramebufferCompletenessCache();
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 7cef4d19..2629731 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -17,7 +17,7 @@
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/shader_manager.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -31,7 +31,7 @@
 class TextureManager;
 
 // Info about a particular Framebuffer.
-class GPU_EXPORT Framebuffer : public base::RefCounted<Framebuffer> {
+class GPU_GLES2_EXPORT Framebuffer : public base::RefCounted<Framebuffer> {
  public:
   class Attachment : public base::RefCounted<Attachment> {
    public:
@@ -320,7 +320,7 @@
 
 // This class keeps track of the frambebuffers and their attached renderbuffers
 // so we can correctly clear them.
-class GPU_EXPORT FramebufferManager {
+class GPU_GLES2_EXPORT FramebufferManager {
  public:
   FramebufferManager(
       uint32_t max_draw_buffers,
diff --git a/gpu/command_buffer/service/gl_context_virtual.h b/gpu/command_buffer/service/gl_context_virtual.h
index 6453333a..7b4c299c 100644
--- a/gpu/command_buffer/service/gl_context_virtual.h
+++ b/gpu/command_buffer/service/gl_context_virtual.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "ui/gl/gl_context.h"
 
 namespace gl {
@@ -23,7 +23,7 @@
 class DecoderContext;
 
 // Encapsulates a virtual OpenGL context.
-class GPU_EXPORT GLContextVirtual : public gl::GLContext {
+class GPU_GLES2_EXPORT GLContextVirtual : public gl::GLContext {
  public:
   GLContextVirtual(gl::GLShareGroup* share_group,
                    gl::GLContext* shared_context,
diff --git a/gpu/command_buffer/service/gl_state_restorer_impl.h b/gpu/command_buffer/service/gl_state_restorer_impl.h
index 082d526..be490a7 100644
--- a/gpu/command_buffer/service/gl_state_restorer_impl.h
+++ b/gpu/command_buffer/service/gl_state_restorer_impl.h
@@ -10,7 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "ui/gl/gl_state_restorer.h"
 
 namespace gpu {
@@ -22,7 +22,7 @@
 }
 
 // This class implements a GLStateRestorer that forwards to a DecoderContext.
-class GPU_EXPORT GLStateRestorerImpl : public gl::GLStateRestorer {
+class GPU_GLES2_EXPORT GLStateRestorerImpl : public gl::GLStateRestorer {
  public:
   explicit GLStateRestorerImpl(base::WeakPtr<DecoderContext> decoder);
   ~GLStateRestorerImpl() override;
diff --git a/gpu/command_buffer/service/gl_stream_texture_image.h b/gpu/command_buffer/service/gl_stream_texture_image.h
index 8fb647a..3fdf673 100644
--- a/gpu/command_buffer/service/gl_stream_texture_image.h
+++ b/gpu/command_buffer/service/gl_stream_texture_image.h
@@ -5,7 +5,7 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GL_STREAM_TEXTURE_IMAGE_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GL_STREAM_TEXTURE_IMAGE_H_
 
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "ui/gl/gl_image.h"
 
 namespace gpu {
@@ -13,7 +13,7 @@
 
 // Specialization of GLImage that allows us to support (stream) textures
 // that supply a texture matrix.
-class GPU_EXPORT GLStreamTextureImage : public gl::GLImage {
+class GPU_GLES2_EXPORT GLStreamTextureImage : public gl::GLImage {
  public:
   // Get the matrix.
   // Copy the texture matrix for this image into |matrix|.
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
index 9f2bd9ae..33bade3 100644
--- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
+++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
@@ -6,7 +6,7 @@
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_APPLY_FRAMEBUFFER_ATTACHMENT_CMAA_INTEL_H_
 
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -22,7 +22,7 @@
 // all color attachments of the currently bound draw framebuffer.
 //
 // Reference GL_INTEL_framebuffer_CMAA for details.
-class GPU_EXPORT ApplyFramebufferAttachmentCMAAINTELResourceManager {
+class GPU_GLES2_EXPORT ApplyFramebufferAttachmentCMAAINTELResourceManager {
  public:
   ApplyFramebufferAttachmentCMAAINTELResourceManager();
   ~ApplyFramebufferAttachmentCMAAINTELResourceManager();
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
index 403d229..7896f1e5 100644
--- a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gfx {
 class Size;
@@ -17,7 +17,7 @@
 namespace gles2 {
 class GLES2Decoder;
 
-class GPU_EXPORT ClearFramebufferResourceManager {
+class GPU_GLES2_EXPORT ClearFramebufferResourceManager {
  public:
   ClearFramebufferResourceManager(const gles2::GLES2Decoder* decoder);
   ~ClearFramebufferResourceManager();
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_tex_image.h b/gpu/command_buffer/service/gles2_cmd_copy_tex_image.h
index eaf574e..15d44a9 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_tex_image.h
+++ b/gpu/command_buffer/service/gles2_cmd_copy_tex_image.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -21,7 +21,7 @@
 // This class encapsulates the resources required to implement the
 // glCopyTexImage and glCopyTexSubImage commands.  These commands somtimes
 // require a blit.
-class GPU_EXPORT CopyTexImageResourceManager {
+class GPU_GLES2_EXPORT CopyTexImageResourceManager {
  public:
   explicit CopyTexImageResourceManager(const gles2::FeatureInfo* feature_info);
   ~CopyTexImageResourceManager();
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
index 95e5063..e17b29e 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -44,7 +44,7 @@
 // GL_CHROMIUM_copy_texture extension.  The copy operation is performed
 // via glCopyTexImage2D() or a blit to a framebuffer object.
 // The target of |dest_id| texture must be GL_TEXTURE_2D.
-class GPU_EXPORT CopyTextureCHROMIUMResourceManager {
+class GPU_GLES2_EXPORT CopyTextureCHROMIUMResourceManager {
  public:
   CopyTextureCHROMIUMResourceManager();
   ~CopyTextureCHROMIUMResourceManager();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 80e4d6d..fdf10c2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -24,7 +24,7 @@
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/command_buffer/service/common_decoder.h"
 #include "gpu/command_buffer/service/decoder_context.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gl {
 class GLSurface;
@@ -77,7 +77,8 @@
 
 // This class implements the DecoderContext interface, decoding GLES2
 // commands and calling GL.
-class GPU_EXPORT GLES2Decoder : public CommonDecoder, public DecoderContext {
+class GPU_GLES2_EXPORT GLES2Decoder : public CommonDecoder,
+                                      public DecoderContext {
  public:
   typedef error::Error Error;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index c44899fe..6fe8e67 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -1141,7 +1141,6 @@
   // This is unconditionally true on mac, no need to test for it at runtime.
   caps.iosurface = true;
 #endif
-  caps.flips_vertically = surface_->FlipsVertically();
   caps.blend_equation_advanced =
       feature_info_->feature_flags().blend_equation_advanced;
   caps.blend_equation_advanced_coherent =
@@ -1167,6 +1166,10 @@
   caps.occlusion_query_boolean =
       feature_info_->feature_flags().occlusion_query_boolean;
   caps.timer_queries = feature_info_->feature_flags().ext_disjoint_timer_query;
+  caps.gpu_rasterization =
+      group_->gpu_feature_info()
+          .status_values[GPU_FEATURE_TYPE_GPU_RASTERIZATION] ==
+      kGpuFeatureStatusEnabled;
   caps.post_sub_buffer = surface_->SupportsPostSubBuffer();
   caps.surfaceless = !offscreen_ && surface_->IsSurfaceless();
   caps.flips_vertically = !offscreen_ && surface_->FlipsVertically();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index 12c3feb3..7e5b104 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -107,7 +107,7 @@
   GLint texture_;
 };
 
-class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
+class GPU_GLES2_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
  public:
   GLES2DecoderPassthroughImpl(DecoderClient* client,
                               CommandBufferServiceBase* command_buffer_service,
diff --git a/gpu/command_buffer/service/gles2_cmd_srgb_converter.h b/gpu/command_buffer/service/gles2_cmd_srgb_converter.h
index 2a19fa9..db39a96 100644
--- a/gpu/command_buffer/service/gles2_cmd_srgb_converter.h
+++ b/gpu/command_buffer/service/gles2_cmd_srgb_converter.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -21,7 +21,7 @@
 // This class encapsulates the resources required to implement the
 // glBlitFramebuffer command, which somtimes requires to convert sRGB
 // to linear (RGBA) color format, or vice versa.
-class GPU_EXPORT SRGBConverter {
+class GPU_GLES2_EXPORT SRGBConverter {
  public:
   explicit SRGBConverter(const gles2::FeatureInfo* feature_info);
   ~SRGBConverter();
diff --git a/gpu/command_buffer/service/gpu_fence_manager.h b/gpu/command_buffer/service/gpu_fence_manager.h
index acb3a40..c6e03a8 100644
--- a/gpu/command_buffer/service/gpu_fence_manager.h
+++ b/gpu/command_buffer/service/gpu_fence_manager.h
@@ -10,7 +10,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gfx {
 struct GpuFenceHandle;
@@ -26,8 +26,8 @@
 
 // This class keeps track of GpuFence objects and their state. As GpuFence
 // objects are not shared there is one GpuFenceManager per context.
-class GPU_EXPORT GpuFenceManager {
-  class GPU_EXPORT GpuFenceEntry {
+class GPU_GLES2_EXPORT GpuFenceManager {
+  class GPU_GLES2_EXPORT GpuFenceEntry {
    public:
     GpuFenceEntry();
     ~GpuFenceEntry();
diff --git a/gpu/command_buffer/service/gpu_switches.h b/gpu/command_buffer/service/gpu_switches.h
index d1c23e6a..6674fad 100644
--- a/gpu/command_buffer/service/gpu_switches.h
+++ b/gpu/command_buffer/service/gpu_switches.h
@@ -13,8 +13,8 @@
 namespace gpu {
 
 // The command decoder names that can be passed to --use-cmd-decoder.
-extern const char kCmdDecoderValidatingName[];
-extern const char kCmdDecoderPassthroughName[];
+GPU_EXPORT extern const char kCmdDecoderValidatingName[];
+GPU_EXPORT extern const char kCmdDecoderPassthroughName[];
 }  // namespace gpu
 
 namespace switches {
diff --git a/gpu/command_buffer/service/gpu_tracer.h b/gpu/command_buffer/service/gpu_tracer.h
index 423ece7b..79de329 100644
--- a/gpu/command_buffer/service/gpu_tracer.h
+++ b/gpu/command_buffer/service/gpu_tracer.h
@@ -17,7 +17,7 @@
 #include "base/macros.h"
 #include "base/threading/thread.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gl {
 class GPUTimingClient;
@@ -53,7 +53,7 @@
 };
 
 // Traces GPU Commands.
-class GPU_EXPORT GPUTracer {
+class GPU_GLES2_EXPORT GPUTracer {
  public:
   explicit GPUTracer(GLES2Decoder* decoder);
   virtual ~GPUTracer();
@@ -103,7 +103,7 @@
   DISALLOW_COPY_AND_ASSIGN(GPUTracer);
 };
 
-class GPU_EXPORT Outputter {
+class GPU_GLES2_EXPORT Outputter {
  public:
   virtual ~Outputter() = default;
 
@@ -122,7 +122,7 @@
                                const std::string& name) = 0;
 };
 
-class GPU_EXPORT TraceOutputter : public Outputter {
+class GPU_GLES2_EXPORT TraceOutputter : public Outputter {
  public:
   TraceOutputter();
   explicit TraceOutputter(const std::string& name);
@@ -152,8 +152,7 @@
   DISALLOW_COPY_AND_ASSIGN(TraceOutputter);
 };
 
-class GPU_EXPORT GPUTrace
-    : public base::RefCounted<GPUTrace> {
+class GPU_GLES2_EXPORT GPUTrace : public base::RefCounted<GPUTrace> {
  public:
   GPUTrace(Outputter* outputter,
            gl::GPUTimingClient* gpu_timing_client,
diff --git a/gpu/command_buffer/service/id_manager.h b/gpu/command_buffer/service/id_manager.h
index 7afb5fd..b855282 100644
--- a/gpu/command_buffer/service/id_manager.h
+++ b/gpu/command_buffer/service/id_manager.h
@@ -8,7 +8,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -17,7 +17,7 @@
 //
 // NOTE: To support shared resources an instance of this class will
 // need to be shared by multiple GLES2Decoders.
-class GPU_EXPORT IdManager {
+class GPU_GLES2_EXPORT IdManager {
  public:
   IdManager();
   ~IdManager();
diff --git a/gpu/command_buffer/service/indexed_buffer_binding_host.h b/gpu/command_buffer/service/indexed_buffer_binding_host.h
index 18175b8..86c78ffd 100644
--- a/gpu/command_buffer/service/indexed_buffer_binding_host.h
+++ b/gpu/command_buffer/service/indexed_buffer_binding_host.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -19,8 +19,8 @@
 // This is a base class for indexed buffer bindings tracking.
 // TransformFeedback and Program should inherit from this base class,
 // for tracking indexed TRANSFORM_FEEDBACK_BUFFER / UNIFORM_BUFFER bindings.
-class GPU_EXPORT IndexedBufferBindingHost :
-    public base::RefCounted<IndexedBufferBindingHost> {
+class GPU_GLES2_EXPORT IndexedBufferBindingHost
+    : public base::RefCounted<IndexedBufferBindingHost> {
  public:
   // In theory |needs_emulation| needs to be true on Desktop GL 4.1 or lower.
   // However, we set it to true everywhere, not to trust drivers to handle
diff --git a/gpu/command_buffer/service/logger.h b/gpu/command_buffer/service/logger.h
index c6eb167..af907b9 100644
--- a/gpu/command_buffer/service/logger.h
+++ b/gpu/command_buffer/service/logger.h
@@ -13,7 +13,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -23,7 +23,7 @@
 
 class DebugMarkerManager;
 
-class GPU_EXPORT Logger {
+class GPU_GLES2_EXPORT Logger {
  public:
   static const int kMaxLogMessages = 256;
 
diff --git a/gpu/command_buffer/service/mailbox_manager_factory.h b/gpu/command_buffer/service/mailbox_manager_factory.h
index 87bd888..a448c55 100644
--- a/gpu/command_buffer/service/mailbox_manager_factory.h
+++ b/gpu/command_buffer/service/mailbox_manager_factory.h
@@ -6,7 +6,7 @@
 #define GPU_COMMAND_BUFFER_SERVICE_MAILBOX_MANAGER_FACTORY_H_
 
 #include "gpu/command_buffer/service/mailbox_manager.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -14,7 +14,7 @@
 
 namespace gles2 {
 
-std::unique_ptr<MailboxManager> GPU_EXPORT
+std::unique_ptr<MailboxManager> GPU_GLES2_EXPORT
 CreateMailboxManager(const GpuPreferences& gpu_preferences);
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/mailbox_manager_impl.h b/gpu/command_buffer/service/mailbox_manager_impl.h
index cb31003..ec668302 100644
--- a/gpu/command_buffer/service/mailbox_manager_impl.h
+++ b/gpu/command_buffer/service/mailbox_manager_impl.h
@@ -13,13 +13,13 @@
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
 
 // Manages resources scoped beyond the context or context group level.
-class GPU_EXPORT MailboxManagerImpl : public MailboxManager {
+class GPU_GLES2_EXPORT MailboxManagerImpl : public MailboxManager {
  public:
   MailboxManagerImpl();
   ~MailboxManagerImpl() override;
diff --git a/gpu/command_buffer/service/mailbox_manager_sync.h b/gpu/command_buffer/service/mailbox_manager_sync.h
index 33f4e36..48275fa 100644
--- a/gpu/command_buffer/service/mailbox_manager_sync.h
+++ b/gpu/command_buffer/service/mailbox_manager_sync.h
@@ -16,7 +16,7 @@
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/texture_definition.h"
 #include "gpu/command_buffer/service/texture_manager.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -24,7 +24,7 @@
 // Manages resources scoped beyond the context or context group level
 // and across threads and driver level share groups by synchronizing
 // texture state.
-class GPU_EXPORT MailboxManagerSync : public MailboxManager {
+class GPU_GLES2_EXPORT MailboxManagerSync : public MailboxManager {
  public:
   MailboxManagerSync();
   ~MailboxManagerSync() override;
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index c138fed..04e4584 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -25,7 +25,7 @@
 namespace gles2 {
 
 // Program cache that stores binaries completely in-memory
-class GPU_EXPORT MemoryProgramCache : public ProgramCache {
+class GPU_GLES2_EXPORT MemoryProgramCache : public ProgramCache {
  public:
   MemoryProgramCache(size_t max_cache_size_bytes,
                      bool disable_gpu_shader_disk_cache,
diff --git a/gpu/command_buffer/service/passthrough_program_cache.h b/gpu/command_buffer/service/passthrough_program_cache.h
index 87f583d..dca1dd9b 100644
--- a/gpu/command_buffer/service/passthrough_program_cache.h
+++ b/gpu/command_buffer/service/passthrough_program_cache.h
@@ -15,7 +15,7 @@
 
 // Program cache that does not store binaries, but communicates with the
 // underlying implementation via the cache control extension.
-class GPU_EXPORT PassthroughProgramCache : public ProgramCache {
+class GPU_GLES2_EXPORT PassthroughProgramCache : public ProgramCache {
  public:
   PassthroughProgramCache(size_t max_cache_size_bytes,
                           bool disable_gpu_shader_disk_cache);
diff --git a/gpu/command_buffer/service/path_manager.h b/gpu/command_buffer/service/path_manager.h
index d334a860..840f621 100644
--- a/gpu/command_buffer/service/path_manager.h
+++ b/gpu/command_buffer/service/path_manager.h
@@ -9,14 +9,14 @@
 
 #include "base/macros.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
 
 // This class keeps track of paths and their client and service ids
 // so we can correctly clear them.
-class GPU_EXPORT PathManager {
+class GPU_GLES2_EXPORT PathManager {
  public:
   PathManager();
   ~PathManager();
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h
index 45b2f6e1..dc21756 100644
--- a/gpu/command_buffer/service/program_cache.h
+++ b/gpu/command_buffer/service/program_cache.h
@@ -24,7 +24,7 @@
 class Shader;
 
 // Program cache base class for caching linked gpu programs
-class GPU_EXPORT ProgramCache {
+class GPU_GLES2_EXPORT ProgramCache {
  public:
   static const size_t kHashLength = base::kSHA1Length;
 
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 841091ca..cbd2f02 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -19,7 +19,7 @@
 #include "gpu/command_buffer/service/common_decoder.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/shader_manager.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -38,7 +38,7 @@
 // This is used to track which attributes a particular program needs
 // so we can verify at glDrawXXX time that every attribute is either disabled
 // or if enabled that it points to a valid source.
-class GPU_EXPORT Program : public base::RefCounted<Program> {
+class GPU_GLES2_EXPORT Program : public base::RefCounted<Program> {
  public:
   static const int kMaxAttachedShaders = 2;
 
@@ -642,7 +642,7 @@
 //
 // NOTE: To support shared resources an instance of this class will
 // need to be shared by multiple GLES2Decoders.
-class GPU_EXPORT ProgramManager {
+class GPU_GLES2_EXPORT ProgramManager {
  public:
   ProgramManager(ProgramCache* program_cache,
                  uint32_t max_varying_vectors,
diff --git a/gpu/command_buffer/service/progress_reporter.h b/gpu/command_buffer/service/progress_reporter.h
index 14d57b6..926e4f8 100644
--- a/gpu/command_buffer/service/progress_reporter.h
+++ b/gpu/command_buffer/service/progress_reporter.h
@@ -5,14 +5,14 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_PROGRESS_REPORTER_H_
 #define GPU_COMMAND_BUFFER_SERVICE_PROGRESS_REPORTER_H_
 
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
 
 // ProgressReporter is used by ContextGroup to report when it is making forward
 // progress in execution, delaying activation of the watchdog timeout.
-class GPU_EXPORT ProgressReporter {
+class GPU_GLES2_EXPORT ProgressReporter {
  public:
   virtual ~ProgressReporter() = default;
 
diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h
index ba0c34a..9f7724b 100644
--- a/gpu/command_buffer/service/query_manager.h
+++ b/gpu/command_buffer/service/query_manager.h
@@ -17,7 +17,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/feature_info.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gl {
 class GPUTimer;
@@ -34,9 +34,9 @@
 
 // This class keeps track of the queries and their state
 // As Queries are not shared there is one QueryManager per context.
-class GPU_EXPORT QueryManager {
+class GPU_GLES2_EXPORT QueryManager {
  public:
-  class GPU_EXPORT Query : public base::RefCounted<Query> {
+  class GPU_GLES2_EXPORT Query : public base::RefCounted<Query> {
    public:
     Query(QueryManager* manager,
           GLenum target,
diff --git a/gpu/command_buffer/service/raster_decoder.h b/gpu/command_buffer/service/raster_decoder.h
index 2b148ea..2cabd936 100644
--- a/gpu/command_buffer/service/raster_decoder.h
+++ b/gpu/command_buffer/service/raster_decoder.h
@@ -29,7 +29,7 @@
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gles2_cmd_validation.h"
 #include "gpu/command_buffer/service/logger.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -40,9 +40,9 @@
 
 // This class implements the AsyncAPIInterface interface, decoding
 // RasterInterface commands and calling GL.
-class GPU_EXPORT RasterDecoder : public DecoderContext,
-                                 public CommonDecoder,
-                                 public gles2::ErrorStateClient {
+class GPU_GLES2_EXPORT RasterDecoder : public DecoderContext,
+                                       public CommonDecoder,
+                                       public gles2::ErrorStateClient {
  public:
   RasterDecoder(DecoderClient* client,
                 CommandBufferServiceBase* command_buffer_service,
diff --git a/gpu/command_buffer/service/renderbuffer_manager.h b/gpu/command_buffer/service/renderbuffer_manager.h
index 72373f7..a647c5b5 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.h
+++ b/gpu/command_buffer/service/renderbuffer_manager.h
@@ -17,7 +17,7 @@
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 class GpuDriverBugWorkarounds;
@@ -29,8 +29,7 @@
 class RenderbufferManager;
 
 // Info about a Renderbuffer.
-class GPU_EXPORT Renderbuffer
-    : public base::RefCounted<Renderbuffer> {
+class GPU_GLES2_EXPORT Renderbuffer : public base::RefCounted<Renderbuffer> {
  public:
   Renderbuffer(RenderbufferManager* manager,
                GLuint client_id,
@@ -146,7 +145,7 @@
 
 // This class keeps track of the renderbuffers and whether or not they have
 // been cleared.
-class GPU_EXPORT RenderbufferManager
+class GPU_GLES2_EXPORT RenderbufferManager
     : public base::trace_event::MemoryDumpProvider {
  public:
   RenderbufferManager(MemoryTracker* memory_tracker,
diff --git a/gpu/command_buffer/service/sampler_manager.h b/gpu/command_buffer/service/sampler_manager.h
index 61c5116..05d2958 100644
--- a/gpu/command_buffer/service/sampler_manager.h
+++ b/gpu/command_buffer/service/sampler_manager.h
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -35,7 +35,7 @@
   GLfloat min_lod;
 };
 
-class GPU_EXPORT Sampler : public base::RefCounted<Sampler> {
+class GPU_GLES2_EXPORT Sampler : public base::RefCounted<Sampler> {
  public:
   Sampler(SamplerManager* manager, GLuint client_id, GLuint service_id);
 
@@ -128,7 +128,7 @@
 };
 
 // This class keeps track of the samplers and their state.
-class GPU_EXPORT SamplerManager {
+class GPU_GLES2_EXPORT SamplerManager {
  public:
   SamplerManager(FeatureInfo* feature_info);
   ~SamplerManager();
diff --git a/gpu/command_buffer/service/service_discardable_manager.h b/gpu/command_buffer/service/service_discardable_manager.h
index e415a82..8723bf0 100644
--- a/gpu/command_buffer/service/service_discardable_manager.h
+++ b/gpu/command_buffer/service/service_discardable_manager.h
@@ -11,7 +11,7 @@
 #include "base/memory/memory_pressure_listener.h"
 #include "gpu/command_buffer/common/discardable_handle.h"
 #include "gpu/command_buffer/service/context_group.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -19,7 +19,7 @@
 class TextureRef;
 }
 
-class GPU_EXPORT ServiceDiscardableManager {
+class GPU_GLES2_EXPORT ServiceDiscardableManager {
  public:
   ServiceDiscardableManager();
   ~ServiceDiscardableManager();
diff --git a/gpu/command_buffer/service/service_transfer_cache.h b/gpu/command_buffer/service/service_transfer_cache.h
index ce553934..4cacac1 100644
--- a/gpu/command_buffer/service/service_transfer_cache.h
+++ b/gpu/command_buffer/service/service_transfer_cache.h
@@ -12,7 +12,7 @@
 #include "cc/paint/transfer_cache_entry.h"
 #include "gpu/command_buffer/common/discardable_handle.h"
 #include "gpu/command_buffer/service/context_group.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 
@@ -24,7 +24,7 @@
 // unlocking and deleting entries when no longer needed, as well as enforcing
 // cache limits. If the cache exceeds its specified limits, unlocked transfer
 // cache entries may be deleted.
-class GPU_EXPORT ServiceTransferCache {
+class GPU_GLES2_EXPORT ServiceTransferCache {
  public:
   ServiceTransferCache();
   ~ServiceTransferCache();
diff --git a/gpu/command_buffer/service/service_utils.h b/gpu/command_buffer/service/service_utils.h
index 8514ed0f..589d13b8 100644
--- a/gpu/command_buffer/service/service_utils.h
+++ b/gpu/command_buffer/service/service_utils.h
@@ -6,7 +6,7 @@
 #define GPU_COMMAND_BUFFER_SERVICE_SERVICE_UTILS_H_
 
 #include "base/command_line.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "ui/gl/gl_context.h"
 
 namespace gpu {
@@ -15,16 +15,16 @@
 namespace gles2 {
 class ContextGroup;
 
-GPU_EXPORT gl::GLContextAttribs GenerateGLContextAttribs(
+GPU_GLES2_EXPORT gl::GLContextAttribs GenerateGLContextAttribs(
     const ContextCreationAttribs& attribs_helper,
     const ContextGroup* context_group);
 
 // Returns true if the passthrough command decoder has been requested
-GPU_EXPORT bool UsePassthroughCommandDecoder(
+GPU_GLES2_EXPORT bool UsePassthroughCommandDecoder(
     const base::CommandLine* command_line);
 
 // Returns true if the driver supports creating passthrough command decoders
-GPU_EXPORT bool PassthroughCommandDecoderSupported();
+GPU_GLES2_EXPORT bool PassthroughCommandDecoderSupported();
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index 4df84f0..18c9f11 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/shader_translator.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -31,7 +31,7 @@
 // to emluate GLES2 the shaders will have to be re-written before passed to
 // the underlying OpenGL. But, when the user calls glGetShaderSource they
 // should get the source they passed in, not the re-written source.
-class GPU_EXPORT Shader : public base::RefCounted<Shader> {
+class GPU_GLES2_EXPORT Shader : public base::RefCounted<Shader> {
  public:
   enum TranslatedShaderSourceType {
     kANGLE,
@@ -265,7 +265,7 @@
 //
 // NOTE: To support shared resources an instance of this class will
 // need to be shared by multiple GLES2Decoders.
-class GPU_EXPORT ShaderManager {
+class GPU_GLES2_EXPORT ShaderManager {
  public:
   ShaderManager(ProgressReporter* progress_reporter);
   ~ShaderManager();
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index eb11dcf..f6f80adb 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "third_party/angle/include/GLSLANG/ShaderLang.h"
 
 namespace gl {
@@ -74,7 +74,7 @@
 };
 
 // Implementation of ShaderTranslatorInterface
-class GPU_EXPORT ShaderTranslator : public ShaderTranslatorInterface {
+class GPU_GLES2_EXPORT ShaderTranslator : public ShaderTranslatorInterface {
  public:
   class DestructionObserver {
    public:
diff --git a/gpu/command_buffer/service/shader_translator_cache.h b/gpu/command_buffer/service/shader_translator_cache.h
index 391ff34a..ffc2bab3 100644
--- a/gpu/command_buffer/service/shader_translator_cache.h
+++ b/gpu/command_buffer/service/shader_translator_cache.h
@@ -27,7 +27,7 @@
 //
 // TODO(backer): Investigate using glReleaseShaderCompiler as an alternative to
 // to this cache.
-class GPU_EXPORT ShaderTranslatorCache
+class GPU_GLES2_EXPORT ShaderTranslatorCache
     : public ShaderTranslator::DestructionObserver {
  public:
   explicit ShaderTranslatorCache(const GpuPreferences& gpu_preferences);
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index 6b10aec..fe57445c 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -23,7 +23,7 @@
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/sampler_manager.h"
 #include "gpu/command_buffer/service/texture_base.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gl/gl_image.h"
 
@@ -74,7 +74,7 @@
 // Info about Textures currently in the system.
 // This class wraps a real GL texture, keeping track of its meta-data. It is
 // jointly owned by possibly multiple TextureRef.
-class GPU_EXPORT Texture final : public TextureBase {
+class GPU_GLES2_EXPORT Texture final : public TextureBase {
  public:
   enum ImageState {
     // If an image is associated with the texture and image state is UNBOUND,
@@ -627,7 +627,7 @@
 // with a client id, though it can outlive the client id if it's still bound to
 // a FBO or another context when destroyed.
 // Multiple TextureRef can point to the same texture with cross-context sharing.
-class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> {
+class GPU_GLES2_EXPORT TextureRef : public base::RefCounted<TextureRef> {
  public:
   TextureRef(TextureManager* manager, GLuint client_id, Texture* texture);
   static scoped_refptr<TextureRef> Create(TextureManager* manager,
@@ -693,9 +693,10 @@
 //
 // NOTE: To support shared resources an instance of this class will need to be
 // shared by multiple GLES2Decoders.
-class GPU_EXPORT TextureManager : public base::trace_event::MemoryDumpProvider {
+class GPU_GLES2_EXPORT TextureManager
+    : public base::trace_event::MemoryDumpProvider {
  public:
-  class GPU_EXPORT DestructionObserver {
+  class GPU_GLES2_EXPORT DestructionObserver {
    public:
     DestructionObserver();
     virtual ~DestructionObserver();
diff --git a/gpu/command_buffer/service/transform_feedback_manager.h b/gpu/command_buffer/service/transform_feedback_manager.h
index edb5227..09c370e4 100644
--- a/gpu/command_buffer/service/transform_feedback_manager.h
+++ b/gpu/command_buffer/service/transform_feedback_manager.h
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/indexed_buffer_binding_host.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -20,7 +20,7 @@
 class TransformFeedbackManager;
 
 // Info about TransformFeedbacks currently in the system.
-class GPU_EXPORT TransformFeedback : public IndexedBufferBindingHost {
+class GPU_GLES2_EXPORT TransformFeedback : public IndexedBufferBindingHost {
  public:
   TransformFeedback(
       TransformFeedbackManager* manager, GLuint client_id, GLuint service_id);
@@ -76,7 +76,7 @@
 };
 
 // This class keeps tracks of the transform feedbacks and their states.
-class GPU_EXPORT TransformFeedbackManager {
+class GPU_GLES2_EXPORT TransformFeedbackManager {
  public:
   // In theory |needs_emulation| needs to be true on Desktop GL 4.1 or lower.
   // However, we set it to true everywhere, not to trust drivers to handle
diff --git a/gpu/command_buffer/service/vertex_array_manager.h b/gpu/command_buffer/service/vertex_array_manager.h
index 8221f30..5ff5649 100644
--- a/gpu/command_buffer/service/vertex_array_manager.h
+++ b/gpu/command_buffer/service/vertex_array_manager.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -21,7 +21,7 @@
 
 // This class keeps track of the vertex arrays and their sizes so we can do
 // bounds checking.
-class GPU_EXPORT VertexArrayManager {
+class GPU_GLES2_EXPORT VertexArrayManager {
  public:
   VertexArrayManager();
   ~VertexArrayManager();
diff --git a/gpu/command_buffer/service/vertex_attrib_manager.h b/gpu/command_buffer/service/vertex_attrib_manager.h
index ced1e371..ff54986 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager.h
+++ b/gpu/command_buffer/service/vertex_attrib_manager.h
@@ -15,7 +15,7 @@
 #include "build/build_config.h"
 #include "gpu/command_buffer/service/buffer_manager.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/gpu_export.h"
+#include "gpu/gpu_gles2_export.h"
 
 namespace gpu {
 namespace gles2 {
@@ -29,7 +29,7 @@
 // Info about a Vertex Attribute. This is used to track what the user currently
 // has bound on each Vertex Attribute so that checking can be done at
 // glDrawXXX time.
-class GPU_EXPORT VertexAttrib {
+class GPU_GLES2_EXPORT VertexAttrib {
  public:
   typedef std::list<VertexAttrib*> VertexAttribList;
 
@@ -180,8 +180,8 @@
 // Manages vertex attributes.
 // This class also acts as the service-side representation of a
 // vertex array object and it's contained state.
-class GPU_EXPORT VertexAttribManager :
-    public base::RefCounted<VertexAttribManager> {
+class GPU_GLES2_EXPORT VertexAttribManager
+    : public base::RefCounted<VertexAttribManager> {
  public:
   typedef std::list<VertexAttrib*> VertexAttribList;
 
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index f151284..df34075 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -144,6 +144,9 @@
       ]
     }
   }
+  if (is_mac) {
+    libs = [ "OpenGL.framework" ]
+  }
   if (is_linux || is_mac) {
     deps += [ "//third_party/angle:angle_gpu_info_util" ]
   }
diff --git a/gpu/gles2_conform_support/egl/BUILD.gn b/gpu/gles2_conform_support/egl/BUILD.gn
index 622671c..92289196 100644
--- a/gpu/gles2_conform_support/egl/BUILD.gn
+++ b/gpu/gles2_conform_support/egl/BUILD.gn
@@ -31,8 +31,10 @@
     "//base",
     "//gpu",
     "//gpu/command_buffer/client:gles2_c_lib_nocheck",
+    "//gpu/command_buffer/client:gles2_cmd_helper",
     "//gpu/command_buffer/client:gles2_implementation_no_check",
     "//gpu/command_buffer/service",
+    "//gpu/command_buffer/service:gles2",
     "//ui/base",
     "//ui/gfx",
     "//ui/gfx/geometry",
diff --git a/gpu/gpu_gles2_export.h b/gpu/gpu_gles2_export.h
new file mode 100644
index 0000000..cf7d3b4
--- /dev/null
+++ b/gpu/gpu_gles2_export.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 GPU_GPU_GLES2_EXPORT_H_
+#define GPU_GPU_GLES2_EXPORT_H_
+
+#if defined(COMPONENT_BUILD) && !defined(NACL_WIN64)
+#if defined(WIN32)
+
+#if defined(GPU_GLES2_IMPLEMENTATION)
+#define GPU_GLES2_EXPORT __declspec(dllexport)
+#else
+#define GPU_GLES2_EXPORT __declspec(dllimport)
+#endif  // defined(GPU_GLES2_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(GPU_GLES2_IMPLEMENTATION)
+#define GPU_GLES2_EXPORT __attribute__((visibility("default")))
+#else
+#define GPU_GLES2_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define GPU_GLES2_EXPORT
+#endif
+
+#endif  // GPU_GPU_GLES2_EXPORT_H_
diff --git a/gpu/ipc/client/BUILD.gn b/gpu/ipc/client/BUILD.gn
index 893723183..7821893 100644
--- a/gpu/ipc/client/BUILD.gn
+++ b/gpu/ipc/client/BUILD.gn
@@ -32,6 +32,7 @@
       "gpu_memory_buffer_impl_io_surface.cc",
       "gpu_memory_buffer_impl_io_surface.h",
     ]
+    libs = [ "IOSurface.framework" ]
   }
   if (is_win) {
     sources += [
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 0ddaa758..bb24210 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -208,6 +208,9 @@
     {"ios-share-canonical-url", flag_descriptions::kShareCanonicalURLName,
      flag_descriptions::kShareCanonicalURLDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(activity_services::kShareCanonicalURL)},
+    {"memex-tab-switcher", flag_descriptions::kMemexTabSwitcherName,
+     flag_descriptions::kMemexTabSwitcherDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kMemexTabSwitcher)},
     {"new-fullscreen-controller", flag_descriptions::kNewFullscreenName,
      flag_descriptions::kNewFullscreenDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(fullscreen::features::kNewFullscreen)},
diff --git a/ios/chrome/browser/download/BUILD.gn b/ios/chrome/browser/download/BUILD.gn
index 9617cf43..3892907 100644
--- a/ios/chrome/browser/download/BUILD.gn
+++ b/ios/chrome/browser/download/BUILD.gn
@@ -10,6 +10,9 @@
     "browser_download_service_factory.mm",
     "download_directory_util.cc",
     "download_directory_util.h",
+    "download_manager_tab_helper.h",
+    "download_manager_tab_helper.mm",
+    "download_manager_tab_helper_delegate.h",
     "pass_kit_mime_type.cc",
     "pass_kit_mime_type.h",
     "pass_kit_tab_helper.h",
@@ -38,6 +41,7 @@
     "browser_download_service_factory_unittest.mm",
     "browser_download_service_unittest.mm",
     "download_directory_util_unittest.mm",
+    "download_manager_tab_helper_unittest.mm",
     "pass_kit_tab_helper_unittest.mm",
   ]
   deps = [
diff --git a/ios/chrome/browser/download/download_manager_tab_helper.h b/ios/chrome/browser/download/download_manager_tab_helper.h
new file mode 100644
index 0000000..a313539
--- /dev/null
+++ b/ios/chrome/browser/download/download_manager_tab_helper.h
@@ -0,0 +1,58 @@
+// 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_DOWNLOAD_DOWNLOAD_MANAGER_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_TAB_HELPER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ios/web/public/download/download_task_observer.h"
+#import "ios/web/public/web_state/web_state_observer.h"
+#import "ios/web/public/web_state/web_state_user_data.h"
+
+@protocol DownloadManagerTabHelperDelegate;
+namespace web {
+class DownloadTask;
+class WebState;
+}  // namespace web
+
+// TabHelper which manages a single file download.
+class DownloadManagerTabHelper
+    : public web::WebStateUserData<DownloadManagerTabHelper>,
+      public web::WebStateObserver,
+      public web::DownloadTaskObserver {
+ public:
+  ~DownloadManagerTabHelper() override;
+
+  // Creates TabHelper. |delegate| is not retained by TabHelper. |web_state|
+  // must not be null.
+  static void CreateForWebState(web::WebState* web_state,
+                                id<DownloadManagerTabHelperDelegate> delegate);
+
+  // Asynchronously downloads a file using the given |task|.
+  virtual void Download(std::unique_ptr<web::DownloadTask> task);
+
+ protected:
+  // Allow subclassing from DownloadManagerTabHelper for testing purposes.
+  DownloadManagerTabHelper(web::WebState* web_state,
+                           id<DownloadManagerTabHelperDelegate> delegate);
+
+ private:
+  // web::WebStateObserver overrides:
+  void WasShown(web::WebState* web_state) override;
+  void WasHidden(web::WebState* web_state) override;
+  void WebStateDestroyed(web::WebState* web_state) override;
+
+  // web::DownloadTaskObserver overrides:
+  void OnDownloadUpdated(web::DownloadTask* task) override;
+
+  web::WebState* web_state_ = nullptr;
+  __weak id<DownloadManagerTabHelperDelegate> delegate_ = nil;
+  std::unique_ptr<web::DownloadTask> task_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadManagerTabHelper);
+};
+
+#endif  // IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_TAB_HELPER_H_
diff --git a/ios/chrome/browser/download/download_manager_tab_helper.mm b/ios/chrome/browser/download/download_manager_tab_helper.mm
new file mode 100644
index 0000000..f2583aa5
--- /dev/null
+++ b/ios/chrome/browser/download/download_manager_tab_helper.mm
@@ -0,0 +1,83 @@
+// 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/download/download_manager_tab_helper.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#import "ios/chrome/browser/download/download_manager_tab_helper_delegate.h"
+#import "ios/web/public/download/download_task.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+DEFINE_WEB_STATE_USER_DATA_KEY(DownloadManagerTabHelper);
+
+DownloadManagerTabHelper::DownloadManagerTabHelper(
+    web::WebState* web_state,
+    id<DownloadManagerTabHelperDelegate> delegate)
+    : web_state_(web_state), delegate_(delegate) {
+  DCHECK(web_state_);
+  web_state_->AddObserver(this);
+}
+
+DownloadManagerTabHelper::~DownloadManagerTabHelper() {
+  DCHECK(!task_);
+}
+
+void DownloadManagerTabHelper::CreateForWebState(
+    web::WebState* web_state,
+    id<DownloadManagerTabHelperDelegate> delegate) {
+  DCHECK(web_state);
+  if (!FromWebState(web_state)) {
+    web_state->SetUserData(
+        UserDataKey(),
+        base::WrapUnique(new DownloadManagerTabHelper(web_state, delegate)));
+  }
+}
+
+void DownloadManagerTabHelper::Download(
+    std::unique_ptr<web::DownloadTask> task) {
+  task_ = std::move(task);
+  task_->AddObserver(this);
+  [delegate_ downloadManagerTabHelper:this didCreateDownload:task_.get()];
+}
+
+void DownloadManagerTabHelper::WasShown(web::WebState* web_state) {
+  if (task_) {
+    [delegate_ downloadManagerTabHelper:this didShowDownload:task_.get()];
+  }
+}
+
+void DownloadManagerTabHelper::WasHidden(web::WebState* web_state) {
+  if (task_) {
+    [delegate_ downloadManagerTabHelper:this didHideDownload:task_.get()];
+  }
+}
+
+void DownloadManagerTabHelper::WebStateDestroyed(web::WebState* web_state) {
+  web_state->RemoveObserver(this);
+  if (task_) {
+    task_->RemoveObserver(this);
+    task_ = nullptr;
+  }
+}
+
+void DownloadManagerTabHelper::OnDownloadUpdated(web::DownloadTask* task) {
+  DCHECK_EQ(task, task_.get());
+  switch (task->GetState()) {
+    case web::DownloadTask::State::kCancelled:
+      task_->RemoveObserver(this);
+      task_ = nullptr;
+      break;
+    case web::DownloadTask::State::kInProgress:
+    case web::DownloadTask::State::kComplete:
+      [delegate_ downloadManagerTabHelper:this didUpdateDownload:task_.get()];
+      break;
+    case web::DownloadTask::State::kNotStarted:
+      // OnDownloadUpdated cannot be called with this state.
+      NOTREACHED();
+  }
+}
diff --git a/ios/chrome/browser/download/download_manager_tab_helper_delegate.h b/ios/chrome/browser/download/download_manager_tab_helper_delegate.h
new file mode 100644
index 0000000..22a3910
--- /dev/null
+++ b/ios/chrome/browser/download/download_manager_tab_helper_delegate.h
@@ -0,0 +1,37 @@
+// 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_DOWNLOAD_DOWNLOAD_MANAGER_TAB_HELPER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_TAB_HELPER_DELEGATE_H_
+
+#import <Foundation/Foundation.h>
+
+class DownloadManagerTabHelper;
+namespace web {
+class DownloadTask;
+}  // namespace web
+
+// Delegate for DownloadManagerTabHelper class.
+@protocol DownloadManagerTabHelperDelegate<NSObject>
+
+// Informs the delegate that a DownloadTask was created.
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+               didCreateDownload:(nonnull web::DownloadTask*)download;
+
+// Informs the delegate that a DownloadTask was updated (download progress was
+// changed, or download has reached a terminal state).
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+               didUpdateDownload:(nonnull web::DownloadTask*)download;
+
+// Informs the delegate that WebState related to this download was hidden.
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+                 didHideDownload:(nonnull web::DownloadTask*)download;
+
+// Informs the delegate that WebState related to this download was shown.
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+                 didShowDownload:(nonnull web::DownloadTask*)download;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_TAB_HELPER_DELEGATE_H_
diff --git a/ios/chrome/browser/download/download_manager_tab_helper_unittest.mm b/ios/chrome/browser/download/download_manager_tab_helper_unittest.mm
new file mode 100644
index 0000000..2b85ccb4
--- /dev/null
+++ b/ios/chrome/browser/download/download_manager_tab_helper_unittest.mm
@@ -0,0 +1,76 @@
+// 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/download/download_manager_tab_helper.h"
+
+#import "ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.h"
+#import "ios/web/public/test/fakes/fake_download_task.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+char kUrl[] = "https://test.test/";
+const char kMimeType[] = "";
+}
+
+// Test fixture for testing DownloadManagerTabHelper class.
+class DownloadManagerTabHelperTest : public PlatformTest {
+ protected:
+  DownloadManagerTabHelperTest()
+      : delegate_([[FakeDownloadManagerTabHelperDelegate alloc] init]) {
+    DownloadManagerTabHelper::CreateForWebState(&web_state_, delegate_);
+  }
+
+  DownloadManagerTabHelper* tab_helper() {
+    return DownloadManagerTabHelper::FromWebState(&web_state_);
+  }
+
+  web::TestWebState web_state_;
+  FakeDownloadManagerTabHelperDelegate* delegate_;
+};
+
+// Tests that created download has NotStarted state.
+TEST_F(DownloadManagerTabHelperTest, DownloadCreation) {
+  ASSERT_FALSE(delegate_.state);
+  auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kMimeType);
+
+  tab_helper()->Download(std::move(task));
+
+  ASSERT_TRUE(delegate_.state);
+  EXPECT_EQ(web::DownloadTask::State::kNotStarted, *delegate_.state);
+}
+
+// Tests that "done" download has Complete state.
+TEST_F(DownloadManagerTabHelperTest, DownloadUpdate) {
+  ASSERT_FALSE(delegate_.state);
+  auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kMimeType);
+
+  web::FakeDownloadTask* task_ptr = task.get();
+  tab_helper()->Download(std::move(task));
+  task_ptr->SetDone(true);
+
+  ASSERT_TRUE(delegate_.state);
+  EXPECT_EQ(web::DownloadTask::State::kComplete, *delegate_.state);
+}
+
+// Tests hiding and showing WebState.
+TEST_F(DownloadManagerTabHelperTest, HideAndShowWebState) {
+  ASSERT_FALSE(delegate_.state);
+  auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kMimeType);
+  tab_helper()->Download(std::move(task));
+  ASSERT_TRUE(delegate_.state);
+  EXPECT_EQ(web::DownloadTask::State::kNotStarted, *delegate_.state);
+
+  web_state_.WasHidden();
+  EXPECT_FALSE(delegate_.state);
+
+  web_state_.WasShown();
+  ASSERT_TRUE(delegate_.state);
+  EXPECT_EQ(web::DownloadTask::State::kNotStarted, *delegate_.state);
+}
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index fbe0c52..6a4bc64d 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -69,6 +69,12 @@
 const char kMarkHttpAsName[] = "Mark non-secure origins as non-secure";
 const char kMarkHttpAsDescription[] = "Change the UI treatment for HTTP pages";
 
+const char kMemexTabSwitcherName[] = "Enable the Memex prototype Tab Switcher.";
+const char kMemexTabSwitcherDescription[] =
+    "When enabled, the TabSwitcher button will navigate to the chrome memex "
+    "prototype site instead of triggering the native Tab Switcher. The native "
+    "TabSwitcher is accessible by long pressing the button";
+
 const char kNewFullscreenName[] = "Enable the new FullscreenController.";
 const char kNewFullscreenDescription[] =
     "When enabled, the new implementation of FullscreenController will be used "
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 9c1a6fb25..e294af3 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -63,6 +63,10 @@
 extern const char kMarkHttpAsName[];
 extern const char kMarkHttpAsDescription[];
 
+// Title and description for the flag to enable the Memex Tab Switcher.
+extern const char kMemexTabSwitcherName[];
+extern const char kMemexTabSwitcherDescription[];
+
 // Title and description for the flag to enable the new fullscreen
 // implementation.
 extern const char kNewFullscreenName[];
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
index e291474..2389358 100644
--- a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
+++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
@@ -103,7 +103,7 @@
     options_mask &= ~SSLErrorUI::SOFT_OVERRIDE_ENABLED;
 
   ssl_error_ui_.reset(new SSLErrorUI(request_url, cert_error, ssl_info,
-                                     options_mask, time_triggered,
+                                     options_mask, time_triggered, GURL(),
                                      controller_.get()));
 
   // Creating an interstitial without showing (e.g. from chrome://interstitials)
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index 91ff1039..14bcc980cb 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -56,7 +56,7 @@
 // TODO(crbug.com/616929): Move common matchers that are useful across tests
 // into a shared location.
 
-// Matcher for bookmarks tool tip star.
+// Matcher for bookmarks tool tip star. (used in iPad)
 id<GREYMatcher> StarButton() {
   return ButtonWithAccessibilityLabelId(IDS_TOOLTIP_STAR);
 }
@@ -152,6 +152,8 @@
 
 #pragma mark Tests
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Verifies that adding a bookmark and removing a bookmark via the UI properly
 // updates the BookmarkModel.
 - (void)testAddRemoveBookmark {
@@ -215,6 +217,9 @@
   [chrome_test_util::BrowserCommandDispatcherForMainBVC() closeCurrentTab];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testOpenSingleBookmarkInNormalAndIncognitoTab)
 // Tests that tapping a bookmark on the NTP navigates to the proper URL.
 - (void)testTapBookmark {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -245,6 +250,8 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Test to set bookmarks in multiple tabs.
 - (void)testBookmarkMultipleTabs {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -262,6 +269,9 @@
   [BookmarksTestCase assertBookmarksWithTitle:@"my bookmark" expectedCount:1];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testOpenSingleBookmarkInNormalAndIncognitoTab.)
 // Try navigating to the bookmark screen, and selecting a bookmark.
 - (void)testSelectBookmark {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -284,6 +294,10 @@
       assertWithMatcher:chrome_test_util::OmniboxText(secondURL.GetContent())];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testDeleteSingleURLNode, testDeleteSingleFolderNode, testDeleteMultipleNodes,
+// testUndoDeleteBookmarkFromSwipe)
 // Try deleting a bookmark, then undoing that delete.
 - (void)testUndoDeleteBookmark {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -312,6 +326,8 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Try deleting a bookmark from the edit screen, then undoing that delete.
 - (void)testUndoDeleteBookmarkFromEditScreen {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -352,6 +368,12 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testMoveFunctionalityOnSingleFolder, testMoveFunctionalityOnMultipleFolder,
+// testMoveFunctionalityOnMultipleUrlSelection,
+// testMoveFunctionalityOnMixedSelection,
+// testMoveCancelledWhenAllSelectionDeleted)
 // Try moving bookmarks, then undoing that move.
 - (void)testUndoMoveBookmark {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -408,6 +430,9 @@
   [BookmarksTestCase assertChildCount:1 ofFolderWithName:@"Folder 2"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, the checking of folder label after moving in edit
+// page has already been done in function tapOnContextMenuButton)
 - (void)testLabelUpdatedUponMove {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(kBookmarkNewGeneration);
@@ -443,6 +468,8 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Test the creation of a bookmark and new folder.
 - (void)testAddBookmarkInNewFolder {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -496,6 +523,9 @@
   [BookmarksTestCase assertFolderExists:@"New Folder"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testEditFunctionalityOnSingleFolder)
 // Tests that changing a folder's title in edit mode works as expected.
 - (void)testChangeFolderTitle {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -524,6 +554,8 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that the default folder bookmarks are saved in is updated to the last
 // used folder.
 - (void)testStickyDefaultFolder {
@@ -602,7 +634,9 @@
   [BookmarksTestCase assertChildCount:2 ofFolderWithName:@"Sticky Folder"];
 }
 
-// Tests that changes to the parent folder from the Single Bookmark Controller
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
+// Tests that changes to the parent folder from the Single Bookmark Editor
 // are saved to the bookmark only when saving the results.
 - (void)testMoveDoesSaveOnSave {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -655,6 +689,9 @@
   [BookmarksTestCase assertChildCount:1 ofFolderWithName:@"New Folder"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testEditFunctionalityOnSingleURL)
 // Test thats editing a single bookmark correctly persists data.
 - (void)testSingleBookmarkEdit {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -691,6 +728,9 @@
                                                  name:@"n5"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testEditFunctionalityOnSingleURL)
 // Tests that cancelling editing a single bookmark correctly doesn't persist
 // data.
 - (void)testSingleBookmarkCancelEdit {
@@ -727,6 +767,9 @@
   [BookmarksTestCase assertAbsenceOfBookmarkWithURL:@"http://www.a.fr"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testLongPressOnSingleURL)
 // Tests that long pressing a bookmark selects it and gives access to editing,
 // as does the Info menu.
 - (void)testLongPressBookmark {
@@ -761,6 +804,9 @@
       performAction:grey_tap()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testEditFunctionalityOnSingleFolder)
 // Tests the editing of a folder.
 - (void)testEditFolder {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -800,6 +846,9 @@
   [BookmarksTestCase assertFolderExistsWithTitle:@"Renamed Folder"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testEditFunctionalityOnSingleFolder)
 // Tests the deletion of a folder.
 - (void)testDeleteFolder {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -815,6 +864,8 @@
   [BookmarksTestCase assertFolderDoesntExistWithTitle:@"Folder 1"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (This
+// test is no longer relevant in the new bookmarks.)
 // Navigates to a deeply nested folder, deletes it and makes sure the UI is
 // consistent.
 - (void)testDeleteCurrentSubfolder {
@@ -840,6 +891,9 @@
   [BookmarksTestCase waitForDeletionOfBookmarkWithTitle:@"Folder 3"];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, this test is already covered in
+// testWhenCurrentFolderDeletedInBackground)
 // Navigates to a deeply nested folder, delete its parent programatically.
 // Verifies that the UI is as expected.
 - (void)testDeleteParentFolder {
@@ -886,6 +940,8 @@
       assertWithMatcher:grey_sufficientlyVisible()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (This
+// test is no longer relevant in the new bookmarks.)
 // Tests that the menu button changes to a back button as expected when browsing
 // nested folders.
 - (void)testBrowseNestedFolders {
@@ -930,6 +986,8 @@
   }
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests moving a bookmark into a new folder created in the moving process.
 - (void)testCreateNewFolderWhileMovingBookmark {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1011,8 +1069,12 @@
                      ofFolderWithName:@"Title For New Folder"];
 }
 
-// Navigates to a deeply nested folder, deletes its root ancestor and checks
-// that the UI is on the top level folder.
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (In
+// BookmarksNewGenTestCase, sidebar doesn't exist.  Deletion of ancestor folder
+// is covered in testWhenCurrentFolderDeletedInBackground and
+// testCachePositionIsResetWhenNodeIsDeleted.) Navigates to a deeply nested
+// folder, deletes its root ancestor and checks that the UI is on the top level
+// folder.
 - (void)testDeleteRootFolder {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(kBookmarkNewGeneration);
@@ -1067,6 +1129,8 @@
       assertWithMatcher:grey_notVisible()];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that keyboard commands are registered when a bookmark is added with the
 // new bookmark UI as it shows only a snackbar.
 - (void)testKeyboardCommandsRegistered_AddBookmark {
@@ -1079,6 +1143,8 @@
                  @"Some keyboard commands are registered.");
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that keyboard commands are not registered when a bookmark is edited, as
 // the edit screen is presented modally.
 - (void)testKeyboardCommandsNotRegistered_EditBookmark {
@@ -1104,6 +1170,8 @@
                  @"No keyboard commands are registered.");
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that tapping No thanks on the promo make it disappear.
 - (void)testPromoNoThanksMakeItDisappear {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1134,9 +1202,11 @@
   [BookmarksTestCase verifyPromoAlreadySeen:YES];
 }
 
-// Tests the tapping on the primary button of sign-in promo view in a cold
-// state makes the sign-in sheet appear, and the promo still appears after
-// dismissing the sheet.
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
+// Tests the tapping on the primary button of sign-in promo view in a cold state
+// makes the sign-in sheet appear, and the promo still appears after dismissing
+// the sheet.
 - (void)testSignInPromoWithColdStateUsingPrimaryButton {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(kBookmarkNewGeneration);
@@ -1162,8 +1232,10 @@
       checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
 }
 
-// Tests the tapping on the primary button of sign-in promo view in a warm
-// state makes the confirmaiton sheet appear, and the promo still appears after
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
+// Tests the tapping on the primary button of sign-in promo view in a warm state
+// makes the confirmaiton sheet appear, and the promo still appears after
 // dismissing the sheet.
 - (void)testSignInPromoWithWarmStateUsingPrimaryButton {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1198,6 +1270,8 @@
       checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests the tapping on the secondary button of sign-in promo view in a warm
 // state makes the sign-in sheet appear, and the promo still appears after
 // dismissing the sheet.
@@ -1235,6 +1309,8 @@
       checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that the sign-in promo should not be shown after been shown 19 times.
 - (void)testAutomaticSigninPromoDismiss {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1267,6 +1343,8 @@
   [SigninEarlGreyUtils checkSigninPromoNotVisible];
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that all elements on the bookmarks landing page are accessible.
 - (void)testAccessibilityOnBookmarksLandingPage {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1282,6 +1360,8 @@
   }
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that all elements on the bookmarks Edit page are accessible.
 - (void)testAccessibilityOnBookmarksEditPage {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1306,6 +1386,8 @@
   }
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that all elements on the bookmarks Move page are accessible.
 - (void)testAccessibilityOnBookmarksMovePage {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1330,6 +1412,8 @@
   }
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that all elements on the bookmarks Move to New Folder page are
 // accessible.
 - (void)testAccessibilityOnBookmarksMoveToNewFolderPage {
@@ -1359,6 +1443,8 @@
   }
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that all elements on bookmarks Delete and Undo are accessible.
 - (void)testAccessibilityOnBookmarksDeleteUndo {
   base::test::ScopedFeatureList scoped_feature_list;
@@ -1381,6 +1467,8 @@
   }
 }
 
+// TODO(crbug.com/753599): Remove this test when clean up old bookmarks. (Same
+// test already exists in BookmarksNewGenTestCase)
 // Tests that all elements on the bookmarks Select page are accessible.
 - (void)testAccessibilityOnBookmarksSelect {
   base::test::ScopedFeatureList scoped_feature_list;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
index 576b37ad..49bbde2 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
@@ -12,6 +12,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/titled_url_match.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -22,6 +23,7 @@
 #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_utils_ios.h"
+#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/app/bookmarks_test_util.h"
@@ -69,6 +71,27 @@
   return web::test::HttpServer::MakeUrl("http://www.a.fr/");
 }
 
+// Matcher for bookmarks tool tip star. (used in iPad)
+id<GREYMatcher> StarButton() {
+  return ButtonWithAccessibilityLabelId(IDS_TOOLTIP_STAR);
+}
+
+// Matcher for the button to add bookmark.
+id<GREYMatcher> AddBookmarkButton() {
+  return ButtonWithAccessibilityLabelId(IDS_BOOKMARK_ADD_EDITOR_TITLE);
+}
+
+// Matcher for the lit star buttom on iPhone that will open the edit button
+// screen.
+id<GREYMatcher> LitStarButtoniPhone() {
+  return ButtonWithAccessibilityLabelId(IDS_IOS_TOOLS_MENU_EDIT_BOOKMARK);
+}
+
+// Matcher for the button to edit bookmark.
+id<GREYMatcher> EditBookmarkButton() {
+  return ButtonWithAccessibilityLabelId(IDS_IOS_BOOKMARK_ACTION_EDIT);
+}
+
 // Matcher for the Delete button on the bookmarks UI.
 id<GREYMatcher> BookmarksDeleteSwipeButton() {
   return ButtonWithAccessibilityLabelId(IDS_IOS_BOOKMARK_ACTION_DELETE);
@@ -118,6 +141,15 @@
   return grey_allOf(grey_accessibilityID(label), grey_sufficientlyVisible(),
                     nil);
 }
+
+// Matcher for the button to close the tools menu.
+id<GREYMatcher> CloseToolsMenuButton() {
+  NSString* closeMenuButtonText =
+      l10n_util::GetNSString(IDS_IOS_TOOLBAR_CLOSE_MENU);
+  return grey_allOf(grey_accessibilityID(kToolbarToolsMenuButtonIdentifier),
+                    grey_accessibilityLabel(closeMenuButtonText), nil);
+}
+
 }  // namespace
 
 // Bookmark integration tests for Chrome.
@@ -152,6 +184,413 @@
 
 #pragma mark - Tests
 
+// Verifies that adding a bookmark and removing a bookmark via the UI properly
+// updates the BookmarkModel.
+- (void)testAddRemoveBookmark {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  const GURL bookmarkedURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/pony.html");
+  std::string expectedURLContent = bookmarkedURL.GetContent();
+  NSString* bookmarkTitle = @"my bookmark";
+
+  [ChromeEarlGrey loadURL:bookmarkedURL];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
+                                          expectedURLContent)]
+      assertWithMatcher:grey_notNil()];
+
+  // Add the bookmark from the UI.
+  [BookmarksNewGenTestCase bookmarkCurrentTabWithTitle:bookmarkTitle];
+
+  // Verify the bookmark is set.
+  [BookmarksNewGenTestCase assertBookmarksWithTitle:bookmarkTitle
+                                      expectedCount:1];
+
+  NSString* const kStarLitLabel =
+      !IsCompact() ? l10n_util::GetNSString(IDS_TOOLTIP_STAR)
+                   : l10n_util::GetNSString(IDS_IOS_BOOKMARK_EDIT_SCREEN_TITLE);
+  // Verify the star is lit.
+  if (IsCompact()) {
+    [ChromeEarlGreyUI openToolsMenu];
+  }
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarLitLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // Clear the bookmark via the UI.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarLitLabel)]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:
+                 grey_allOf(grey_accessibilityLabel(l10n_util::GetNSString(
+                                IDS_IOS_BOOKMARK_ACTION_DELETE)),
+                            grey_accessibilityTrait(UIAccessibilityTraitButton),
+                            grey_not(grey_accessibilityID(@"Edit_editing_bar")),
+                            nil)] performAction:grey_tap()];
+
+  // Verify the bookmark is not in the BookmarkModel.
+  [BookmarksNewGenTestCase assertBookmarksWithTitle:bookmarkTitle
+                                      expectedCount:0];
+
+  NSString* const kStarUnlitLabel =
+      !IsCompact() ? l10n_util::GetNSString(IDS_TOOLTIP_STAR)
+                   : l10n_util::GetNSString(IDS_BOOKMARK_ADD_EDITOR_TITLE);
+
+  // Verify the star is not lit.
+  if (IsCompact()) {
+    [ChromeEarlGreyUI openToolsMenu];
+  }
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarUnlitLabel)]
+      assertWithMatcher:grey_notNil()];
+
+  // TODO(crbug.com/617652): This code should be removed when a common helper
+  // is added to close any menus, which should be run as test setup.
+  if (IsCompact()) {
+    [[EarlGrey selectElementWithMatcher:CloseToolsMenuButton()]
+        performAction:grey_tap()];
+  }
+
+  // Close the opened tab.
+  [chrome_test_util::BrowserCommandDispatcherForMainBVC() closeCurrentTab];
+}
+
+// Test to set bookmarks in multiple tabs.
+- (void)testBookmarkMultipleTabs {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  const GURL firstURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/pony.html");
+  const GURL secondURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/destination.html");
+  [ChromeEarlGrey loadURL:firstURL];
+  chrome_test_util::OpenNewTab();
+  [ChromeEarlGrey loadURL:secondURL];
+
+  [BookmarksNewGenTestCase bookmarkCurrentTabWithTitle:@"my bookmark"];
+  [BookmarksNewGenTestCase assertBookmarksWithTitle:@"my bookmark"
+                                      expectedCount:1];
+}
+
+// Test the creation of a bookmark and new folder (by tapping on the star).
+- (void)testAddBookmarkInNewFolder {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  const GURL bookmarkedURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/pony.html");
+  std::string expectedURLContent = bookmarkedURL.GetContent();
+
+  [ChromeEarlGrey loadURL:bookmarkedURL];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
+                                          expectedURLContent)]
+      assertWithMatcher:grey_notNil()];
+
+  [BookmarksNewGenTestCase starCurrentTab];
+
+  // Verify the snackbar title.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Bookmarked")]
+      assertWithMatcher:grey_notNil()];
+
+  // Tap on the snackbar.
+  NSString* snackbarLabel =
+      l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_EDIT_BUTTON);
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
+      performAction:grey_tap()];
+
+  // Verify that the newly-created bookmark is in the BookmarkModel.
+  [BookmarksNewGenTestCase
+      assertBookmarksWithTitle:base::SysUTF8ToNSString(expectedURLContent)
+                 expectedCount:1];
+
+  // Verify that the editor is present.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Single Bookmark Editor")]
+      assertWithMatcher:grey_notNil()];
+
+  [BookmarksNewGenTestCase assertFolderName:@"Mobile Bookmarks"];
+
+  // Tap the Folder button.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Change Folder")]
+      performAction:grey_tap()];
+
+  // Create a new folder with default name.
+  [BookmarksNewGenTestCase addFolderWithName:nil];
+
+  // Verify that the editor is present.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Single Bookmark Editor")]
+      assertWithMatcher:grey_notNil()];
+
+  [BookmarksNewGenTestCase assertFolderExists:@"New Folder"];
+}
+
+// Tests that the default folder bookmarks are saved in is updated to the last
+// used folder.
+- (void)testStickyDefaultFolder {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Invoke Edit through long press.
+  [[EarlGrey
+      selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"First URL")]
+      performAction:grey_longPress()];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT)]
+      performAction:grey_tap()];
+
+  // Tap the Folder button.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Change Folder")]
+      performAction:grey_tap()];
+
+  // Create a new folder.
+  [BookmarksNewGenTestCase addFolderWithName:@"Sticky Folder"];
+
+  // Verify that the editor is present.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Single Bookmark Editor")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Tap the Done button.
+  [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Single Bookmark Editor")]
+      assertWithMatcher:grey_notVisible()];
+
+  // Close bookmarks
+  [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
+      performAction:grey_tap()];
+
+  // Second, bookmark a page.
+
+  // Verify that the bookmark that is going to be added is not in the
+  // BookmarkModel.
+  const GURL bookmarkedURL = web::test::HttpServer::MakeUrl(
+      "http://ios/testing/data/http_server_files/fullscreen.html");
+  NSString* const bookmarkedURLString =
+      base::SysUTF8ToNSString(bookmarkedURL.spec());
+  [BookmarksNewGenTestCase assertBookmarksWithTitle:bookmarkedURLString
+                                      expectedCount:0];
+  // Open the page.
+  std::string expectedURLContent = bookmarkedURL.GetContent();
+  [ChromeEarlGrey loadURL:bookmarkedURL];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
+                                          expectedURLContent)]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify that the folder has only one element.
+  [BookmarksNewGenTestCase assertChildCount:1
+                           ofFolderWithName:@"Sticky Folder"];
+
+  // Bookmark the page.
+  [BookmarksNewGenTestCase starCurrentTab];
+
+  // Verify the snackbar title.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
+                                          @"Bookmarked to Sticky Folder")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Verify that the newly-created bookmark is in the BookmarkModel.
+  [BookmarksNewGenTestCase assertBookmarksWithTitle:bookmarkedURLString
+                                      expectedCount:1];
+
+  // Verify that the folder has now two elements.
+  [BookmarksNewGenTestCase assertChildCount:2
+                           ofFolderWithName:@"Sticky Folder"];
+}
+
+// Tests that changes to the parent folder from the Single Bookmark Editor
+// are saved to the bookmark only when saving the results.
+- (void)testMoveDoesSaveOnSave {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Invoke Edit through long press.
+  [[EarlGrey
+      selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"First URL")]
+      performAction:grey_longPress()];
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT)]
+      performAction:grey_tap()];
+
+  // Tap the Folder button.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Change Folder")]
+      performAction:grey_tap()];
+
+  // Create a new folder.
+  [BookmarksNewGenTestCase addFolderWithName:nil];
+
+  // Verify that the editor is present.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Single Bookmark Editor")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Check that the new folder doesn't contain the bookmark.
+  [BookmarksNewGenTestCase assertChildCount:0 ofFolderWithName:@"New Folder"];
+
+  // Tap the Done button.
+  [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Single Bookmark Editor")]
+      assertWithMatcher:grey_notVisible()];
+
+  // Check that the new folder contains the bookmark.
+  [BookmarksNewGenTestCase assertChildCount:1 ofFolderWithName:@"New Folder"];
+
+  // Close bookmarks
+  [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
+      performAction:grey_tap()];
+
+  // Check that the new folder still contains the bookmark.
+  [BookmarksNewGenTestCase assertChildCount:1 ofFolderWithName:@"New Folder"];
+}
+
+// Tests moving bookmarks into a new folder created in the moving process.
+- (void)testCreateNewFolderWhileMovingBookmarks {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select URLs.
+  [[EarlGrey
+      selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"Second URL")]
+      performAction:grey_tap()];
+  [[EarlGrey
+      selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"First URL")]
+      performAction:grey_tap()];
+
+  // Tap context menu.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarMoreString])]
+      performAction:grey_tap()];
+
+  // Tap on Move.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE)]
+      performAction:grey_tap()];
+
+  // Choose to move the bookmark into a new folder.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Create New Folder")]
+      performAction:grey_tap()];
+
+  // Enter custom new folder name.
+  [BookmarksNewGenTestCase
+      renameBookmarkFolderWithFolderTitle:@"Title For New Folder"];
+
+  // Verify current parent folder (Change Folder) is Bookmarks folder.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(
+                                   grey_accessibilityID(@"Change Folder"),
+                                   grey_accessibilityLabel(@"Mobile Bookmarks"),
+                                   nil)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Choose new parent folder (Change Folder).
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Change Folder")]
+      performAction:grey_tap()];
+
+  // Verify folder picker UI is displayed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Picker")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Verify Folder 2 only has one item.
+  [BookmarksNewGenTestCase assertChildCount:1 ofFolderWithName:@"Folder 2"];
+
+  // Select Folder 2 as new Change Folder.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder 2")]
+      performAction:grey_tap()];
+
+  // Verify folder picker is dismissed and folder creator is now visible.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Creator")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Picker")]
+      assertWithMatcher:grey_notVisible()];
+
+  // Verify picked parent folder (Change Folder) is Folder 2.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(
+                                   grey_accessibilityID(@"Change Folder"),
+                                   grey_accessibilityLabel(@"Folder 2"), nil)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Tap Done (accessibilityID is 'Save') to close bookmark move flow.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Save")]
+      performAction:grey_tap()];
+
+  // Verify all folder flow UI is now closed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Creator")]
+      assertWithMatcher:grey_notVisible()];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Picker")]
+      assertWithMatcher:grey_notVisible()];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Editor")]
+      assertWithMatcher:grey_notVisible()];
+
+  // Verify new folder has been created under Folder 2.
+  [BookmarksNewGenTestCase assertChildCount:2 ofFolderWithName:@"Folder 2"];
+
+  // Verify new folder has two bookmarks.
+  [BookmarksNewGenTestCase assertChildCount:2
+                           ofFolderWithName:@"Title For New Folder"];
+}
+
+// Tests that keyboard commands are registered when a bookmark is added with the
+// new bookmark UI as it shows only a snackbar.
+- (void)testKeyboardCommandsRegistered_AddBookmark {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  // Add the bookmark.
+  [BookmarksNewGenTestCase starCurrentTab];
+  GREYAssertTrue(chrome_test_util::GetRegisteredKeyCommandsCount() > 0,
+                 @"Some keyboard commands are registered.");
+}
+
+// Tests that keyboard commands are not registered when a bookmark is edited, as
+// the edit screen is presented modally.
+- (void)testKeyboardCommandsNotRegistered_EditBookmark {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Select single URL.
+  [[EarlGrey
+      selectElementWithMatcher:TappableBookmarkNodeWithLabel(@"Second URL")]
+      performAction:grey_tap()];
+
+  // Edit the bookmark.
+  if (!IsCompact()) {
+    [[EarlGrey selectElementWithMatcher:StarButton()] performAction:grey_tap()];
+  } else {
+    [ChromeEarlGreyUI openToolsMenu];
+    [[EarlGrey selectElementWithMatcher:LitStarButtoniPhone()]
+        performAction:grey_tap()];
+  }
+  GREYAssertTrue(chrome_test_util::GetRegisteredKeyCommandsCount() == 0,
+                 @"No keyboard commands are registered.");
+}
+
 // Test that swiping left to right navigate back.
 - (void)testNavigateBackWithGesture {
   // Disabled on iPad as there is not "navigate back" gesture.
@@ -2776,6 +3215,117 @@
   [BookmarksNewGenTestCase openBookmarkFolder:@"Mobile Bookmarks"];
 }
 
+// Asserts that |expectedCount| bookmarks exist with the corresponding |title|
+// using the BookmarkModel.
++ (void)assertBookmarksWithTitle:(NSString*)title
+                   expectedCount:(NSUInteger)expectedCount {
+  // Get BookmarkModel and wait for it to be loaded.
+  bookmarks::BookmarkModel* bookmarkModel =
+      ios::BookmarkModelFactory::GetForBrowserState(
+          chrome_test_util::GetOriginalBrowserState());
+
+  // Verify the correct number of bookmarks exist.
+  base::string16 matchString = base::SysNSStringToUTF16(title);
+  std::vector<bookmarks::TitledUrlMatch> matches;
+  bookmarkModel->GetBookmarksMatching(matchString, 50, &matches);
+  const size_t count = matches.size();
+  GREYAssertEqual(expectedCount, count, @"Unexpected number of bookmarks");
+}
+
+// Tap on the star to bookmark a page, then edit the bookmark to change the
+// title to |title|.
++ (void)bookmarkCurrentTabWithTitle:(NSString*)title {
+  [BookmarksNewGenTestCase waitForBookmarkModelLoaded:YES];
+  // Add the bookmark from the UI.
+  [BookmarksNewGenTestCase starCurrentTab];
+
+  // Set the bookmark name.
+  [[EarlGrey selectElementWithMatcher:EditBookmarkButton()]
+      performAction:grey_tap()];
+  NSString* titleIdentifier = @"Title Field_textField";
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(titleIdentifier)]
+      performAction:grey_replaceText(title)];
+
+  // Dismiss the window.
+  [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
+      performAction:grey_tap()];
+}
+
+// Adds a bookmark for the current tab. Must be called when on a tab.
++ (void)starCurrentTab {
+  if (!IsCompact()) {
+    [[EarlGrey selectElementWithMatcher:StarButton()] performAction:grey_tap()];
+  } else {
+    [ChromeEarlGreyUI openToolsMenu];
+    [[EarlGrey selectElementWithMatcher:AddBookmarkButton()]
+        performAction:grey_tap()];
+  }
+}
+
+// Check that the currently edited bookmark is in |folderName| folder.
++ (void)assertFolderName:(NSString*)folderName {
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(
+                                   grey_accessibilityID(@"Change Folder"),
+                                   grey_accessibilityLabel(folderName), nil)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Creates a new folder starting from the folder picker.
+// Passing a |name| of 0 length will use the default value.
++ (void)addFolderWithName:(NSString*)name {
+  // Wait for folder picker to appear.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Picker")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Tap on "Create New Folder."
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"Create New Folder")]
+      performAction:grey_tap()];
+
+  // Verify the folder creator is displayed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Creator")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Change the name of the folder.
+  if (name.length > 0) {
+    [[EarlGrey
+        selectElementWithMatcher:grey_accessibilityID(@"Title_textField")]
+        performAction:grey_replaceText(name)];
+  }
+
+  // Tap the Save button.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Save")]
+      performAction:grey_tap()];
+}
+
+// Asserts that a folder called |title| exists.
++ (void)assertFolderExists:(NSString*)title {
+  base::string16 folderTitle16(base::SysNSStringToUTF16(title));
+  bookmarks::BookmarkModel* bookmark_model =
+      ios::BookmarkModelFactory::GetForBrowserState(
+          chrome_test_util::GetOriginalBrowserState());
+
+  ui::TreeNodeIterator<const bookmarks::BookmarkNode> iterator(
+      bookmark_model->root_node());
+  BOOL folderExists = NO;
+
+  while (iterator.has_next()) {
+    const bookmarks::BookmarkNode* bookmark = iterator.Next();
+    if (bookmark->is_url())
+      continue;
+    // This is a folder.
+    if (bookmark->GetTitle() == folderTitle16) {
+      folderExists = YES;
+      break;
+    }
+  }
+
+  NSString* assertMessage =
+      [NSString stringWithFormat:@"Folder %@ doesn't exist", title];
+  GREYAssert(folderExists, assertMessage);
+}
+
 // Checks that the promo has already been seen or not.
 + (void)verifyPromoAlreadySeen:(BOOL)seen {
   ios::ChromeBrowserState* browserState =
diff --git a/ios/chrome/browser/ui/commands/toolbar_commands.h b/ios/chrome/browser/ui/commands/toolbar_commands.h
index 754390dd..becd471d 100644
--- a/ios/chrome/browser/ui/commands/toolbar_commands.h
+++ b/ios/chrome/browser/ui/commands/toolbar_commands.h
@@ -9,8 +9,13 @@
 @protocol ToolbarCommands
 // Contracts the Toolbar to its regular form.
 - (void)contractToolbar;
+
 // Triggers the animation of the tools menu button.
 - (void)triggerToolsMenuButtonAnimation;
+
+// Navigates to the Memex tab switcher.
+// TODO(crbug.com/799601): Delete this once its not needed.
+- (void)navigateToMemexTabSwitcher;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_TOOLBAR_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
index 6cecee4..be8749cd 100644
--- a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
@@ -76,6 +76,7 @@
     "//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui",
     "//ios/chrome/browser/ui/history_popup/requirements",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/common",
@@ -114,6 +115,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/toolbar:resource_macros",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/images",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.mm
index d73ad98..257c7eb 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h"
 
+#include "base/ios/ios_util.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
@@ -14,6 +15,7 @@
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_configuration.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_tools_menu_button.h"
+#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #include "ios/chrome/browser/ui/toolbar/toolbar_resource_macros.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -138,9 +140,17 @@
       setTitleColor:[self.toolbarConfiguration buttonTitleHighlightedColor]
            forState:UIControlStateHighlighted];
   [self configureButton:tabSwitcherStripButton width:kToolbarButtonWidth];
-  [tabSwitcherStripButton addTarget:self.dispatcher
-                             action:@selector(displayTabSwitcher)
-                   forControlEvents:UIControlEventTouchUpInside];
+
+  // TODO(crbug.com/799601): Delete this once its not needed.
+  if (base::FeatureList::IsEnabled(kMemexTabSwitcher)) {
+    [tabSwitcherStripButton addTarget:self.dispatcher
+                               action:@selector(navigateToMemexTabSwitcher)
+                     forControlEvents:UIControlEventTouchUpInside];
+  } else {
+    [tabSwitcherStripButton addTarget:self.dispatcher
+                               action:@selector(displayTabSwitcher)
+                     forControlEvents:UIControlEventTouchUpInside];
+  }
 
   tabSwitcherStripButton.visibilityMask =
       self.visibilityConfiguration.tabGridButtonVisibility;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
index 1a3aba1..4d167af 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
@@ -89,6 +89,9 @@
 - (void)activateFakeSafeAreaInsets:(UIEdgeInsets)fakeSafeAreaInsets;
 // Deactivates the constraints used to create a fake safe area.
 - (void)deactivateFakeSafeAreaInsets;
+// Navigates to the Memex tab switcher.
+// TODO(crbug.com/799601): Delete this once its not needed.
+- (void)navigateToMemexTabSwitcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index 75cdfd6e..12fd377f 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -287,6 +287,11 @@
   [self.toolbarViewController deactivateFakeSafeAreaInsets];
 }
 
+- (void)navigateToMemexTabSwitcher {
+  const GURL memexURL("https://chrome-memex.appspot.com");
+  [self loadGURLFromLocationBar:memexURL transition:ui::PAGE_TRANSITION_LINK];
+}
+
 // TODO(crbug.com/786940): This protocol should move to the ViewController
 // owning the Toolbar. This can wait until the omnibox and toolbar refactoring
 // is more advanced.
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
index 2b705376..13f91d75 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h"
 
+#include "base/ios/ios_util.h"
 #import "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
@@ -21,6 +22,7 @@
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_tools_menu_button.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_view.h"
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
+#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_constants.h"
 #import "ios/chrome/browser/ui/toolbar/public/web_toolbar_controller_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -329,6 +331,15 @@
   // TabSwitcher button.
   [self addStandardActionsForButton:self.view.tabSwitchStripButton];
 
+  // TODO(crbug.com/799601): Delete this once its not needed.
+  if (base::FeatureList::IsEnabled(kMemexTabSwitcher)) {
+    UILongPressGestureRecognizer* tabSwitcherLongPress =
+        [[UILongPressGestureRecognizer alloc]
+            initWithTarget:self
+                    action:@selector(handleLongPress:)];
+    [self.view.tabSwitchStripButton addGestureRecognizer:tabSwitcherLongPress];
+  }
+
   // Tools menu button.
   [self addStandardActionsForButton:self.view.toolsMenuButton];
 
@@ -373,6 +384,9 @@
     [self.dispatcher showTabHistoryPopupForBackwardHistory];
   } else if (gesture.view == self.view.forwardButton) {
     [self.dispatcher showTabHistoryPopupForForwardHistory];
+  } else if (gesture.view == self.view.tabSwitchStripButton) {
+    // TODO(crbug.com/799601): Delete this once its not needed.
+    [self.dispatcher displayTabSwitcher];
   }
 }
 
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
index 312cefd4..2b6e3ec 100644
--- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
@@ -296,6 +296,10 @@
   [self cancelOmniboxEdit];
 }
 
+- (void)navigateToMemexTabSwitcher {
+  [self.toolbarController navigateToMemexTabSwitcher];
+}
+
 #pragma mark - Fullscreen helpers
 
 // Creates a FullscreenUIUpdater for the toolbar controller and adds it as a
diff --git a/ios/chrome/browser/ui/toolbar/public/abstract_web_toolbar.h b/ios/chrome/browser/ui/toolbar/public/abstract_web_toolbar.h
index 6826ce7..c612233 100644
--- a/ios/chrome/browser/ui/toolbar/public/abstract_web_toolbar.h
+++ b/ios/chrome/browser/ui/toolbar/public/abstract_web_toolbar.h
@@ -37,6 +37,9 @@
 - (void)updateToolbarForSideSwipeSnapshot:(Tab*)tab;
 // Remove any formatting added by -updateToolbarForSideSwipeSnapshot.
 - (void)resetToolbarAfterSideSwipeSnapshot;
+// Navigates to the Memex tab switcher.
+// TODO(crbug.com/799601): Delete this once its not needed.
+- (void)navigateToMemexTabSwitcher;
 // WebToolbarDelegate delegate.
 @property(nonatomic, weak) id<WebToolbarDelegate> delegate;
 // Convenience getter for the UIViewController.
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
index c6598f5b..d03b005 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h
@@ -15,4 +15,8 @@
 // toolbar.
 extern const base::Feature kAdaptiveToolbar;
 
+// Feature to choose whether to use the memex prototype tab switcher or the
+// regular native tab switcher.
+extern const base::Feature kMemexTabSwitcher;
+
 #endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_CONTROLLER_BASE_FEATURE_H_
diff --git a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
index 97a06b6..ff24873 100644
--- a/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
+++ b/ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.mm
@@ -13,3 +13,6 @@
 
 const base::Feature kAdaptiveToolbar{"AdaptiveToolbar",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kMemexTabSwitcher{"MemexTabSwitcher",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
index b2cfdbfc..4937209 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
@@ -93,6 +93,10 @@
   [self.toolbarCoordinator resetToolbarAfterSideSwipeSnapshot];
 }
 
+- (void)navigateToMemexTabSwitcher {
+  [self.toolbarCoordinator navigateToMemexTabSwitcher];
+}
+
 #pragma mark - Abstract Toolbar
 
 - (void)setShareButtonEnabled:(BOOL)enabled {
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index a5416262f5..66aad3a 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -1916,6 +1916,10 @@
   [self.dispatcher preloadVoiceSearch];
 }
 
+- (void)navigateToMemexTabSwitcher {
+  // no-op since WTC won't support the memex Tab Switcher.
+}
+
 #pragma mark - UIViewController
 
 - (void)viewSafeAreaInsetsDidChange {
diff --git a/ios/chrome/test/fakes/BUILD.gn b/ios/chrome/test/fakes/BUILD.gn
index befab567..a849777 100644
--- a/ios/chrome/test/fakes/BUILD.gn
+++ b/ios/chrome/test/fakes/BUILD.gn
@@ -7,6 +7,8 @@
   testonly = true
 
   sources = [
+    "fake_download_manager_tab_helper_delegate.h",
+    "fake_download_manager_tab_helper_delegate.mm",
     "fake_pass_kit_tab_helper_delegate.h",
     "fake_pass_kit_tab_helper_delegate.mm",
   ]
@@ -14,6 +16,7 @@
   deps = [
     "//ios/chrome/browser/download",
     "//ios/web/public",
+    "//ios/web/public/download",
   ]
 
   libs = [ "Foundation.framework" ]
diff --git a/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.h b/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.h
new file mode 100644
index 0000000..d8936c9a
--- /dev/null
+++ b/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.h
@@ -0,0 +1,21 @@
+// 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_TEST_FAKES_FAKE_DOWNLOAD_MANAGER_TAB_HELPER_DELEGATE_H_
+#define IOS_CHROME_TEST_FAKES_FAKE_DOWNLOAD_MANAGER_TAB_HELPER_DELEGATE_H_
+
+#import "ios/chrome/browser/download/download_manager_tab_helper_delegate.h"
+#import "ios/web/public/download/download_task.h"
+
+// DownloadManagerTabHelperDelegate which stores the state of download task.
+@interface FakeDownloadManagerTabHelperDelegate
+    : NSObject<DownloadManagerTabHelperDelegate>
+
+// The state of current download task. null if there is no current download task
+// or when DownloadManager's WebState was hidden.
+@property(nonatomic, readonly) web::DownloadTask::State* state;
+
+@end
+
+#endif  // IOS_CHROME_TEST_FAKES_FAKE_DOWNLOAD_MANAGER_TAB_HELPER_DELEGATE_H_
diff --git a/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm b/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm
new file mode 100644
index 0000000..da919033
--- /dev/null
+++ b/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm
@@ -0,0 +1,39 @@
+// 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/test/fakes/fake_download_manager_tab_helper_delegate.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation FakeDownloadManagerTabHelperDelegate {
+  std::unique_ptr<web::DownloadTask::State> _state;
+}
+
+- (web::DownloadTask::State*)state {
+  return _state.get();
+}
+
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+               didCreateDownload:(nonnull web::DownloadTask*)download {
+  _state = std::make_unique<web::DownloadTask::State>(download->GetState());
+}
+
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+               didUpdateDownload:(nonnull web::DownloadTask*)download {
+  _state = std::make_unique<web::DownloadTask::State>(download->GetState());
+}
+
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+                 didHideDownload:(nonnull web::DownloadTask*)download {
+  _state = nullptr;
+}
+
+- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper
+                 didShowDownload:(nonnull web::DownloadTask*)download {
+  _state = std::make_unique<web::DownloadTask::State>(download->GetState());
+}
+
+@end
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc
index 146feb0..d5d9678 100644
--- a/ipc/ipc_sync_channel.cc
+++ b/ipc/ipc_sync_channel.cc
@@ -206,9 +206,10 @@
         }
         for (; it != message_queue_.end(); it++) {
           int message_group = it->context->restrict_dispatch_group();
-          if (!dispatching_context ||
-              message_group == kRestrictDispatchGroup_None ||
-              message_group == dispatching_context->restrict_dispatch_group()) {
+          if (message_group == kRestrictDispatchGroup_None ||
+              (dispatching_context &&
+               message_group ==
+                   dispatching_context->restrict_dispatch_group())) {
             message = it->message;
             context = it->context;
             it = message_queue_.erase(it);
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc
index 27e55f618..5550542 100644
--- a/media/cdm/cdm_adapter.cc
+++ b/media/cdm/cdm_adapter.cc
@@ -1201,11 +1201,21 @@
   init_promise_id_ = CdmPromiseAdapter::kInvalidPromiseId;
 }
 
-cdm::CdmProxy* CdmAdapter::CreateCdmProxy() {
+cdm::CdmProxy* CdmAdapter::CreateCdmProxy(cdm::CdmProxyClient* client) {
   DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  return helper_->CreateCdmProxy();
+  // CdmProxy should only be created once, at CDM initialization time.
+  if (cdm_proxy_created_ ||
+      init_promise_id_ == CdmPromiseAdapter::kInvalidPromiseId) {
+    DVLOG(1) << __func__
+             << ": CdmProxy can only be created once, and must be created "
+                "during CDM initialization.";
+    return nullptr;
+  }
+
+  cdm_proxy_created_ = true;
+  return helper_->CreateCdmProxy(client);
 }
 
 void CdmAdapter::OnStorageIdObtained(uint32_t version,
diff --git a/media/cdm/cdm_adapter.h b/media/cdm/cdm_adapter.h
index 2cde314..978c5b6c 100644
--- a/media/cdm/cdm_adapter.h
+++ b/media/cdm/cdm_adapter.h
@@ -149,7 +149,7 @@
 
   // cdm::Host_10 specific implementation.
   void OnInitialized(bool success) override;
-  cdm::CdmProxy* CreateCdmProxy() override;
+  cdm::CdmProxy* CreateCdmProxy(cdm::CdmProxyClient* client) override;
 
   // cdm::Host_8 specific implementation.
   void OnRejectPromise(uint32_t promise_id,
@@ -265,6 +265,8 @@
   int last_read_file_size_kb_ = 0;
   bool file_size_uma_reported_ = false;
 
+  bool cdm_proxy_created_ = false;
+
   // Used to keep track of promises while the CDM is processing the request.
   CdmPromiseAdapter cdm_promise_adapter_;
 
diff --git a/media/cdm/cdm_auxiliary_helper.cc b/media/cdm/cdm_auxiliary_helper.cc
index bd65b64..23f2109 100644
--- a/media/cdm/cdm_auxiliary_helper.cc
+++ b/media/cdm/cdm_auxiliary_helper.cc
@@ -17,7 +17,7 @@
   return nullptr;
 }
 
-cdm::CdmProxy* CdmAuxiliaryHelper::CreateCdmProxy() {
+cdm::CdmProxy* CdmAuxiliaryHelper::CreateCdmProxy(cdm::CdmProxyClient* client) {
   return nullptr;
 }
 
diff --git a/media/cdm/cdm_auxiliary_helper.h b/media/cdm/cdm_auxiliary_helper.h
index 60f304b..a3bfb1a06 100644
--- a/media/cdm/cdm_auxiliary_helper.h
+++ b/media/cdm/cdm_auxiliary_helper.h
@@ -21,6 +21,7 @@
 class FileIO;
 class FileIOClient;
 class CdmProxy;
+class CdmProxyClient;
 }  // namespace cdm
 
 namespace media {
@@ -50,7 +51,7 @@
   // The caller does not own the returned object and should not delete it
   // directly. Instead, it should call cdm::CdmProxy::Destroy() after it's not
   // needed anymore.
-  virtual cdm::CdmProxy* CreateCdmProxy();
+  virtual cdm::CdmProxy* CreateCdmProxy(cdm::CdmProxyClient* client);
 
   // CdmAllocator implementation.
   cdm::Buffer* CreateCdmBuffer(size_t capacity) override;
diff --git a/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy.h b/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy.h
index 22ca6bb..65eca0d 100644
--- a/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy.h
+++ b/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy.h
@@ -54,7 +54,7 @@
   virtual void OnDeferredInitializationDone(cdm::StreamType stream_type,
                                             cdm::Status decoder_status) = 0;
   virtual cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) = 0;
-  virtual cdm::CdmProxy* CreateCdmProxy() = 0;
+  virtual cdm::CdmProxy* CreateCdmProxy(cdm::CdmProxyClient* client) = 0;
   virtual void RequestStorageId(uint32_t version) = 0;
 };
 
diff --git a/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy_impl.h b/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy_impl.h
index 363c696..97a1b8b5 100644
--- a/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy_impl.h
+++ b/media/cdm/ppapi/clear_key_cdm/cdm_host_proxy_impl.h
@@ -110,7 +110,9 @@
     return host_->CreateFileIO(client);
   }
 
-  cdm::CdmProxy* CreateCdmProxy() final { return host_->CreateCdmProxy(); }
+  cdm::CdmProxy* CreateCdmProxy(cdm::CdmProxyClient* client) final {
+    return host_->CreateCdmProxy(client);
+  }
 
   void RequestStorageId(uint32_t version) final {
     host_->RequestStorageId(version);
@@ -125,12 +127,13 @@
 // Specialization for cdm::Host_9 methods.
 
 template <>
-void CdmHostProxyImpl<cdm::Host_9>::OnInitialized(bool success) {
+void CdmHostProxyImpl<cdm::Host_9>::OnInitialized(bool /* success */) {
   // OnInitialized() doesn't exist on Host_9.
 }
 
 template <>
-cdm::CdmProxy* CdmHostProxyImpl<cdm::Host_9>::CreateCdmProxy() {
+cdm::CdmProxy* CdmHostProxyImpl<cdm::Host_9>::CreateCdmProxy(
+    cdm::CdmProxyClient* /* client */) {
   NOTREACHED() << "cdm::ContentDecryptionModule_9 CDM should never call this.";
   return nullptr;
 }
diff --git a/media/cdm/ppapi/clear_key_cdm/cdm_proxy_test.cc b/media/cdm/ppapi/clear_key_cdm/cdm_proxy_test.cc
index 7e2a48d..3ec79d4 100644
--- a/media/cdm/ppapi/clear_key_cdm/cdm_proxy_test.cc
+++ b/media/cdm/ppapi/clear_key_cdm/cdm_proxy_test.cc
@@ -23,11 +23,13 @@
   DVLOG(1) << __func__;
   completion_cb_ = std::move(completion_cb);
 
-  cdm_proxy_ = cdm_host_proxy_->CreateCdmProxy();
-  if (!cdm_proxy_)
+  cdm_proxy_ = cdm_host_proxy_->CreateCdmProxy(this);
+  if (!cdm_proxy_) {
     OnTestComplete(false);
+    return;
+  }
 
-  cdm_proxy_->Initialize(this);
+  cdm_proxy_->Initialize();
 }
 
 void CdmProxyTest::OnTestComplete(bool success) {
@@ -46,6 +48,12 @@
     return;
   }
 
+  // Only one CdmProxy can be created during the lifetime of the CDM instance.
+  if (cdm_host_proxy_->CreateCdmProxy(this)) {
+    OnTestComplete(false);
+    return;
+  }
+
   cdm_proxy_->Process(cdm::CdmProxy::kIntelNegotiateCryptoSessionKeyExchange,
                       crypto_session_id, kClearKeyCdmProxyInputData.data(),
                       kClearKeyCdmProxyInputData.size(), 0);
@@ -78,6 +86,13 @@
     return;
   }
 
+  // Cannot create another CdmProxy even after destroying the first one.
+  cdm_proxy_->Destroy();
+  if (cdm_host_proxy_->CreateCdmProxy(this)) {
+    OnTestComplete(false);
+    return;
+  }
+
   OnTestComplete(true);
 }
 
diff --git a/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.cc b/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.cc
index 539eade6..6f57347 100644
--- a/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.cc
+++ b/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.cc
@@ -382,6 +382,13 @@
   // to check persistent state permission.
   allow_persistent_state_ = allow_persistent_state;
 
+  // CdmProxy must be created during initialization time. OnInitialized() will
+  // be called in OnCdmProxyTestComplete().
+  if (key_system_ == kExternalClearKeyCdmProxyTestKeySystem) {
+    StartCdmProxyTest();
+    return;
+  }
+
   cdm_host_proxy_->OnInitialized(true);
 }
 
@@ -430,6 +437,8 @@
       std::vector<uint8_t>(init_data, init_data + init_data_size),
       std::move(promise));
 
+  // Run unit tests if applicable. Unit test results are reported in the form of
+  // a session message. Therefore it can only be called after session creation.
   if (key_system_ == kExternalClearKeyFileIOTestKeySystem) {
     StartFileIOTest();
   } else if (key_system_ == kExternalClearKeyOutputProtectionTestKeySystem) {
@@ -438,11 +447,11 @@
              kExternalClearKeyPlatformVerificationTestKeySystem) {
     StartPlatformVerificationTest();
   } else if (key_system_ == kExternalClearKeyVerifyCdmHostTestKeySystem) {
-    VerifyCdmHostTest();
+    ReportVerifyCdmHostTestResult();
   } else if (key_system_ == kExternalClearKeyStorageIdTestKeySystem) {
     StartStorageIdTest();
   } else if (key_system_ == kExternalClearKeyCdmProxyTestKeySystem) {
-    StartCdmProxyTest();
+    ReportCdmProxyTestResult();
   }
 }
 
@@ -967,7 +976,7 @@
                                          challenge.data(), challenge.size());
 }
 
-void ClearKeyCdm::VerifyCdmHostTest() {
+void ClearKeyCdm::ReportVerifyCdmHostTestResult() {
   // VerifyCdmHost() should have already been called and test result stored
   // in |g_verify_host_files_result|.
   OnUnitTestComplete(g_verify_host_files_result);
@@ -995,7 +1004,15 @@
   DCHECK(cdm_proxy_test_);
 
   cdm_proxy_test_.reset();
-  OnUnitTestComplete(success);
+  has_cdm_proxy_test_passed_ = success;
+
+  // Ignore test result here. It will be reported in ReportCdmProxyTestResult().
+  cdm_host_proxy_->OnInitialized(true);
+}
+
+void ClearKeyCdm::ReportCdmProxyTestResult() {
+  // StartCdmProxyTest() should have already been called and finished.
+  OnUnitTestComplete(has_cdm_proxy_test_passed_);
 }
 
 }  // namespace media
diff --git a/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.h b/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.h
index d142cea..9c8ec55 100644
--- a/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.h
+++ b/media/cdm/ppapi/clear_key_cdm/clear_key_cdm.h
@@ -142,11 +142,12 @@
 
   void StartOutputProtectionTest();
   void StartPlatformVerificationTest();
-  void VerifyCdmHostTest();
+  void ReportVerifyCdmHostTestResult();
   void StartStorageIdTest();
 
   void StartCdmProxyTest();
   void OnCdmProxyTestComplete(bool success);
+  void ReportCdmProxyTestResult();
 
   int host_interface_version_ = 0;
 
@@ -173,13 +174,13 @@
 #endif  // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
 
   std::unique_ptr<CdmVideoDecoder> video_decoder_;
-
   std::unique_ptr<FileIOTestRunner> file_io_test_runner_;
   std::unique_ptr<CdmProxyTest> cdm_proxy_test_;
 
   bool is_running_output_protection_test_ = false;
   bool is_running_platform_verification_test_ = false;
   bool is_running_storage_id_test_ = false;
+  bool has_cdm_proxy_test_passed_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ClearKeyCdm);
 };
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index c129c5a..ecd72bd 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -162,6 +162,7 @@
     "//ui/gfx/geometry",
   ]
   deps = [
+    "//gpu/command_buffer/service:gles2",
     "//gpu/ipc/service",
     "//ui/base",
     "//ui/display/types",
diff --git a/media/gpu/ipc/service/BUILD.gn b/media/gpu/ipc/service/BUILD.gn
index 5550c3f..812d291 100644
--- a/media/gpu/ipc/service/BUILD.gn
+++ b/media/gpu/ipc/service/BUILD.gn
@@ -34,6 +34,7 @@
     "//media/gpu",
   ]
   deps = [
+    "//gpu/command_buffer/service:gles2",
     "//gpu/ipc/service",
     "//media:media_features",
     "//media/gpu:features",
diff --git a/media/mojo/services/mojo_cdm_helper.cc b/media/mojo/services/mojo_cdm_helper.cc
index 06c1fbcd..a5abcbfc 100644
--- a/media/mojo/services/mojo_cdm_helper.cc
+++ b/media/mojo/services/mojo_cdm_helper.cc
@@ -37,18 +37,20 @@
   return cdm_file_io;
 }
 
-cdm::CdmProxy* MojoCdmHelper::CreateCdmProxy() {
+cdm::CdmProxy* MojoCdmHelper::CreateCdmProxy(cdm::CdmProxyClient* client) {
+  DVLOG(3) << __func__;
+
+  if (cdm_proxy_) {
+    DVLOG(1) << __func__ << ": Only one outstanding CdmProxy allowed.";
+    return nullptr;
+  }
+
   mojom::CdmProxyPtr cdm_proxy_ptr;
   service_manager::GetInterface<mojom::CdmProxy>(interface_provider_,
                                                  &cdm_proxy_ptr);
-  auto mojo_cdm_proxy =
-      std::make_unique<MojoCdmProxy>(this, std::move(cdm_proxy_ptr));
-
-  cdm::CdmProxy* cdm_proxy = mojo_cdm_proxy.get();
-  DVLOG(3) << __func__ << ": cdm_proxy = " << cdm_proxy;
-
-  cdm_proxy_set_.push_back(std::move(mojo_cdm_proxy));
-  return cdm_proxy;
+  cdm_proxy_ =
+      std::make_unique<MojoCdmProxy>(this, std::move(cdm_proxy_ptr), client);
+  return cdm_proxy_.get();
 }
 
 cdm::Buffer* MojoCdmHelper::CreateCdmBuffer(size_t capacity) {
@@ -103,10 +105,13 @@
 
 void MojoCdmHelper::DestroyCdmProxy(MojoCdmProxy* cdm_proxy) {
   DVLOG(3) << __func__ << ": cdm_proxy = " << cdm_proxy;
-  base::EraseIf(cdm_proxy_set_,
-                [cdm_proxy](const std::unique_ptr<MojoCdmProxy>& ptr) {
-                  return ptr.get() == cdm_proxy;
-                });
+
+  if (cdm_proxy != cdm_proxy_.get()) {
+    DVLOG(3) << __func__ << ": Invalid CdmProxy to destroy.";
+    return;
+  }
+
+  cdm_proxy_.reset();
 }
 
 void MojoCdmHelper::ReportFileReadSize(int file_size_bytes) {
diff --git a/media/mojo/services/mojo_cdm_helper.h b/media/mojo/services/mojo_cdm_helper.h
index 2d971282..4537c2fb 100644
--- a/media/mojo/services/mojo_cdm_helper.h
+++ b/media/mojo/services/mojo_cdm_helper.h
@@ -42,7 +42,7 @@
   // CdmAuxiliaryHelper implementation.
   void SetFileReadCB(FileReadCB file_read_cb) final;
   cdm::FileIO* CreateCdmFileIO(cdm::FileIOClient* client) final;
-  cdm::CdmProxy* CreateCdmProxy() final;
+  cdm::CdmProxy* CreateCdmProxy(cdm::CdmProxyClient* client) final;
   cdm::Buffer* CreateCdmBuffer(size_t capacity) final;
   std::unique_ptr<VideoFrameImpl> CreateCdmVideoFrame() final;
   void QueryStatus(QueryStatusCB callback) final;
@@ -84,7 +84,8 @@
   // A list of open cdm::FileIO objects.
   // TODO(xhwang): Switch to use UniquePtrComparator.
   std::vector<std::unique_ptr<MojoCdmFileIO>> cdm_file_io_set_;
-  std::vector<std::unique_ptr<MojoCdmProxy>> cdm_proxy_set_;
+
+  std::unique_ptr<MojoCdmProxy> cdm_proxy_;
 
   base::WeakPtrFactory<MojoCdmHelper> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(MojoCdmHelper);
diff --git a/media/mojo/services/mojo_cdm_proxy.cc b/media/mojo/services/mojo_cdm_proxy.cc
index 2fcef88b..1d0ef97 100644
--- a/media/mojo/services/mojo_cdm_proxy.cc
+++ b/media/mojo/services/mojo_cdm_proxy.cc
@@ -64,25 +64,26 @@
 
 }  // namespace
 
-MojoCdmProxy::MojoCdmProxy(Delegate* delegate, mojom::CdmProxyPtr cdm_proxy_ptr)
+MojoCdmProxy::MojoCdmProxy(Delegate* delegate,
+                           mojom::CdmProxyPtr cdm_proxy_ptr,
+                           cdm::CdmProxyClient* client)
     : delegate_(delegate),
       cdm_proxy_ptr_(std::move(cdm_proxy_ptr)),
+      client_(client),
       client_binding_(this),
       weak_factory_(this) {
   DVLOG(1) << __func__;
   DCHECK(delegate_);
+  DCHECK(client);
 }
 
 MojoCdmProxy::~MojoCdmProxy() {
   DVLOG(1) << __func__;
 }
 
-void MojoCdmProxy::Initialize(cdm::CdmProxyClient* client) {
+void MojoCdmProxy::Initialize() {
   DVLOG(2) << __func__;
 
-  DCHECK(client);
-  client_ = client;
-
   mojom::CdmProxyClientAssociatedPtrInfo client_ptr_info;
   client_binding_.Bind(mojo::MakeRequest(&client_ptr_info));
 
diff --git a/media/mojo/services/mojo_cdm_proxy.h b/media/mojo/services/mojo_cdm_proxy.h
index fff5787f..ff78eba 100644
--- a/media/mojo/services/mojo_cdm_proxy.h
+++ b/media/mojo/services/mojo_cdm_proxy.h
@@ -28,11 +28,13 @@
     virtual void DestroyCdmProxy(MojoCdmProxy* cdm_proxy) = 0;
   };
 
-  MojoCdmProxy(Delegate* delegate, mojom::CdmProxyPtr cdm_proxy_ptr);
+  MojoCdmProxy(Delegate* delegate,
+               mojom::CdmProxyPtr cdm_proxy_ptr,
+               cdm::CdmProxyClient* client);
   ~MojoCdmProxy() override;
 
   // cdm::CdmProxy implementation.
-  void Initialize(cdm::CdmProxyClient* client) final;
+  void Initialize() final;
   void Process(Function function,
                uint32_t crypto_session_id,
                const uint8_t* input_data,
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index ae92fe0..11c27840 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -2303,7 +2303,7 @@
 
 // TestTCPSocketRTT requires kernel support for tcp_info struct, and so it is
 // enabled only on certain platforms.
-#if defined(TCP_INFO) || defined(OS_LINUX)
+#if defined(TCP_INFO) || defined(OS_LINUX) || defined(OS_ANDROID)
 #define MAYBE_TestTCPSocketRTT TestTCPSocketRTT
 #else
 #define MAYBE_TestTCPSocketRTT DISABLED_TestTCPSocketRTT
diff --git a/net/socket/tcp_socket_posix.cc b/net/socket/tcp_socket_posix.cc
index adb8cf5..6004620 100644
--- a/net/socket/tcp_socket_posix.cc
+++ b/net/socket/tcp_socket_posix.cc
@@ -150,11 +150,57 @@
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 #if defined(HAVE_TCP_INFO)
-bool GetTcpInfo(SocketDescriptor fd, tcp_info* info) {
+// Returns a zero value if the transport RTT is unavailable.
+base::TimeDelta GetTransportRtt(SocketDescriptor fd) {
+  tcp_info info;
+  // Reset |tcpi_rtt| to verify if getsockopt() actually updates |tcpi_rtt|.
+  info.tcpi_rtt = 0;
+
   socklen_t info_len = sizeof(tcp_info);
-  return getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &info_len) == 0 &&
-         info_len == sizeof(tcp_info);
+  if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) != 0)
+    return base::TimeDelta();
+
+  // Verify that |tcpi_rtt| in tcp_info struct was updated. Note that it's
+  // possible that |info_len| is shorter than |sizeof(tcp_info)| which implies
+  // that only a subset of values in |info| may have been updated by
+  // getsockopt().
+  if (info_len < static_cast<socklen_t>(offsetof(tcp_info, tcpi_rtt) +
+                                        sizeof(info.tcpi_rtt))) {
+    return base::TimeDelta();
+  }
+
+  return base::TimeDelta::FromMicroseconds(info.tcpi_rtt);
 }
+
+// Returns true if getsockopt() call was successful. Sets
+// |server_acked_syn_data| to true if SYN-ACK acked data in SYN sent or
+// received.
+bool GetServerAckedDataInSyn(SocketDescriptor fd, bool* server_acked_syn_data) {
+  tcp_info info;
+  // Reset |tcpi_options| to verify if getsockopt() actually updates
+  // |tcpi_options|.
+  info.tcpi_options = 0;
+
+  socklen_t info_len = sizeof(tcp_info);
+  if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &info_len) != 0) {
+    *server_acked_syn_data = false;
+    return false;
+  }
+
+  // Verify that |tcpi_options| in tcp_info struct was updated. Note that it's
+  // possible that |info_len| is shorter than |sizeof(tcp_info)| which implies
+  // that only a subset of values in |info| may have been updated by
+  // getsockopt().
+  if (info_len < static_cast<socklen_t>(offsetof(tcp_info, tcpi_options) +
+                                        sizeof(info.tcpi_options))) {
+    *server_acked_syn_data = false;
+    return false;
+  }
+
+  *server_acked_syn_data = (info.tcpi_options & TCPI_OPT_SYN_DATA);
+  return true;
+}
+
 #endif  // defined(TCP_INFO)
 
 }  // namespace
@@ -802,20 +848,11 @@
     return;
   }
 
-  tcp_info info;
-  if (!GetTcpInfo(socket_->socket_fd(), &info))
+  base::TimeDelta rtt = GetTransportRtt(socket_->socket_fd());
+  if (rtt.is_zero())
     return;
 
-  // Only notify the |socket_performance_watcher_| if the RTT in |tcp_info|
-  // struct was populated. A value of 0 may be valid in certain cases
-  // (on very fast networks), but it is discarded. This means that
-  // some of the RTT values may be missed, but the values that are kept are
-  // guaranteed to be correct.
-  if (info.tcpi_rtt == 0 && info.tcpi_rttvar == 0)
-    return;
-
-  socket_performance_watcher_->OnUpdatedRTTAvailable(
-      base::TimeDelta::FromMicroseconds(info.tcpi_rtt));
+  socket_performance_watcher_->OnUpdatedRTTAvailable(rtt);
 #endif  // defined(TCP_INFO)
 }
 
@@ -833,24 +870,22 @@
   }
 
   bool getsockopt_success = false;
-  bool server_acked_data = false;
+  bool server_acked_syn_data = false;
 #if defined(HAVE_TCP_INFO)
   // Probe to see the if the socket used TCP FastOpen.
-  tcp_info info;
-  getsockopt_success = GetTcpInfo(socket_->socket_fd(), &info);
-  server_acked_data =
-      getsockopt_success && (info.tcpi_options & TCPI_OPT_SYN_DATA);
+  getsockopt_success =
+      GetServerAckedDataInSyn(socket_->socket_fd(), &server_acked_syn_data);
 #endif  // defined(TCP_INFO)
 
   if (getsockopt_success) {
     if (tcp_fastopen_status_ == TCP_FASTOPEN_FAST_CONNECT_RETURN) {
-      tcp_fastopen_status_ = (server_acked_data ?
-                              TCP_FASTOPEN_SYN_DATA_ACK :
-                              TCP_FASTOPEN_SYN_DATA_NACK);
+      tcp_fastopen_status_ =
+          (server_acked_syn_data ? TCP_FASTOPEN_SYN_DATA_ACK
+                                 : TCP_FASTOPEN_SYN_DATA_NACK);
     } else {
-      tcp_fastopen_status_ = (server_acked_data ?
-                              TCP_FASTOPEN_NO_SYN_DATA_ACK :
-                              TCP_FASTOPEN_NO_SYN_DATA_NACK);
+      tcp_fastopen_status_ =
+          (server_acked_syn_data ? TCP_FASTOPEN_NO_SYN_DATA_ACK
+                                 : TCP_FASTOPEN_NO_SYN_DATA_NACK);
     }
   } else {
     tcp_fastopen_status_ =
@@ -866,15 +901,11 @@
     return false;
 
 #if defined(HAVE_TCP_INFO)
-  tcp_info info;
-  if (GetTcpInfo(socket_->socket_fd(), &info)) {
-    // tcpi_rtt is zero when the kernel doesn't have an RTT estimate,
-    // and possibly in other cases such as connections to localhost.
-    if (info.tcpi_rtt > 0) {
-      *out_rtt = base::TimeDelta::FromMicroseconds(info.tcpi_rtt);
-      return true;
-    }
-  }
+  base::TimeDelta rtt = GetTransportRtt(socket_->socket_fd());
+  if (rtt.is_zero())
+    return false;
+  *out_rtt = rtt;
+  return true;
 #endif  // defined(TCP_INFO)
   return false;
 }
diff --git a/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
index 057f0d4..e96f51b 100644
--- a/sandbox/linux/seccomp-bpf/syscall_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -18,6 +18,7 @@
 
 #include "base/macros.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
 #include "build/build_config.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
@@ -163,6 +164,8 @@
 
 TEST(Syscall, ComplexSyscallSixArgs) {
   int fd;
+  const size_t kPageSize = base::GetPageSize();
+
   ASSERT_LE(0,
             fd = Syscall::Call(__NR_openat, AT_FDCWD, "/dev/null", O_RDWR, 0L));
 
@@ -172,7 +175,7 @@
       (char*)NULL,
       addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
                                                     (void*)NULL,
-                                                    4096,
+                                                    kPageSize,
                                                     PROT_READ,
                                                     MAP_PRIVATE | MAP_ANONYMOUS,
                                                     fd,
@@ -184,7 +187,7 @@
             addr1 = reinterpret_cast<char*>(
                 Syscall::Call(kMMapNr,
                               addr0,
-                              4096L,
+                              kPageSize,
                               PROT_READ | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
                               fd,
@@ -192,7 +195,7 @@
   ++*addr1;  // This should not seg fault
 
   // Clean up
-  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, 4096L));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, kPageSize));
   EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
 
   // Check that the offset argument (i.e. the sixth argument) is processed
@@ -202,32 +205,42 @@
       0);
   char* addr2, *addr3;
   ASSERT_NE((char*)NULL,
-            addr2 = reinterpret_cast<char*>(Syscall::Call(
-                kMMapNr, (void*)NULL, 8192L, PROT_READ, MAP_PRIVATE, fd, 0L)));
+            addr2 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                          (void*)NULL,
+                                                          2 * kPageSize,
+                                                          PROT_READ,
+                                                          MAP_PRIVATE,
+                                                          fd,
+                                                          0L
+                                                          )));
   ASSERT_NE((char*)NULL,
             addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
                                                           (void*)NULL,
-                                                          4096L,
+                                                          kPageSize,
                                                           PROT_READ,
                                                           MAP_PRIVATE,
                                                           fd,
 #if defined(__NR_mmap2)
                                                           1L
 #else
-                                                          4096L
+                                                          kPageSize
 #endif
                                                           )));
-  EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096));
+  EXPECT_EQ(0, memcmp(addr2 + kPageSize, addr3, kPageSize));
 
   // Just to be absolutely on the safe side, also verify that the file
   // contents matches what we are getting from a read() operation.
-  char buf[8192];
-  EXPECT_EQ(8192, Syscall::Call(__NR_read, fd, buf, 8192L));
-  EXPECT_EQ(0, memcmp(addr2, buf, 8192));
+  char buf[2 * kPageSize];
+  EXPECT_EQ(2 * kPageSize, static_cast<size_t>(Syscall::Call(__NR_read,
+                                                             fd,
+                                                             buf,
+                                                             2 * kPageSize
+                                                             )));
+  EXPECT_EQ(0, memcmp(addr2, buf, 2 * kPageSize));
 
   // Clean up
-  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 8192L));
-  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, 4096L));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 2 * kPageSize));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, kPageSize));
   EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
 }
 
diff --git a/services/ui/public/cpp/gpu/BUILD.gn b/services/ui/public/cpp/gpu/BUILD.gn
index d8e7c0b..d761ff6 100644
--- a/services/ui/public/cpp/gpu/BUILD.gn
+++ b/services/ui/public/cpp/gpu/BUILD.gn
@@ -43,6 +43,7 @@
     "//cc",
     "//gpu",
     "//gpu/command_buffer/client",
+    "//gpu/command_buffer/client:gles2_cmd_helper",
     "//gpu/command_buffer/client:gles2_implementation",
     "//gpu/skia_bindings",
     "//mojo/public/cpp/system",
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 2061fae..ec2bc22 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -1807,7 +1807,8 @@
               "device_type": "sprout"
             }
           ],
-          "expiration": 14400
+          "expiration": 14400,
+          "hard_timeout": 900
         },
         "test": "media_unittests"
       },
@@ -3021,7 +3022,7 @@
             }
           ],
           "expiration": 10800,
-          "hard_timeout": 960,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -4637,7 +4638,8 @@
             {
               "device_type": "coho"
             }
-          ]
+          ],
+          "hard_timeout": 900
         },
         "test": "media_unittests"
       },
@@ -5599,7 +5601,8 @@
             {
               "device_type": "gce_x86"
             }
-          ]
+          ],
+          "hard_timeout": 900
         },
         "test": "media_unittests"
       },
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 793a006..e87a82a8 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -1719,6 +1719,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -3397,6 +3398,7 @@
               "device_type": "hammerhead"
             }
           ],
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -5021,7 +5023,7 @@
             }
           ],
           "expiration": 10800,
-          "hard_timeout": 300,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -6529,7 +6531,7 @@
             }
           ],
           "expiration": 10800,
-          "hard_timeout": 960,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -7992,7 +7994,7 @@
             }
           ],
           "expiration": 10800,
-          "hard_timeout": 600,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -9521,7 +9523,7 @@
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 960,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -11032,7 +11034,7 @@
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 960,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
@@ -12758,7 +12760,7 @@
             }
           ],
           "expiration": 10800,
-          "hard_timeout": 600,
+          "hard_timeout": 900,
           "output_links": [
             {
               "link": [
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 441697d1..44ec412 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1009,6 +1009,17 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--enable-viz",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_unittests.filter"
+        ],
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 129cf61..b31c371 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -785,6 +785,17 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--enable-viz",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_unittests.filter"
+        ],
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1513,6 +1524,17 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--enable-viz",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_unittests.filter"
+        ],
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -2097,6 +2119,17 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--enable-viz",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_unittests.filter"
+        ],
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/chromium.sandbox.json b/testing/buildbot/chromium.sandbox.json
index 29f10c1..0e7ba41 100644
--- a/testing/buildbot/chromium.sandbox.json
+++ b/testing/buildbot/chromium.sandbox.json
@@ -223,6 +223,17 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--enable-viz",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_unittests.filter"
+        ],
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 7120f2f..e39e81a9 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -375,6 +375,7 @@
 -DeclarativeNetRequestResourceTypeBrowserTest.Test1/1
 -DeclarativeNetRequestResourceTypeBrowserTest.Test2/1
 -DeclarativeNetRequestResourceTypeBrowserTest.Test2/0
+-DevToolsFrontendInWebRequestApiTest.HiddenRequests
 -ExtensionWebRequestApiTest.DeclarativeSendMessage
 -ExtensionWebRequestApiTest.ExtensionRequests
 -ExtensionWebRequestApiTest.HostedAppRequest
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 8a3765b..d931a078 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2301,28 +2301,6 @@
       # chromium.fyi
       'Fuchsia ARM64',
     ],
-    'modifications': {
-      'KitKat Tablet Tester': {
-        'swarming': {
-          'hard_timeout': 300,
-        },
-      },
-      'Lollipop Tablet Tester': {
-        'swarming': {
-          'hard_timeout': 600,
-        },
-      },
-      'Marshmallow Phone Tester (rel)': {
-        'swarming': {
-          'hard_timeout': 960,
-        },
-      },
-      'Marshmallow Tablet Tester': {
-        'swarming': {
-          'hard_timeout': 600,
-        },
-      },
-    },
   },
   'message_center_unittests': {
     'remove_from': [
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 74456497..4cde076 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -389,7 +389,11 @@
     'ipc_tests': {},
     'jingle_unittests': {},
     'media_blink_unittests': {},
-    'media_unittests': {},
+    'media_unittests': {
+      'android_swarming': {
+        'hard_timeout': 900,
+      },
+    },
     'midi_unittests': {},
     'net_unittests': {
       'android_swarming': {
@@ -1695,6 +1699,13 @@
       },
       'test': 'content_browsertests',
     },
+    'viz_content_unittests': {
+      'args': [
+        '--enable-viz',
+        '--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_unittests.filter',
+      ],
+      'test': 'content_unittests',
+    }
   },
 
   # TODO(kbr): rename this back to vr_platform_specific_chromium_gtests and
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f931a965..beaecde 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3856,6 +3856,12 @@
                     "enable_features": [
                         "UseHeuristicLanguageModel"
                     ]
+                },
+                {
+                    "name": "Beta_Experiment",
+                    "enable_features": [
+                        "UseHeuristicLanguageModel"
+                    ]
                 }
             ]
         }
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 39a5a292..e556a3b 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -62,6 +62,7 @@
 crbug.com/769942 virtual/spv175/compositing/overflow/accelerated-scrolling-with-clip-path-text.html [ Failure ]
 crbug.com/769942 virtual/spv175/compositing/overflow/accelerated-scrolling-with-clip-path.html [ Failure ]
 crbug.com/769942 virtual/spv175/compositing/overflow/accelerated-scrolling-with-clip-reference.html [ Failure ]
+crbug.com/769942 virtual/spv175/fast/borders/border-image-fill-inline-no-border.html [ Failure ]
 crbug.com/769942 virtual/spv175/paint/clipath/clip-path-bigger-than-border-box-visual-rect.html [ Failure ]
 crbug.com/769942 virtual/spv175/paint/clipath/clip-path-bigger-than-visual-overflow.html [ Failure ]
 crbug.com/769942 virtual/spv175/paint/clipath/clip-path-with-background-and-box-behind.html [ Failure ]
@@ -79,7 +80,6 @@
 
 crbug.com/771643 virtual/spv175/compositing/overflow/nested-border-radius-clipping.html [ Failure ]
 crbug.com/771643 virtual/spv175/compositing/visibility/visibility-image-layers.html [ Failure Pass ]
-crbug.com/771643 virtual/spv175/fast/borders/border-image-fill-inline-no-border.html [ Failure ]
 crbug.com/771643 virtual/spv175/fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
 crbug.com/771643 virtual/spv175/fast/borders/inline-mask-overlay-image-outset.html [ Failure ]
 crbug.com/771643 virtual/spv175/fast/borders/inline-mask-overlay-image.html [ Failure ]
@@ -92,8 +92,6 @@
 crbug.com/771643 virtual/spv175/paint/invalidation/svg/filter-refresh.svg [ Failure ]
 crbug.com/771643 virtual/spv175/paint/invalidation/svg/paintorder-filtered.svg [ Failure ]
 crbug.com/771643 virtual/spv175/paint/invalidation/svg/text-viewbox-rescale.html [ Failure ]
-crbug.com/771643 virtual/spv175/paint/invalidation/svg/use-clipped-hit.svg [ Failure ]
-crbug.com/771643 virtual/spv175/paint/invalidation/svg/zoom-coords-viewattr-01-b.svg [ Failure ]
 
 # spv175+root-layer-scrolls failures. They also fail with root-layer-scrolls without enable-slimming-paint-v175.
 crbug.com/417782 virtual/spv175/compositing/overflow/border-radius-composited-subframe.html [ Failure ]
@@ -2036,12 +2034,6 @@
 crbug.com/626703 external/wpt/mediacapture-streams/MediaStreamTrack-end-manual.https.html [ Timeout Failure ]
 crbug.com/626703 external/wpt/media-source/mediasource-avtracks.html [ Failure Crash ]
 crbug.com/626703 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Timeout Failure ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/notifications/constructor-basic.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/notifications/constructor-invalid.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/notifications/event-onclose.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/notifications/event-onshow.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/notifications/instance.html [ Timeout ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/notifications/lang.html [ Timeout ]
 crbug.com/626703 external/wpt/orientation-event/deviceorientationabsoluteevent.html [ Timeout ]
 crbug.com/626703 external/wpt/payment-request/payment-request-show-method.https.html [ Pass Failure ]
 crbug.com/626703 external/wpt/performance-timeline/po-observe.html [ Timeout ]
@@ -3301,7 +3293,7 @@
 crbug.com/669329 http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js [ Pass Failure Crash ]
 crbug.com/669329 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js [ Pass Failure Crash ]
 
-crbug.com/760543 http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.js [ Pass Timeout ]
+crbug.com/799619 [ Debug ] http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.js [ Pass Timeout ]
 crbug.com/760543 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Pass Timeout ]
 
 crbug.com/769347 [ Mac ] fast/dom/inert/inert-node-is-uneditable.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html
deleted file mode 100644
index dd301004..0000000
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
-<script>
-'use strict';
-bluetooth_test(() => {
-  return setUpPreconnectedDevice({name: ''})
-    .then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
-    .then(device => {
-      assert_equals(device.name, '');
-    });
-}, 'Device with empty name and no UUIDs nearby. Should be found if ' +
-   'acceptAllDevices is true.');
-</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html
deleted file mode 100644
index cad9d75..0000000
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/device-with-name.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
-<script>
-bluetooth_test(() => {
-  let device_name = 'LE Device';
-  return setUpPreconnectedDevice({name: device_name})
-    .then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
-    .then(device => {
-      assert_equals(device.name, device_name);
-    });
-}, 'A device with name and no UUIDs nearby. Should be found if ' +
-   'acceptAllDevices is true.');
-</script>
diff --git a/third_party/WebKit/LayoutTests/editing/inserting/insert-space-at-start-of-wrapped-line.html b/third_party/WebKit/LayoutTests/editing/inserting/insert-space-at-start-of-wrapped-line.html
index 9defdf2..41224ff 100644
--- a/third_party/WebKit/LayoutTests/editing/inserting/insert-space-at-start-of-wrapped-line.html
+++ b/third_party/WebKit/LayoutTests/editing/inserting/insert-space-at-start-of-wrapped-line.html
@@ -11,10 +11,37 @@
   white-space: pre-wrap;
 }
 </style>
-<textarea id="textarea">12345     67</textarea>
-<div id="plaintext" contenteditable="plaintext-only">12345     67</div>
-<div id="richedit" contenteditable>12345     67</div>
+<textarea id="textarea"></textarea>
+<div id="plaintext" contenteditable="plaintext-only"></div>
+<div id="richedit" contenteditable></div>
 <script>
+function runInElement(element, before, after, expected) {
+  test(() => {
+    let offset = before.length;
+    let acutal;
+    if (element.tagName === 'TEXTAREA') {
+      element.value = before + after;
+      element.focus();
+      element.setSelectionRange(offset, offset);
+      eventSender.keyDown(' ');
+      actual = element.value;
+    } else {
+      element.textContent = before + after;
+      let textNode = element.firstChild;
+      window.getSelection().setBaseAndExtent(textNode, offset, textNode, offset);
+      eventSender.keyDown(' ');
+      actual = element.textContent;
+    }
+    assert_equals(actual, before + (expected ? '\n ' : ' ') + after);
+  }, `Typing space at "${before}|${after}" ${expected ? 'should' : 'should not'} insert a line break in ${element.id}`);
+}
+
+function run(before, after, expected) {
+  runInElement(textarea, before, after, expected);
+  runInElement(plaintext, before, after, expected);
+  runInElement(richedit, before, after, false);
+}
+
 (function () {
   if (!window.eventSender) {
     test(function () {
@@ -23,28 +50,9 @@
     return;
   }
 
-  test(function () {
-    let textarea = document.getElementById('textarea');
-    textarea.focus();
-    textarea.setSelectionRange(10, 10);
-    eventSender.keyDown(' ');
-    assert_equals(textarea.value, '12345     \n 67', 'Line break should be inserted automatically');
-  }, 'Typing space at the start of wrapped line in textarea');
-
-  test(function () {
-    let editor = document.getElementById('plaintext');
-    let textNode = editor.firstChild;
-    window.getSelection().setBaseAndExtent(textNode, 10, textNode, 10);
-    eventSender.keyDown(' ');
-    assert_equals(editor.textContent, '12345     \n 67', 'Line break should be inserted automatically');
-  }, 'Typing space at the start of wrapped line in plaintext-only');
-
-  test(function () {
-    let editor = document.getElementById('richedit');
-    let textNode = editor.firstChild;
-    window.getSelection().setBaseAndExtent(textNode, 10, textNode, 10);
-    eventSender.keyDown(' ');
-    assert_equals(editor.textContent, '12345      67', 'Line break should NOT be inserted automatically');
-  }, 'Typing space at the start of wrapped line in contenteditable');
+  run('123456789 ', 'XY', true);
+  run('12345     ', 'XY', true);
+  run('12345        ', 'XY', true);
+  run('123456789-', 'XY', false);
 })();
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.html
new file mode 100644
index 0000000..56e905c6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/device-with-empty-name.https.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+bluetooth_test(() => {
+  return setUpPreconnectedDevice({name: ''})
+    .then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
+    .then(device => {
+      assert_equals(device.name, '');
+    });
+}, 'Device with empty name and no UUIDs nearby. Should be found if ' +
+   'acceptAllDevices is true.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.html
new file mode 100644
index 0000000..8c271df5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/device-with-name.https.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script>
+bluetooth_test(() => {
+  let device_name = 'LE Device';
+  return setUpPreconnectedDevice({name: device_name})
+    .then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
+    .then(device => {
+      assert_equals(device.name, device_name);
+    });
+}, 'A device with name and no UUIDs nearby. Should be found if ' +
+   'acceptAllDevices is true.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.html
similarity index 64%
rename from third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.html
rename to third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.html
index 13d3f86..adf77ba 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/optional-services-missing.https.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
 <script>
 'use strict';
 bluetooth_test(() => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.html
similarity index 66%
rename from third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.html
rename to third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.html
index bb03bf3..e202e74 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/acceptAllDevices/optional-services-present.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/requestDevice/acceptAllDevices/optional-services-present.https.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
 <script>
 'use strict';
 const test_desc = 'requestDevice called with acceptAllDevices: true and with ' +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-svg-anchor-child.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-svg-anchor-child.html
new file mode 100644
index 0000000..d0119d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-svg-anchor-child.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Display: display:contents on SVG anchor child</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-display/#unbox-svg">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<svg>
+  <a>
+    <tspan style="display:contents;color:green">Text</tspan>
+  </a>
+  <text>
+    <a>
+      <tspan style="display:contents;color:green">Text</tspan>
+    </a>
+  </text>
+</svg>
+<script>
+  test(() => {}, "Loading this page should not cause a crash.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-svg-switch-child.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-svg-switch-child.html
new file mode 100644
index 0000000..7befdb4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-svg-switch-child.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Display: display:contents on SVG switch child</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-display/#unbox-svg">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<svg>
+  <switch>
+    <tspan style="display:contents;color:green">Text</tspan>
+  </switch>
+</svg>
+<script>
+  test(() => {}, "Loading this page should not cause a crash.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/interface-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/interface-expected.txt
new file mode 100644
index 0000000..51ea83cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/interface-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS StylePropertyMapReadOnly interface: existence and properties of interface object
+PASS StylePropertyMapReadOnly interface object length
+PASS StylePropertyMapReadOnly interface object name
+PASS StylePropertyMapReadOnly interface: existence and properties of interface prototype object
+PASS StylePropertyMapReadOnly interface: existence and properties of interface prototype object's "constructor" property
+PASS StylePropertyMapReadOnly interface: operation get(DOMString)
+PASS StylePropertyMapReadOnly interface: operation getAll(DOMString)
+PASS StylePropertyMapReadOnly interface: operation has(DOMString)
+PASS Testing Symbol.iterator property of iterable interface StylePropertyMapReadOnly
+PASS Testing pair iterable interface StylePropertyMapReadOnly
+PASS StylePropertyMapReadOnly interface: operation getProperties()
+FAIL StylePropertyMapReadOnly interface: stringifier assert_own_property: interface prototype object missing non-static operation expected property "toString" missing
+PASS StylePropertyMapReadOnly interface: operation entries()
+PASS StylePropertyMapReadOnly interface: operation keys()
+PASS StylePropertyMapReadOnly interface: operation values()
+PASS StylePropertyMapReadOnly interface: operation forEach(function, any)
+PASS StylePropertyMap interface: existence and properties of interface object
+PASS StylePropertyMap interface object length
+PASS StylePropertyMap interface object name
+PASS StylePropertyMap interface: existence and properties of interface prototype object
+PASS StylePropertyMap interface: existence and properties of interface prototype object's "constructor" property
+PASS StylePropertyMap interface: operation append(DOMString, [object Object],[object Object])
+PASS StylePropertyMap interface: operation delete(DOMString)
+PASS StylePropertyMap interface: operation set(DOMString, [object Object],[object Object])
+PASS StylePropertyMap interface: operation update(DOMString, UpdateFunction)
+PASS Element interface: operation computedStyleMap()
+PASS Element interface: attribute attributeStyleMap
+PASS CSSStyleRule interface: attribute attributeStyleMap
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/interface.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/interface.html
new file mode 100644
index 0000000..3e884909
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/the-stylepropertymap/interface.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>StylePropertyMap IDL</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#the-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script type="text/plain" id="idl">
+interface StylePropertyMapReadOnly {
+    CSSStyleValue? get(DOMString property);
+    sequence<CSSStyleValue> getAll(DOMString property);
+    boolean has(DOMString property);
+    iterable<DOMString, (CSSStyleValue or sequence<CSSStyleValue>)>;
+    sequence<DOMString> getProperties();
+    stringifier;
+};
+
+callback UpdateFunction = CSSStyleValue (CSSStyleValue oldValue);
+
+interface StylePropertyMap : StylePropertyMapReadOnly {
+    void append(DOMString property, (CSSStyleValue or DOMString)... values);
+    void delete(DOMString property);
+    void set(DOMString property, (CSSStyleValue or DOMString)... values);
+    void update(DOMString property, UpdateFunction updateFunction);
+};
+
+partial interface Element {
+    StylePropertyMapReadOnly computedStyleMap();
+};
+
+partial interface CSSStyleRule {
+    [SameObject] readonly attribute StylePropertyMap attributeStyleMap;
+};
+
+partial interface Element {
+    [SameObject] readonly attribute StylePropertyMap attributeStyleMap;
+};
+</script>
+<script>
+'use strict';
+const idlArray = new IdlArray();
+idlArray.add_idls(document.getElementById('idl').textContent);
+idlArray.add_untested_idls('interface Element {};');
+idlArray.add_untested_idls('interface CSSStyleRule {};');
+idlArray.test();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/service-workers/OWNERS
index 2910cf26..c7c9d2c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/OWNERS
@@ -1,3 +1,4 @@
 # TEAM: worker-dev@chromium.org
 # COMPONENT: Blink>ServiceWorker
-worker-dev@chromium.org
+# WPT-NOTIFY: true
+file://content/browser/service_worker/OWNERS
diff --git a/third_party/WebKit/LayoutTests/fast/table/percent-height-content-in-percent-height-cell-and-percent-height-table.html b/third_party/WebKit/LayoutTests/fast/table/percent-height-content-in-percent-height-cell-and-percent-height-table.html
index 7559d0f..ab9ea83 100644
--- a/third_party/WebKit/LayoutTests/fast/table/percent-height-content-in-percent-height-cell-and-percent-height-table.html
+++ b/third_party/WebKit/LayoutTests/fast/table/percent-height-content-in-percent-height-cell-and-percent-height-table.html
@@ -12,11 +12,11 @@
     background: red;
   }
 </style>
-<p>crbug.com/762330: A table with percent height and nothing to resolve against should be treated as auto .</p>
+<p>crbug.com/762330 and crbug.com/798478: A table with percent height and nothing to resolve against should be treated as auto per the spec but we make an exception for the sake of interoperability.</p>
 <table>
     <tr class="full">
         <td class="full">
-          <div class='full container' id="test" data-expected-height=20>
+          <div class='full container' id="test" data-expected-height=50>
             <div class='full'>
               Text
             </div>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
index 6def153..e277afea 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
@@ -9,7 +9,12 @@
         {
           "object": "LayoutSVGViewportContainer svg id='inner'",
           "rect": [0, 0, 200, 200],
-          "reason": "disappeared"
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='inner'",
+          "rect": [0, 0, 100, 100],
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
index ada07216..1a9f42b6 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
@@ -7,14 +7,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutSVGRoot svg",
-          "rect": [0, 0, 100, 100],
-          "reason": "appeared"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg id='s'",
           "rect": [0, 0, 100, 100],
-          "reason": "disappeared"
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
index 9cf0fb2..832926ee 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
@@ -17,8 +17,13 @@
           "reason": "appeared"
         },
         {
+          "object": "LayoutSVGViewportContainer svg id='inner'",
+          "rect": [100, 0, 100, 200],
+          "reason": "incremental"
+        },
+        {
           "object": "InlineTextBox 'right-aligned text'",
-          "rect": [0, 85, 101, 19],
+          "rect": [0, 85, 100, 19],
           "reason": "disappeared"
         },
         {
@@ -29,6 +34,11 @@
         {
           "object": "LayoutSVGRect rect",
           "rect": [180, 60, 20, 20],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [180, 60, 20, 20],
           "reason": "full"
         },
         {
@@ -39,6 +49,11 @@
         {
           "object": "LayoutSVGRect rect",
           "rect": [80, 60, 20, 20],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [80, 60, 20, 20],
           "reason": "full"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt
index 010474f..fa7410b 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/text-rescale-expected.txt
@@ -33,7 +33,7 @@
         },
         {
           "object": "LayoutSVGViewportContainer svg",
-          "rect": [9, 3, 5, 3],
+          "rect": [9, 3, 4, 3],
           "reason": "paint property change"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-mouse-test-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-mouse-test-expected.txt
new file mode 100644
index 0000000..e02d970
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-mouse-test-expected.txt
@@ -0,0 +1,45 @@
+Tests that the styles sidebar can be used with a mouse.
+
+Test switching between items
+mouse down: SPAN:blue
+Not editing
+mouse up: SPAN:blue
+Editing: "blue"
+
+mouse down: SPAN:color
+Not editing
+mouse up: SPAN:color
+Editing: "color"
+
+mouse down: SPAN:blue
+Not editing
+mouse up: SPAN:color
+Editing: "color"
+
+Cancel editing by clicking a blank area
+mouse down: LI:    color: blue;
+Not editing
+mouse up: LI:    color: blue;
+Not editing
+
+Create a new property by clicking a blank area
+mouse down: LI:    color: blue;
+Not editing
+mouse up: LI:    color: blue;
+Editing: ""
+
+Test disabling the property
+mouse down: INPUT:
+Not editing
+mouse up: INPUT:
+Not editing
+Enabled: false
+
+Test enabling the property
+mouse down: INPUT:
+Not editing
+mouse up: INPUT:
+Not editing
+Enabled: true
+
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-mouse-test.js b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-mouse-test.js
new file mode 100644
index 0000000..d7a3878
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles/styles-mouse-test.js
@@ -0,0 +1,91 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(`Tests that the styles sidebar can be used with a mouse.\n`);
+  await TestRunner.loadModule('elements_test_runner');
+  await TestRunner.showPanel('elements');
+  await TestRunner.loadHTML(`
+    <style>
+      #inspected {
+        color: blue;
+        background-color: red;
+      }
+    </style>
+    <div id="inspected">Text</div>
+  `);
+  await new Promise(x => ElementsTestRunner.selectNodeAndWaitForStyles('inspected', x));
+
+  var stylesPane = UI.panels.elements._stylesWidget;
+  var firstRule = stylesPane._sectionBlocks[0].sections[1].propertiesTreeOutline;
+  var blueElement = () => firstRule.firstChild().valueElement;
+  var colorElement = () => firstRule.firstChild().nameElement;
+  var listItemElement = () => firstRule.firstChild().listItemElement;
+
+  TestRunner.addResult('Test switching between items')
+  mouseDown(blueElement());
+  mouseUp(blueElement());
+  TestRunner.addResult('');
+
+  mouseDown(colorElement());
+  mouseUp(colorElement());
+  TestRunner.addResult('');
+
+  mouseDown(blueElement());
+  mouseUp(colorElement());
+  TestRunner.addResult('');
+
+  TestRunner.addResult('Cancel editing by clicking a blank area');
+  mouseDown(listItemElement(), 6); // offset the click to stop eventSender from doing dblclick
+  mouseUp(listItemElement(), 6);
+  TestRunner.addResult('');
+
+  TestRunner.addResult('Create a new property by clicking a blank area');
+  mouseDown(listItemElement());
+  mouseUp(listItemElement());
+  TestRunner.addResult('');
+
+  TestRunner.addResult('Test disabling the property');
+
+  var checkbox = () => listItemElement().querySelector('.enabled-button');
+  mouseDown(checkbox());
+  mouseUp(checkbox());
+  TestRunner.addResult('Enabled: ' + checkbox().checked);
+  TestRunner.addResult('');
+
+
+  TestRunner.addResult('Test enabling the property');
+  mouseDown(checkbox());
+  mouseUp(checkbox());
+  TestRunner.addResult('Enabled: ' + checkbox().checked);
+  TestRunner.addResult('');
+
+
+  TestRunner.completeTest();
+
+  function dumpEditingState() {
+    if (!stylesPane._isEditingStyle) {
+      TestRunner.addResult('Not editing');
+      return;
+    }
+    TestRunner.addResult('Editing: "' + document.deepActiveElement().textContent + '"');
+  }
+
+  function mouseDown(element, offset = 0) {
+    TestRunner.addResult('mouse down: ' + element.tagName + ':' + element.textContent);
+    var rect = element.getBoundingClientRect();
+    eventSender.mouseMoveTo((rect.left + rect.right) / 2 + offset, (rect.top + rect.bottom) / 2);
+    eventSender.mouseDown();
+    dumpEditingState();
+  }
+
+  function mouseUp(element, offset = 0) {
+    TestRunner.addResult('mouse up: ' + element.tagName + ':' + element.textContent);
+    var rect = element.getBoundingClientRect();
+    eventSender.mouseMoveTo((rect.left + rect.right) / 2 + offset, (rect.top + rect.bottom) / 2);
+    eventSender.mouseUp();
+    dumpEditingState();
+  }
+
+})();
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/metadata.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/metadata.vtt
deleted file mode 100644
index 4759463..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/metadata.vtt
+++ /dev/null
@@ -1,38 +0,0 @@
-WEBVTT
-
-00:00:00.000 --> 00:00:01.000
-Lorem ipsum dolor sit amet, 
-
-00:00:02.000 --> 00:00:03.000
-consectetuer adipiscing elit, 
-
-00:00:04.000 --> 00:00:05.000
-sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 
-
-00:00:06.000 --> 00:00:07.000
-Ut wisi enim ad minim veniam, 
-
-00:00:08.000 --> 00:00:09.000
-quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. 
-
-00:00:10.000 --> 00:00:11.000
-Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, 
-
-00:00:12.000 --> 00:00:13.000
-vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
-
-00:00:14.000 --> 00:00:15.000
-dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
-
-00:00:16.000 --> 00:00:17.000
-Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id
-
-00:00:18.000 --> 00:00:19.000
-quod mazim placerat facer possim assum. 
-
-00:00:20.000 --> 00:00:21.000
-Typi non habent claritatem insitam;
-
-00:00:22.000 --> 00:00:23.000
-est usus legentis in iis qui facit eorum claritatem.
-
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc004-no-webvtt.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc004-no-webvtt.vtt
deleted file mode 100644
index 12053b2..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc004-no-webvtt.vtt
+++ /dev/null
@@ -1,10 +0,0 @@
-AWEBVTT FILE
-A file with wrong file header should not be recognized as a webvtt file.
-
-1
-00:00:00.000 --> 00:00:30.500
-Bear is Coming!!!!!
-
-2
-00:00:31.000 --> 00:20:00.500
-I said Bear is coming!!!!
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc005-default-styles.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc005-default-styles.vtt
deleted file mode 100644
index d890ca3..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc005-default-styles.vtt
+++ /dev/null
@@ -1,19 +0,0 @@
-WEBVTT
-
-COMMENT-->
-this is a comment, that will parse as part of the header;
-the STYLE and DEFAULTS below are parsed as invalid cues
-
-STYLE-->
-::cue(.narration) { color: blue; }
-
-DEFAULTS -->
-line:-1 align:middle size:50%
-
-1
-00:00:00.000 --> 00:00:30.500
-Bear is Coming!!!!!
-
-2
-00:00:31.000 --> 00:20:00.500
-I said Bear is coming!!!!
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc005-metadata-area.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc005-metadata-area.vtt
deleted file mode 100644
index 255298ae..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc005-metadata-area.vtt
+++ /dev/null
@@ -1,14 +0,0 @@
-WEBVTT
-This is where metadata would go and these lines should be skipped.
-author = silviapf@google.com
-COMMENT-->
-this is a comment, that will parse as part of the header;
-the STYLE and DEFAULTS below are parsed as invalid cues
-
-1
-00:00:00.000 --> 00:00:30.500
-Bear is Coming!!!!!
-
-2
-00:00:31.000 --> 00:20:00.500
-I said Bear is coming!!!!
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign-bad.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign-bad.vtt
deleted file mode 100644
index 8e7b3b7..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign-bad.vtt
+++ /dev/null
@@ -1,17 +0,0 @@
-WEBVTT
-Invalid vertical direction settings (all settings are ignored).
-
-1
-00:00:00.000 --> 00:00:30.500 vertical:#vertical
-Bear is Coming!!!!!
-Normal rendering - direction setting is ignored.
-
-2
-00:00:31.000 --> 00:01:00.500 vertical:verticallr
-I said Bear is coming!!!!
-Normal rendering - direction setting is ignored.
-
-3
-00:01:01.000 --> 00:02:00.500 vertical:vertical-rl
-I said Bear is coming now!!!!
-Normal rendering - direction setting is ignored.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign-ltr.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign-ltr.vtt
deleted file mode 100644
index 7483836..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign-ltr.vtt
+++ /dev/null
@@ -1,20 +0,0 @@
-WEBVTT
-Valid vertical direction settings.
-
-1
-00:00:00.000 --> 00:00:30.500 vertical:rl
-الدب قادم!!!!!
-يجعل على الجانب الأيمن من المعاينة الفيديو والمتوسطة الانحياز ،
-أسفل إلى أعلى، وتزايد اليسار.
-
-2
-00:00:31.000 --> 00:01:00.500 vertical:lr
-قلت الدب قادم!!
-يجعل على الجانب الأيسر من المعاينة الفيديو والمتوسطة الانحياز ،
-أسفل إلى أعلى، وتنامي اليمين.
-
-3
-00:01:01.000 --> 00:02:00.500 vertical:rl align:start position:0%
-قلت الدب قادم الآن!!
-يجعل على الجانب الأيمن من المعاينة الفيديو ، على حد سواء أسفل محاذاة
-لمربع جديلة والنص داخل النص ، من أسفل إلى أعلى، وتزايد اليسار.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign.vtt
deleted file mode 100644
index f757a36..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc021-valign.vtt
+++ /dev/null
@@ -1,20 +0,0 @@
-WEBVTT
-Valid vertical direction settings.
-
-1
-00:00:00.000 --> 00:00:30.500 vertical:rl
-Bear is Coming!!!!!
-Renders on the right side of the video viewport, middle aligned,
-top to bottom, growing left.
-
-2
-00:00:31.000 --> 00:01:00.500 vertical:lr
-I said Bear is coming!!!!
-Renders on the left side of the video viewport, middle aligned,
-top to bottom, growing right.
-
-3
-00:01:01.000 --> 00:02:00.500 vertical:rl align:start position:0%
-I said Bear is coming now!!!!
-Renders on the right side of the video viewport, top aligned both
-for the cue box and the text within, text from top to bottom, growing left.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc022-entities-wrong.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc022-entities-wrong.vtt
deleted file mode 100644
index f45fee4..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc022-entities-wrong.vtt
+++ /dev/null
@@ -1,15 +0,0 @@
-WEBVTT
-Invalid use of < and > characters.
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-This cue has a less than < character.
-It turns everything from there on into an annotation
-for an empty tag and ends only at the next &gt; or &amp; character.
-
-
-3
-00:01:01.000 --> 00:02:00.500 align:start position:20%
-This cue has a greater than > character.
-Since it's not related to a &lt; character,
-it's just interpreted as text.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc023-markup-bad.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc023-markup-bad.vtt
deleted file mode 100644
index 4ff7add..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc023-markup-bad.vtt
+++ /dev/null
@@ -1,22 +0,0 @@
-WEBVTT
-Cue text has invalid markup of <b>, <i>, <u>, <rt> and <ruby>.  Has a bad effect on the remainder of the cue.
-
-1
-00:00:00.000 --> 00:00:15.000 align:start position:20%
-The following bear starts bold but end is broken:
-<b>Bear</ b> is Coming!!!!!
-
-00:00:15.500 --> 00:00:30.500 align:start position:20%
-The following bear is not in italics but the markup is removed:
-< i>Bear</i> is Coming!!!!!
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-The following bear is not underlined and markup is removed:
-I said < u >Bear</u> is coming!!!!
-
-3
-00:01:01.000 --> 00:01:30.000 align:start position:20%
-The following bear is not ruby annotated and markup is removed:
-I said <ru by>Bear<rt>bear with me</rt></ruby> is coming!!!!
-
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc023-markup.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc023-markup.vtt
deleted file mode 100644
index 252a599..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc023-markup.vtt
+++ /dev/null
@@ -1,22 +0,0 @@
-WEBVTT
-Cues with <b>, <i>, <u>, <rt> and <ruby> tags (all valid).
-
-1
-00:00:00.000 --> 00:00:15.000 align:start position:20%
-The following bear is bold:
-<b>Bear</b> is Coming!!!!!
-
-00:00:15.500 --> 00:00:30.500 align:start position:20%
-The following bear is in italics and has a class of "larger":
-<i.larger>Bear</i> is Coming!!!!!
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-The following bear is underlined even though the element has a blank:
-I said <u >Bear</u> is coming!!!!
-
-3
-00:01:01.000 --> 00:01:30.000 align:start position:20%
-The following bear is ruby annotated:
-I said <ruby>Bear<rt>bear with me</rt></ruby> is coming!!!!
-
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc024-timestamp-bad.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc024-timestamp-bad.vtt
deleted file mode 100644
index 4479cdb7..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc024-timestamp-bad.vtt
+++ /dev/null
@@ -1,17 +0,0 @@
-WEBVTT
-Invalid <timestamp> markup.
-
-1
-00:00:00.000 --> 00:00:30.500 align:start position:20%
-This <00:00:05.000>cue <00:00:10.000>is <00:00:12.000>painted <00:00:08.000>on.
-But since the last two timestamps are out of order, they are ignored.
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-I <00:00:20.000>said <00:00:22.000>Bear <00:00:24.000>is <00:00:26.000>coming!!!!
-All of these timestamps are before the start of the cue, so get ignored.
-
-3
-00:01:01.000 --> 00:02:00.500 align:start position:20%
-I <00:02:05.000>said <00:02:10.000>Bear <00:02:15.000>is <00:02:20.000>coming <00:02:25.000>now!!!!
-All of these timestamps are after the end of the cue, so get ignored.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc024-timestamp.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc024-timestamp.vtt
deleted file mode 100644
index 17d464b..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc024-timestamp.vtt
+++ /dev/null
@@ -1,14 +0,0 @@
-WEBVTT
-Paint-on text in cues with <timestamp> markup.
-
-1
-00:00:00.000 --> 00:00:30.500 align:start position:20%
-This <00:00:05.000>cue <00:00:10.000>is <00:00:15.000>painted <00:00:20.000>on.
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-I <00:00:35.000>said <00:00:40.000>Bear <00:00:45.000>is <00:00:50.000>coming!!!!
-
-3
-00:01:01.000 --> 00:02:00.500 align:start position:20%
-I <00:01:05.000>said <00:01:10.000>Bear <00:01:15.000>is <00:01:20.000>coming <00:01:25.000>now!!!!
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc025-class-bad.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc025-class-bad.vtt
deleted file mode 100644
index 650ea2c4..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc025-class-bad.vtt
+++ /dev/null
@@ -1,17 +0,0 @@
-WEBVTT
-Invalid <c> class markup.
-
-1
-00:00:00.000 --> 00:00:30.500 align:start position:20%
-<c .black>Bear is Coming!!!!!</c>
-The space signified an annotation start.
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-<c.red&large>I said Bear is coming!!!!</c>
-Probably should only allow characters that CSS allows in class names.
-
-3
-00:01:01.000 --> 00:02:00.500 align:start position:20%
-I said <c.9red.upper+case>Bear is coming now</c>!!!!
-Probably should only allow characters that CSS allows in class names.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc025-class.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc025-class.vtt
deleted file mode 100644
index ea3ef62..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc025-class.vtt
+++ /dev/null
@@ -1,14 +0,0 @@
-WEBVTT
-Cue text fragment with <c> class markup is mapped to HTML <span> element with CSS classes.
-
-1
-00:00:00.000 --> 00:00:30.500 align:start position:20%
-<c.black>Bear is Coming!!!!!</c>
-
-2
-00:00:31.000 --> 00:01:00.500 align:start position:20%
-<c.green>I said Bear is coming!!!!</c>
-
-3
-00:01:01.000 --> 00:02:00.500 align:start position:20%
-I said <c.red.uppercase>Bear is coming now</c>!!!!
diff --git a/third_party/WebKit/LayoutTests/media/track/track-helpers.js b/third_party/WebKit/LayoutTests/media/track/track-helpers.js
deleted file mode 100644
index 12e8aff..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-helpers.js
+++ /dev/null
@@ -1,73 +0,0 @@
-function enableAllTextTracks(textTracks) {
-    for (var i = 0; i < textTracks.length; i++) {
-        var track = textTracks[i];
-        if (track.mode == "disabled")
-            track.mode = "hidden";
-    }
-}
-
-function assert_cues_equal(cues, expected) {
-    assert_equals(cues.length, expected.length);
-    for (var i = 0; i < cues.length; i++) {
-        assert_equals(cues[i].id, expected[i].id);
-        assert_equals(cues[i].startTime, expected[i].startTime);
-        assert_equals(cues[i].endTime, expected[i].endTime);
-        assert_equals(cues[i].text, expected[i].text);
-    }
-}
-
-function assert_cues_match(cues, expected) {
-    assert_equals(cues.length, expected.length);
-    for (var i = 0; i < cues.length; i++) {
-        var cue = cues[i];
-        var expectedItem = expected[i];
-        for (var property of Object.getOwnPropertyNames(expectedItem))
-            assert_equals(cue[property], expectedItem[property]);
-    }
-}
-
-function check_cues_from_track(src, func) {
-    async_test(function(t) {
-        var video = document.createElement("video");
-        var trackElement = document.createElement("track");
-        trackElement.src = src;
-        trackElement.default = true;
-        video.appendChild(trackElement);
-
-        trackElement.onload = t.step_func_done(function() {
-            func(trackElement.track);
-        });
-    }, "Check cues from " + src);
-}
-
-function assert_cue_fragment(cue, children) {
-    var fragment = createFragment(children);
-    assert_true(fragment.isEqualNode(cue.getCueAsHTML()));
-}
-
-function assert_cue_fragment_as_textcontent(cue, children) {
-    var fragment = createFragment(children);
-    assert_equals(cue.getCueAsHTML().textContent, fragment.textContent);
-}
-
-function createFragment(children) {
-    var fragment = document.createDocumentFragment();
-    cloneChildrenToFragment(fragment, children);
-    return fragment;
-}
-
-function cloneChildrenToFragment(root, children) {
-    for (var child of children) {
-        var childElement;
-        if (child.type == "text") {
-            childElement = document.createTextNode(child.value);
-        } else {
-            childElement = document.createElement(child.type);
-            var styles = child.style || {};
-            for (var attr of Object.getOwnPropertyNames(styles))
-                childElement[attr] = styles[attr];
-            cloneChildrenToFragment(childElement, child.value);
-        }
-        root.appendChild(childElement);
-    }
-}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu.html b/third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu.html
index 989249c..1562aa2c 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu.html
+++ b/third_party/WebKit/LayoutTests/media/video-controls-track-selection-menu.html
@@ -2,7 +2,6 @@
 <title>Test that we can display a track list menu and select tracks from the list.</title>
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
-<script src="track/track-helpers.js"></script>
 <script src="media-file.js"></script>
 <script src="media-controls.js"></script>
 <!-- Width should be large enough to display closed captions button. -->
@@ -15,10 +14,13 @@
     var video = document.querySelector("video");
 
     var trackElements = document.querySelectorAll("track");
-    for (var i = 0; i < video.textTracks.length; i++)
+    var textTracks = video.textTracks;
+    for (var i = 0; i < textTracks.length; i++) {
         trackElements[i].onload = t.step_func(trackLoaded);
-
-    enableAllTextTracks(video.textTracks);
+        var track = textTracks[i];
+        if (track.mode == "disabled")
+            track.mode = "hidden";
+    }
 
     var numberOfTracksLoaded = 0;
     function trackLoaded() {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.txt
index 2cac404..fb7c272 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.txt
@@ -7,26 +7,6 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutSVGPath polygon id='t3'",
-          "rect": [304, 150, 165, 164],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [31, 150, 165, 164],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [441, 150, 164, 164],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [168, 150, 164, 164],
-          "reason": "style change"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg id='poly'",
           "rect": [168, 150, 164, 163],
           "reason": "style change"
@@ -37,6 +17,26 @@
           "reason": "style change"
         },
         {
+          "object": "LayoutSVGPath polygon id='t3'",
+          "rect": [317, 163, 139, 138],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon",
+          "rect": [44, 163, 139, 138],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon",
+          "rect": [454, 163, 138, 138],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon",
+          "rect": [181, 163, 138, 138],
+          "reason": "style change"
+        },
+        {
           "object": "LayoutSVGContainer use id='t2'",
           "rect": [181, 163, 138, 137],
           "reason": "style change"
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-paintorder-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-paintorder-expected.txt
index bef19c0..db8347e2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-paintorder-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-paintorder-expected.txt
@@ -7,26 +7,6 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutSVGPath polygon id='t3'",
-          "rect": [304, 150, 165, 164],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [31, 150, 165, 164],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [441, 150, 164, 164],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [168, 150, 164, 164],
-          "reason": "style change"
-        },
-        {
           "object": "LayoutSVGContainer use id='t2'",
           "rect": [168, 150, 164, 163],
           "reason": "style change"
@@ -45,6 +25,26 @@
           "object": "LayoutSVGViewportContainer svg id='poly'",
           "rect": [32, 150, 163, 163],
           "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon id='t3'",
+          "rect": [317, 163, 139, 138],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon",
+          "rect": [44, 163, 139, 138],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon",
+          "rect": [454, 163, 138, 138],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutSVGPath polygon",
+          "rect": [181, 163, 138, 138],
+          "reason": "style change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
index 64ab6b6..622b520 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
@@ -28,12 +28,12 @@
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [0, 85, 101, 19],
+          "rect": [0, 85, 100, 19],
           "reason": "geometry"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [0, 85, 101, 19],
+          "rect": [0, 85, 100, 19],
           "reason": "full"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt
index d067e6a2..10e1809 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/text-rescale-expected.txt
@@ -192,31 +192,11 @@
           "reason": "subtree"
         },
         {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [9, 3, 5, 3],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [9, 3, 5, 3],
-          "reason": "subtree"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg",
           "rect": [9, 3, 5, 3],
           "reason": "subtree"
         },
         {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [0, 0, 5, 2],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [0, 0, 5, 2],
-          "reason": "subtree"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg",
           "rect": [0, 0, 5, 2],
           "reason": "subtree"
@@ -227,6 +207,16 @@
           "reason": "subtree"
         },
         {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [9, 3, 4, 3],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [9, 3, 4, 3],
+          "reason": "subtree"
+        },
+        {
           "object": "LayoutBlockFlow P",
           "rect": [6, 3, 4, 2],
           "reason": "subtree"
@@ -247,6 +237,16 @@
           "reason": "subtree"
         },
         {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 0, 1, 1],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 0, 1, 1],
+          "reason": "subtree"
+        },
+        {
           "object": "LayoutText #text",
           "rect": [0, 0, 1, 1],
           "reason": "subtree"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
deleted file mode 100644
index 0a6b91a..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that scripts panel does not create too many source frames.
-
-
-Running: testSourceFramesCount
-Reloading page...
-Page reloaded.
-Too many frames opened: 4
-Visible view: script5.js
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
deleted file mode 100644
index 0a6b91a..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that scripts panel does not create too many source frames.
-
-
-Running: testSourceFramesCount
-Reloading page...
-Page reloaded.
-Too many frames opened: 4
-Visible view: script5.js
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
deleted file mode 100644
index 0a6b91a..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that scripts panel does not create too many source frames.
-
-
-Running: testSourceFramesCount
-Reloading page...
-Page reloaded.
-Too many frames opened: 4
-Visible view: script5.js
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/devtools/tracing/console-timeline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/devtools/tracing/console-timeline-expected.txt
deleted file mode 100644
index 70edf10..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/devtools/tracing/console-timeline-expected.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-Tests console.timeline and timelineEnd commands.
-
-
-Running: testStartStopTimeline
-Main._lateInitialization
-timestamp 0
-Timeline 'one'
-timestamp 1
-Timeline 'one'
-timestamp 2
-
-Running: testStartStopMultiple
-error: Event Timeline 'one' has already been started
-error: Event Timeline 'two' has already been started
-timestamp 0
-Timeline 'one'
-timestamp 1
-Timeline 'one'
-Timeline 'two'
-Timeline 'two'
-Timeline 'two'
-timestamp 2
-Timeline 'one'
-timestamp 3
-Timeline 'two'
-timestamp 4
-Timeline 'one'
-timestamp 5
-
-Running: testStartMultipleStopInsideEvals
-timestamp 0
-Timeline 'one'
-timestamp 1
-Timeline 'two'
-timestamp 2
-timestamp 3
-Timeline 'two'
-timestamp 4
-timestamp 5
-Timeline 'one'
-timestamp 6 - FAIL
-
-Running: testStopUnknown
-timestamp 0
-Timeline 'one'
-timestamp 1
-Timeline 'two'
-timestamp 2
-Timeline 'one'
-timestamp 3
-
-Running: testStartFromPanel
-timestamp 0
-Timeline 'one'
-timestamp 1
-Timeline 'one'
-timestamp 2
-
-Running: testStopFromPanel
-timestamp 0
-Timeline 'one'
-timestamp 1
-Timeline 'two'
-timestamp 2
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
index 390855d..eb94fee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
@@ -28,12 +28,12 @@
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [0, 86, 101, 18],
+          "rect": [0, 86, 100, 18],
           "reason": "geometry"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [0, 86, 101, 18],
+          "rect": [0, 86, 100, 18],
           "reason": "full"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt
index db6a8ff..e87bafcb 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/text-rescale-expected.txt
@@ -162,16 +162,6 @@
           "reason": "subtree"
         },
         {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [9, 3, 5, 2],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [9, 3, 5, 2],
-          "reason": "subtree"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg",
           "rect": [9, 3, 5, 2],
           "reason": "subtree"
@@ -182,6 +172,16 @@
           "reason": "subtree"
         },
         {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [9, 3, 4, 2],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [9, 3, 4, 2],
+          "reason": "subtree"
+        },
+        {
           "object": "LayoutBlockFlow P",
           "rect": [6, 3, 4, 2],
           "reason": "subtree"
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/devtools/console/console-links-in-errors-with-trace-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/devtools/console/console-links-in-errors-with-trace-expected.txt
deleted file mode 100644
index 0e5fc2c6..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/devtools/console/console-links-in-errors-with-trace-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Test that relative links in traces open in the sources panel.
-
-Clicking link source3.js:3
-Panel sources was opened.
-
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
deleted file mode 100644
index 0a6b91a..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/source-frame-count-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that scripts panel does not create too many source frames.
-
-
-Running: testSourceFramesCount
-Reloading page...
-Page reloaded.
-Too many frames opened: 4
-Visible view: script5.js
-
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
index 4a273e3a..7cdb518 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
@@ -19,7 +19,12 @@
         {
           "object": "LayoutSVGViewportContainer svg id='inner'",
           "rect": [0, 0, 200, 200],
-          "reason": "disappeared"
+          "reason": "paint property change"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='inner'",
+          "rect": [0, 0, 100, 100],
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
index 443196f9..964dc47 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
@@ -17,14 +17,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutSVGRoot svg",
-          "rect": [0, 0, 100, 100],
-          "reason": "appeared"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg id='s'",
           "rect": [0, 0, 100, 100],
-          "reason": "disappeared"
+          "reason": "paint property change"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
index 8b6e879..a33b8a9 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
@@ -27,8 +27,13 @@
           "reason": "appeared"
         },
         {
+          "object": "LayoutSVGViewportContainer svg id='inner'",
+          "rect": [100, 0, 100, 200],
+          "reason": "incremental"
+        },
+        {
           "object": "InlineTextBox 'right-aligned text'",
-          "rect": [0, 85, 101, 19],
+          "rect": [0, 85, 100, 19],
           "reason": "disappeared"
         },
         {
@@ -39,6 +44,11 @@
         {
           "object": "LayoutSVGRect rect",
           "rect": [180, 60, 20, 20],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [180, 60, 20, 20],
           "reason": "full"
         },
         {
@@ -49,6 +59,11 @@
         {
           "object": "LayoutSVGRect rect",
           "rect": [80, 60, 20, 20],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [80, 60, 20, 20],
           "reason": "full"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/repaint-paintorder-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/repaint-paintorder-expected.txt
index f1a4c92..0e3665be 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/repaint-paintorder-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/repaint-paintorder-expected.txt
@@ -18,22 +18,22 @@
       "paintInvalidations": [
         {
           "object": "LayoutSVGPath polygon id='t3'",
-          "rect": [304, 150, 165, 164],
+          "rect": [317, 163, 139, 138],
           "reason": "style change"
         },
         {
           "object": "LayoutSVGPath polygon",
-          "rect": [31, 150, 165, 164],
+          "rect": [44, 163, 139, 138],
           "reason": "style change"
         },
         {
           "object": "LayoutSVGPath polygon",
-          "rect": [441, 150, 164, 164],
+          "rect": [454, 163, 138, 138],
           "reason": "style change"
         },
         {
           "object": "LayoutSVGPath polygon",
-          "rect": [168, 150, 164, 164],
+          "rect": [181, 163, 138, 138],
           "reason": "style change"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/text-rescale-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/text-rescale-expected.txt
index 80d6e17..995a5f8 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/text-rescale-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/text-rescale-expected.txt
@@ -43,7 +43,7 @@
         },
         {
           "object": "LayoutSVGViewportContainer svg",
-          "rect": [9, 3, 5, 3],
+          "rect": [9, 3, 4, 3],
           "reason": "paint property change"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/use-clipped-hit-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/use-clipped-hit-expected.txt
new file mode 100644
index 0000000..8c72df9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/use-clipped-hit-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "InlineTextBox 'Unknown'",
+          "rect": [90, 115, 64, 19],
+          "reason": "disappeared"
+        },
+        {
+          "object": "InlineTextBox 'Passed'",
+          "rect": [90, 115, 44, 19],
+          "reason": "appeared"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGText text id='status'",
+      "reason": "full"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "appeared"
+    },
+    {
+      "object": "InlineTextBox 'Passed'",
+      "reason": "appeared"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/zoom-coords-viewattr-01-b-expected.png b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/zoom-coords-viewattr-01-b-expected.png
new file mode 100644
index 0000000..7e29399
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/zoom-coords-viewattr-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/core/css/CSSSegmentedFontFace.h b/third_party/WebKit/Source/core/css/CSSSegmentedFontFace.h
index 2da41b7..f9c4fab 100644
--- a/third_party/WebKit/Source/core/css/CSSSegmentedFontFace.h
+++ b/third_party/WebKit/Source/core/css/CSSSegmentedFontFace.h
@@ -32,7 +32,6 @@
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/HashMap.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
 
diff --git a/third_party/WebKit/Source/core/css/CSSSelector.cpp b/third_party/WebKit/Source/core/css/CSSSelector.cpp
index 1bcbe07..048a26c3 100644
--- a/third_party/WebKit/Source/core/css/CSSSelector.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSelector.cpp
@@ -1001,8 +1001,8 @@
 }
 
 template <typename Functor>
-static bool ForEachTagHistory(const Functor& functor,
-                              const CSSSelector& selector) {
+static bool ForAnyInTagHistory(const Functor& functor,
+                               const CSSSelector& selector) {
   for (const CSSSelector* current = &selector; current;
        current = current->TagHistory()) {
     if (functor(*current))
@@ -1010,7 +1010,7 @@
     if (const CSSSelectorList* selector_list = current->SelectorList()) {
       for (const CSSSelector* sub_selector = selector_list->First();
            sub_selector; sub_selector = CSSSelectorList::Next(*sub_selector)) {
-        if (ForEachTagHistory(functor, *sub_selector))
+        if (ForAnyInTagHistory(functor, *sub_selector))
           return true;
       }
     }
@@ -1020,7 +1020,7 @@
 }
 
 bool CSSSelector::HasContentPseudo() const {
-  return ForEachTagHistory(
+  return ForAnyInTagHistory(
       [](const CSSSelector& selector) -> bool {
         return selector.RelationIsAffectedByPseudoContent();
       },
@@ -1028,7 +1028,7 @@
 }
 
 bool CSSSelector::HasSlottedPseudo() const {
-  return ForEachTagHistory(
+  return ForAnyInTagHistory(
       [](const CSSSelector& selector) -> bool {
         return selector.GetPseudoType() == CSSSelector::kPseudoSlotted;
       },
@@ -1036,7 +1036,7 @@
 }
 
 bool CSSSelector::HasDeepCombinatorOrShadowPseudo() const {
-  return ForEachTagHistory(
+  return ForAnyInTagHistory(
       [](const CSSSelector& selector) -> bool {
         return selector.Relation() == CSSSelector::kShadowDeep ||
                selector.Relation() == CSSSelector::kShadowPiercingDescendant ||
@@ -1046,7 +1046,7 @@
 }
 
 bool CSSSelector::NeedsUpdatedDistribution() const {
-  return ForEachTagHistory(
+  return ForAnyInTagHistory(
       [](const CSSSelector& selector) -> bool {
         return selector.RelationIsAffectedByPseudoContent() ||
                selector.GetPseudoType() == CSSSelector::kPseudoSlotted ||
diff --git a/third_party/WebKit/Source/core/css/SelectorQuery.cpp b/third_party/WebKit/Source/core/css/SelectorQuery.cpp
index 97ee86e..62cee6e 100644
--- a/third_party/WebKit/Source/core/css/SelectorQuery.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorQuery.cpp
@@ -94,12 +94,6 @@
   }
 };
 
-// TODO(esprehn): Move this to Element and update callers elsewhere.
-inline bool HasClassName(const Element& element,
-                         const AtomicString& class_name) {
-  return element.HasClass() && element.ClassNames().Contains(class_name);
-}
-
 inline bool SelectorMatches(const CSSSelector& selector,
                             Element& element,
                             const ContainerNode& root_node) {
@@ -159,7 +153,7 @@
     typename SelectorQueryTrait::OutputType& output) {
   for (Element& element : ElementTraversal::DescendantsOf(root_node)) {
     QUERY_STATS_INCREMENT(fast_class);
-    if (!HasClassName(element, class_name))
+    if (!element.HasClassName(class_name))
       continue;
     if (selector && !SelectorMatches(*selector, element, root_node))
       continue;
@@ -207,7 +201,7 @@
 
   for (Element* element = &ToElement(root_node); element;
        element = element->parentElement()) {
-    if (HasClassName(*element, class_name))
+    if (element->HasClassName(class_name))
       return true;
   }
   return false;
@@ -243,7 +237,7 @@
       Element* element = ElementTraversal::FirstWithin(root_node);
       while (element) {
         QUERY_STATS_INCREMENT(fast_class);
-        if (HasClassName(*element, class_name)) {
+        if (element->HasClassName(class_name)) {
           ExecuteForTraverseRoot<SelectorQueryTrait>(*element, root_node,
                                                      output);
           if (SelectorQueryTrait::kShouldOnlyMatchFirstElement &&
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h
index 07870f5..fad0410 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.h
@@ -39,7 +39,6 @@
   FloatSize ElementSize(const FloatSize& default_object_size) const final;
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) final {
     return GetImage();
   }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index bba93fd..4f50b7d 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -124,7 +124,6 @@
 #include "core/layout/AdjustForAbsoluteZoom.h"
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutBoxItem.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
@@ -654,11 +653,9 @@
   if (!box_to_scroll)
     return;
 
-  ScrollResult result = LayoutBoxItem(box_to_scroll)
-                            .EnclosingBox()
-                            .Scroll(ScrollGranularity(static_cast<int>(
-                                        scroll_state.deltaGranularity())),
-                                    delta);
+  ScrollResult result = box_to_scroll->EnclosingBox()->Scroll(
+      ScrollGranularity(static_cast<int>(scroll_state.deltaGranularity())),
+      delta);
 
   if (!result.DidScroll())
     return;
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index a6cc00ef..733596b 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -784,6 +784,7 @@
   bool HasID() const;
   bool HasClass() const;
   const SpaceSplitString& ClassNames() const;
+  bool HasClassName(const AtomicString& class_name) const;
 
   ScrollOffset SavedLayerScrollOffset() const;
   void SetSavedLayerScrollOffset(const ScrollOffset&);
@@ -1188,6 +1189,10 @@
   return GetElementData()->ClassNames();
 }
 
+inline bool Element::HasClassName(const AtomicString& class_name) const {
+  return HasClass() && ClassNames().Contains(class_name);
+}
+
 inline bool Element::HasID() const {
   return GetElementData() && GetElementData()->HasID();
 }
diff --git a/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp b/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
index ca47d84..8ff06ad 100644
--- a/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
+++ b/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
@@ -31,7 +31,6 @@
 #include "core/layout/LayoutObjectInlines.h"
 #include "core/layout/LayoutText.h"
 #include "core/layout/LayoutTextFragment.h"
-#include "core/layout/api/LayoutTextFragmentItem.h"
 #include "platform/wtf/text/WTFString.h"
 #include "platform/wtf/text/icu/UnicodeIcu.h"
 
@@ -218,19 +217,18 @@
        child = child->NextSibling()) {
     if (!child->IsText() || !ToLayoutText(child)->IsTextFragment())
       continue;
-    LayoutTextFragmentItem child_fragment =
-        LayoutTextFragmentItem(ToLayoutTextFragment(child));
-    if (child_fragment.GetFirstLetterPseudoElement() != this)
+    LayoutTextFragment* child_fragment = ToLayoutTextFragment(child);
+    if (child_fragment->GetFirstLetterPseudoElement() != this)
       continue;
 
-    child_fragment.SetTextFragment(old_text.Impl()->Substring(0, length), 0,
-                                   length);
-    child_fragment.DirtyLineBoxes();
+    child_fragment->SetTextFragment(old_text.Impl()->Substring(0, length), 0,
+                                    length);
+    child_fragment->DirtyLineBoxes();
 
     // Make sure the first-letter layoutObject is set to require a layout as it
     // needs to re-create the line boxes. The remaining text layoutObject
     // will be marked by the LayoutText::setText.
-    child_fragment.SetNeedsLayoutAndPrefWidthsRecalc(
+    child_fragment->SetNeedsLayoutAndPrefWidthsRecalc(
         LayoutInvalidationReason::kTextChanged);
     break;
   }
diff --git a/third_party/WebKit/Source/core/dom/ScriptedAnimationController.h b/third_party/WebKit/Source/core/dom/ScriptedAnimationController.h
index bea49754..9debc98 100644
--- a/third_party/WebKit/Source/core/dom/ScriptedAnimationController.h
+++ b/third_party/WebKit/Source/core/dom/ScriptedAnimationController.h
@@ -30,7 +30,6 @@
 #include "core/dom/FrameRequestCallbackCollection.h"
 #include "platform/bindings/TraceWrapperMember.h"
 #include "platform/heap/Handle.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/AtomicString.h"
 #include "platform/wtf/text/StringImpl.h"
diff --git a/third_party/WebKit/Source/core/dom/Text.cpp b/third_party/WebKit/Source/core/dom/Text.cpp
index 7fab404a..2f736e4 100644
--- a/third_party/WebKit/Source/core/dom/Text.cpp
+++ b/third_party/WebKit/Source/core/dom/Text.cpp
@@ -36,7 +36,6 @@
 #include "core/layout/LayoutText.h"
 #include "core/layout/LayoutTextCombine.h"
 #include "core/layout/LayoutTextFragment.h"
-#include "core/layout/api/LayoutTextItem.h"
 #include "core/layout/svg/LayoutSVGInlineText.h"
 #include "core/svg/SVGForeignObjectElement.h"
 #include "core/svg_names.h"
@@ -383,7 +382,7 @@
 }
 
 void Text::RecalcTextStyle(StyleRecalcChange change) {
-  if (LayoutTextItem layout_item = LayoutTextItem(GetLayoutObject())) {
+  if (LayoutText* layout_text = GetLayoutObject()) {
     if (change != kNoChange || NeedsStyleRecalc()) {
       scoped_refptr<ComputedStyle> new_style =
           GetDocument().EnsureStyleResolver().StyleForText(this);
@@ -396,10 +395,10 @@
         SetNeedsReattachLayoutTree();
         return;
       }
-      layout_item.SetStyle(std::move(new_style));
+      layout_text->SetStyle(std::move(new_style));
     }
     if (NeedsStyleRecalc())
-      layout_item.SetText(DataImpl());
+      layout_text->SetText(DataImpl());
     ClearNeedsStyleRecalc();
   } else if (NeedsStyleRecalc() || NeedsWhitespaceLayoutObject()) {
     SetNeedsReattachLayoutTree();
diff --git a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp
index 5c658f0..016210878 100644
--- a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp
+++ b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp
@@ -32,8 +32,6 @@
 #include "core/frame/Settings.h"
 #include "core/layout/LayoutBlock.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutBlockItem.h"
-#include "core/layout/api/LayoutItem.h"
 #include "core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "core/paint/PaintInfo.h"
@@ -73,27 +71,25 @@
                           : layout_object->ContainingBlock();
 }
 
-static LayoutRect MapCaretRectToCaretPainter(
-    const LayoutBlockItem& caret_painter_item,
-    const LocalCaretRect& caret_rect) {
+static LayoutRect MapCaretRectToCaretPainter(const LayoutBlock* caret_block,
+                                             const LocalCaretRect& caret_rect) {
   // FIXME: This shouldn't be called on un-rooted subtrees.
   // FIXME: This should probably just use mapLocalToAncestor.
   // Compute an offset between the caretLayoutItem and the caretPainterItem.
 
-  // TODO(layout-dev): We should allow constructing a "const layout item" from a
-  // |const LayoutObject*| that allows using all const functions.
-  LayoutItem caret_layout_item =
-      LayoutItem(const_cast<LayoutObject*>(caret_rect.layout_object));
-  DCHECK(caret_layout_item.IsDescendantOf(caret_painter_item));
+  LayoutObject* caret_layout_object =
+      const_cast<LayoutObject*>(caret_rect.layout_object);
+  DCHECK(caret_layout_object->IsDescendantOf(caret_block));
 
   LayoutRect result_rect = caret_rect.rect;
-  caret_painter_item.FlipForWritingMode(result_rect);
-  while (caret_layout_item != caret_painter_item) {
-    LayoutItem container_item = caret_layout_item.Container();
-    if (container_item.IsNull())
+  caret_block->FlipForWritingMode(result_rect);
+  while (caret_layout_object != caret_block) {
+    LayoutObject* container_object = caret_layout_object->Container();
+    if (!container_object)
       return LayoutRect();
-    result_rect.Move(caret_layout_item.OffsetFromContainer(container_item));
-    caret_layout_item = container_item;
+    result_rect.Move(
+        caret_layout_object->OffsetFromContainer(container_object));
+    caret_layout_object = container_object;
   }
   return result_rect;
 }
@@ -110,9 +106,9 @@
 
   // Get the layoutObject that will be responsible for painting the caret
   // (which is either the layoutObject we just found, or one of its containers).
-  const LayoutBlockItem caret_painter_item =
-      LayoutBlockItem(CaretLayoutBlock(caret_position.AnchorNode()));
-  return MapCaretRectToCaretPainter(caret_painter_item, caret_rect);
+  const LayoutBlock* caret_block =
+      CaretLayoutBlock(caret_position.AnchorNode());
+  return MapCaretRectToCaretPainter(caret_block, caret_rect);
 }
 
 void CaretDisplayItemClient::ClearPreviousVisualRect(const LayoutBlock& block) {
diff --git a/third_party/WebKit/Source/core/editing/EditingStrategy.cpp b/third_party/WebKit/Source/core/editing/EditingStrategy.cpp
index 0e9205ed..eb8207eb 100644
--- a/third_party/WebKit/Source/core/editing/EditingStrategy.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingStrategy.cpp
@@ -23,35 +23,6 @@
   return LastOffsetForEditing(&node);
 }
 
-// TODO(yosin): We should move "isEmptyNonEditableNodeInEditable()" to
-// "EditingUtilities.cpp"
-// |isEmptyNonEditableNodeInEditable()| is introduced for fixing
-// http://crbug.com/428986.
-static bool IsEmptyNonEditableNodeInEditable(const Node& node) {
-  // Editability is defined the DOM tree rather than the flat tree. For example:
-  // DOM:
-  //   <host>
-  //     <span>unedittable</span>
-  //     <shadowroot><div ce><content /></div></shadowroot>
-  //   </host>
-  //
-  // Flat Tree:
-  //   <host><div ce><span1>unedittable</span></div></host>
-  // e.g. editing/shadow/breaking-editing-boundaries.html
-  return !NodeTraversal::HasChildren(node) && !HasEditableStyle(node) &&
-         node.parentNode() && HasEditableStyle(*node.parentNode());
-}
-
-// TODO(yosin): We should move "editingIgnoresContent()" to
-// "EditingUtilities.cpp"
-// TODO(yosin): We should not use |isEmptyNonEditableNodeInEditable()| in
-// |editingIgnoresContent()| since |isEmptyNonEditableNodeInEditable()|
-// requires clean layout tree.
-bool EditingIgnoresContent(const Node& node) {
-  return !node.CanContainRangeEndPoint() ||
-         IsEmptyNonEditableNodeInEditable(node);
-}
-
 template <typename Traversal>
 int EditingAlgorithm<Traversal>::LastOffsetForEditing(const Node* node) {
   DCHECK(node);
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index eddb870c2..129e4db 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -2199,4 +2199,29 @@
   }
 }
 
+// |IsEmptyNonEditableNodeInEditable()| is introduced for fixing
+// http://crbug.com/428986.
+static bool IsEmptyNonEditableNodeInEditable(const Node& node) {
+  // Editability is defined the DOM tree rather than the flat tree. For example:
+  // DOM:
+  //   <host>
+  //     <span>unedittable</span>
+  //     <shadowroot><div ce><content /></div></shadowroot>
+  //   </host>
+  //
+  // Flat Tree:
+  //   <host><div ce><span1>unedittable</span></div></host>
+  // e.g. editing/shadow/breaking-editing-boundaries.html
+  return !NodeTraversal::HasChildren(node) && !HasEditableStyle(node) &&
+         node.parentNode() && HasEditableStyle(*node.parentNode());
+}
+
+// TODO(yosin): We should not use |IsEmptyNonEditableNodeInEditable()| in
+// |EditingIgnoresContent()| since |IsEmptyNonEditableNodeInEditable()|
+// requires clean layout tree.
+bool EditingIgnoresContent(const Node& node) {
+  return !node.CanContainRangeEndPoint() ||
+         IsEmptyNonEditableNodeInEditable(node);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index 746a0af..268cc4d 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -223,8 +223,21 @@
     return false;
   const Position& position =
       selection.ComputeVisibleSelectionInDOMTree().Start();
-  return !InSameLine(PositionWithAffinity(position, TextAffinity::kUpstream),
-                     PositionWithAffinity(position, TextAffinity::kDownstream));
+  if (InSameLine(PositionWithAffinity(position, TextAffinity::kUpstream),
+                 PositionWithAffinity(position, TextAffinity::kDownstream)))
+    return false;
+
+  // Only when the previous character is a space to avoid undesired side
+  // effects. There are cases where a new line is desired even if the previous
+  // character is not a space, but typing another space will do.
+  Position prev =
+      PreviousPositionOf(position, PositionMoveType::kGraphemeCluster);
+  const Node* prev_node = prev.ComputeContainerNode();
+  if (!prev_node || !prev_node->IsTextNode())
+    return false;
+  int prev_offset = prev.ComputeOffsetInContainerNode();
+  UChar prev_char = ToText(prev_node)->data()[prev_offset];
+  return prev_char == kSpaceCharacter;
 }
 
 bool Editor::HandleTextEvent(TextEvent* event) {
@@ -571,8 +584,7 @@
 
   if (layout_object->IsCanvas()) {
     return ToHTMLCanvasElement(const_cast<Node&>(node))
-        .CopiedImage(kFrontBuffer, kPreferNoAcceleration,
-                     kSnapshotReasonCopyToClipboard);
+        .CopiedImage(kFrontBuffer, kPreferNoAcceleration);
   }
 
   if (layout_object->IsImage()) {
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
index 2a655cd7..0223f21 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -58,7 +58,6 @@
 #include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutItem.h"
 #include "core/layout/api/LineLayoutAPIShim.h"
 #include "core/layout/api/LineLayoutItem.h"
 #include "core/layout/line/InlineIterator.h"
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsParagraph.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsParagraph.cpp
index 5c56721..0bfc5331 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnitsParagraph.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnitsParagraph.cpp
@@ -34,7 +34,6 @@
 #include "core/editing/EphemeralRange.h"
 #include "core/editing/VisiblePosition.h"
 #include "core/layout/LayoutText.h"
-#include "core/layout/api/LayoutItem.h"
 
 namespace blink {
 
@@ -85,24 +84,24 @@
         break;
     }
 
-    const LayoutItem layout_item =
-        LayoutItem(previous_node_iterator->GetLayoutObject());
-    if (layout_item.IsNull()) {
+    const LayoutObject* layout_object =
+        previous_node_iterator->GetLayoutObject();
+    if (!layout_object) {
       previous_node_iterator =
           Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
       continue;
     }
-    const ComputedStyle& style = layout_item.StyleRef();
+    const ComputedStyle& style = layout_object->StyleRef();
     if (style.Visibility() != EVisibility::kVisible) {
       previous_node_iterator =
           Strategy::PreviousPostOrder(*previous_node_iterator, start_block);
       continue;
     }
 
-    if (layout_item.IsBR() || IsEnclosingBlock(previous_node_iterator))
+    if (layout_object->IsBR() || IsEnclosingBlock(previous_node_iterator))
       break;
 
-    if (layout_item.IsText() &&
+    if (layout_object->IsText() &&
         ToLayoutText(previous_node_iterator->GetLayoutObject())
             ->ResolvedTextLength()) {
       SECURITY_DCHECK(previous_node_iterator->IsTextNode());
diff --git a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
index c3be6df..c71b06c 100644
--- a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
+++ b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
@@ -39,7 +39,7 @@
 #include "core/frame/VisualViewport.h"
 #include "core/input/Touch.h"
 #include "core/input/TouchList.h"
-#include "core/layout/api/LayoutItem.h"
+#include "core/layout/LayoutObject.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "platform/KeyboardCodes.h"
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
index 88ff269..473bc47 100644
--- a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
@@ -114,7 +114,7 @@
          method == "Debugger.setBreakpointByUrl" ||
          method == "Debugger.removeBreakpoint" ||
          method == "Debugger.setBreakpointsActive" ||
-         method == "Performance.getMetrics";
+         method == "Performance.getMetrics" || method == "Page.crash";
 }
 
 }  // namespace
@@ -233,6 +233,10 @@
                                const String& method,
                                const String& message) override {
     DCHECK(ShouldInterruptForMethod(method));
+    // Crash renderer.
+    if (method == "Page.crash")
+      CHECK(false);
+
     MainThreadDebugger::InterruptMainThreadAndRun(
         CrossThreadBind(&WebDevToolsAgentImpl::DispatchMessageFromFrontend,
                         agent_, session_id_, method, message));
diff --git a/third_party/WebKit/Source/core/exported/WebDocument.cpp b/third_party/WebKit/Source/core/exported/WebDocument.cpp
index 4d4f3d1..435e4f0 100644
--- a/third_party/WebKit/Source/core/exported/WebDocument.cpp
+++ b/third_party/WebKit/Source/core/exported/WebDocument.cpp
@@ -52,7 +52,6 @@
 #include "core/html/forms/HTMLFormElement.h"
 #include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/loader/DocumentLoader.h"
 #include "platform/bindings/ScriptState.h"
 #include "platform/weborigin/SecurityOrigin.h"
diff --git a/third_party/WebKit/Source/core/exported/WebPagePopupImpl.cpp b/third_party/WebKit/Source/core/exported/WebPagePopupImpl.cpp
index ea59669..c9ccc7c 100644
--- a/third_party/WebKit/Source/core/exported/WebPagePopupImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPagePopupImpl.cpp
@@ -45,7 +45,6 @@
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/loader/EmptyClients.h"
 #include "core/loader/FrameLoadRequest.h"
 #include "core/page/FocusController.h"
diff --git a/third_party/WebKit/Source/core/fetch/README.md b/third_party/WebKit/Source/core/fetch/README.md
new file mode 100644
index 0000000..79bab9c1
--- /dev/null
+++ b/third_party/WebKit/Source/core/fetch/README.md
@@ -0,0 +1,6 @@
+The implementation of the [Fetch API](https://fetch.spec.whatwg.org/#fetch-api).
+
+Fetching/loading code is divided into:
+- core/fetch: Fetch API
+- core/loader: high-level fetching
+- platform/loader/fetch: low-level fetching
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 08124a82..963f92b3 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -73,8 +73,6 @@
 #include "core/layout/ScrollAlignment.h"
 #include "core/layout/TextAutosizer.h"
 #include "core/layout/TracedLayoutObject.h"
-#include "core/layout/api/LayoutBoxModel.h"
-#include "core/layout/api/LayoutItem.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
@@ -1102,8 +1100,8 @@
       // We need to ensure that we mark up all layoutObjects up to the
       // LayoutView for paint invalidation. This simplifies our code as we
       // just always do a full tree walk.
-      if (LayoutItem container = LayoutItem(root->Container()))
-        container.SetMayNeedPaintInvalidation();
+      if (LayoutObject* container = root->Container())
+        container->SetMayNeedPaintInvalidation();
     }
     layout_subtree_root_list_.Clear();
   } else {
@@ -1792,11 +1790,10 @@
   for (const auto& viewport_constrained_object :
        *viewport_constrained_objects_) {
     LayoutObject* layout_object = viewport_constrained_object;
-    LayoutItem layout_item = LayoutItem(layout_object);
-    DCHECK(layout_item.Style()->HasViewportConstrainedPosition() ||
-           layout_item.Style()->HasStickyConstrainedPosition());
-    DCHECK(layout_item.HasLayer());
-    PaintLayer* layer = LayoutBoxModel(layout_item).Layer();
+    DCHECK(layout_object->Style()->HasViewportConstrainedPosition() ||
+           layout_object->Style()->HasStickyConstrainedPosition());
+    DCHECK(layout_object->HasLayer());
+    PaintLayer* layer = ToLayoutBoxModelObject(layout_object)->Layer();
 
     if (layer->IsPaintInvalidationContainer())
       continue;
@@ -1805,8 +1802,8 @@
       continue;
 
     // invalidate even if there is an ancestor with a filter that moves pixels.
-    layout_item
-        .SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
+    layout_object
+        ->SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
 
     TRACE_EVENT_INSTANT1(
         TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index f941ab2c..fa36f16 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -58,7 +58,6 @@
 #include "platform/wtf/AutoReset.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/HashSet.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/ShapeProperties.h"
 #include "public/platform/WebDisplayMode.h"
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameClientImpl.cpp b/third_party/WebKit/Source/core/frame/RemoteFrameClientImpl.cpp
index eb975fb0..4c7ffea 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameClientImpl.cpp
@@ -14,7 +14,6 @@
 #include "core/frame/RemoteFrameView.h"
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/layout/LayoutEmbeddedContent.h"
-#include "core/layout/api/LayoutItem.h"
 #include "platform/exported/WrappedResourceRequest.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/weborigin/SecurityOrigin.h"
diff --git a/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp b/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp
index a2767e3..e55cd8f 100644
--- a/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp
+++ b/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp
@@ -45,7 +45,6 @@
 #include "core/inspector/ConsoleMessage.h"
 #include "core/layout/LayoutBlockFlow.h"
 #include "core/layout/LayoutFullScreen.h"
-#include "core/layout/api/LayoutFullScreenItem.h"
 #include "core/page/ChromeClient.h"
 #include "core/svg/SVGSVGElement.h"
 #include "platform/ScopedOrientationChangeIndicator.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 57ca614..ed09115 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -412,8 +412,7 @@
       // Push a frame
       double start_time = WTF::CurrentTimeTicksInSeconds();
       scoped_refptr<StaticBitmapImage> image =
-          canvas2d_buffer_->NewImageSnapshot(kPreferAcceleration,
-                                             kSnapshotReasonLowLatencyFrame);
+          canvas2d_buffer_->NewImageSnapshot(kPreferAcceleration);
       FloatRect src_rect(0, 0, Size().Width(), Size().Height());
       dirty_rect_.Intersect(src_rect);
       IntRect int_dirty = EnclosingIntRect(dirty_rect_);
@@ -629,9 +628,8 @@
 
   if (listener_needs_new_frame_capture) {
     SourceImageStatus status;
-    scoped_refptr<Image> source_image = GetSourceImageForCanvas(
-        &status, kPreferNoAcceleration, kSnapshotReasonCanvasListenerCapture,
-        FloatSize());
+    scoped_refptr<Image> source_image =
+        GetSourceImageForCanvas(&status, kPreferNoAcceleration, FloatSize());
     if (status != kNormalSourceImageStatus)
       return;
     sk_sp<SkImage> image =
@@ -690,7 +688,7 @@
               : SkBlendMode::kSrc;
       FloatRect src_rect = FloatRect(FloatPoint(), FloatSize(Size()));
       scoped_refptr<StaticBitmapImage> snapshot =
-          NewImageSnapshot(kPreferAcceleration, kSnapshotReasonPaint);
+          NewImageSnapshot(kPreferAcceleration);
       if (snapshot) {
         // GraphicsContext cannot handle gpu resource serialization.
         snapshot = snapshot->MakeUnaccelerated();
@@ -742,8 +740,7 @@
 
 scoped_refptr<StaticBitmapImage> HTMLCanvasElement::ToStaticBitmapImage(
     SourceDrawingBuffer source_buffer,
-    AccelerationHint hint,
-    SnapshotReason reason) const {
+    AccelerationHint hint) const {
   if (size_.IsEmpty())
     return nullptr;
   scoped_refptr<StaticBitmapImage> image_bitmap = nullptr;
@@ -751,7 +748,7 @@
     if (context_->CreationAttributes().premultipliedAlpha()) {
       context_->PaintRenderingResultsToCanvas(source_buffer);
       if (webgl_buffer_)
-        image_bitmap = webgl_buffer_->NewImageSnapshot(hint, reason);
+        image_bitmap = webgl_buffer_->NewImageSnapshot(hint);
     } else {
       scoped_refptr<Uint8Array> data_array =
           context_->PaintRenderingResultsToDataArray(source_buffer);
@@ -769,7 +766,7 @@
   } else if (context_ || PlaceholderFrame()) {
     DCHECK(Is2d() || PlaceholderFrame());
     if (canvas2d_buffer_) {
-      image_bitmap = canvas2d_buffer_->NewImageSnapshot(hint, reason);
+      image_bitmap = canvas2d_buffer_->NewImageSnapshot(hint);
     } else if (PlaceholderFrame()) {
       DCHECK(PlaceholderFrame()->OriginClean());
       image_bitmap = PlaceholderFrame();
@@ -811,8 +808,8 @@
     NOTREACHED();
   }
 
-  scoped_refptr<StaticBitmapImage> image_bitmap = ToStaticBitmapImage(
-      source_buffer, kPreferNoAcceleration, kSnapshotReasonToBlob);
+  scoped_refptr<StaticBitmapImage> image_bitmap =
+      ToStaticBitmapImage(source_buffer, kPreferNoAcceleration);
   if (image_bitmap) {
     std::unique_ptr<ImageDataBuffer> data_buffer =
         ImageDataBuffer::Create(image_bitmap);
@@ -873,8 +870,8 @@
       mime_type, ImageEncoderUtils::kEncodeReasonToBlobCallback);
 
   CanvasAsyncBlobCreator* async_creator = nullptr;
-  scoped_refptr<StaticBitmapImage> image_bitmap = ToStaticBitmapImage(
-      kBackBuffer, kPreferNoAcceleration, kSnapshotReasonToBlob);
+  scoped_refptr<StaticBitmapImage> image_bitmap =
+      ToStaticBitmapImage(kBackBuffer, kPreferNoAcceleration);
   if (image_bitmap) {
     async_creator = CanvasAsyncBlobCreator::Create(
         image_bitmap, encoding_mime_type, callback, start_time, &GetDocument());
@@ -1150,8 +1147,7 @@
 
 scoped_refptr<Image> HTMLCanvasElement::CopiedImage(
     SourceDrawingBuffer source_buffer,
-    AccelerationHint hint,
-    SnapshotReason snapshot_reason) {
+    AccelerationHint hint) {
   if (SurfaceLayerBridge())
     return PlaceholderFrame();
 
@@ -1163,10 +1159,10 @@
 
   if (context_->GetContextType() ==
       CanvasRenderingContext::kContextImageBitmap) {
-    scoped_refptr<Image> image = context_->GetImage(hint, snapshot_reason);
+    scoped_refptr<Image> image = context_->GetImage(hint);
     // TODO(fserb): return image?
     if (image)
-      return context_->GetImage(hint, snapshot_reason);
+      return context_->GetImage(hint);
     // Special case: transferFromImageBitmap is not yet called.
     sk_sp<SkSurface> surface =
         SkSurface::MakeRasterN32Premul(width(), height());
@@ -1178,7 +1174,7 @@
   if (context_->Is3d())
     need_to_update |= context_->PaintRenderingResultsToCanvas(source_buffer);
   if (need_to_update && TryCreateImageBuffer()) {
-    copied_image_ = NewImageSnapshot(hint, snapshot_reason);
+    copied_image_ = NewImageSnapshot(hint);
     UpdateMemoryUsage();
   }
   return copied_image_;
@@ -1252,7 +1248,6 @@
 scoped_refptr<Image> HTMLCanvasElement::GetSourceImageForCanvas(
     SourceImageStatus* status,
     AccelerationHint hint,
-    SnapshotReason reason,
     const FloatSize&) {
   if (!width() || !height()) {
     *status = kZeroSizeCanvasSourceImageStatus;
@@ -1278,7 +1273,7 @@
   if (context_->GetContextType() ==
       CanvasRenderingContext::kContextImageBitmap) {
     *status = kNormalSourceImageStatus;
-    scoped_refptr<Image> result = context_->GetImage(hint, reason);
+    scoped_refptr<Image> result = context_->GetImage(hint);
     if (!result)
       result = CreateTransparentImage(Size());
     *status = result ? kNormalSourceImageStatus : kInvalidSourceImageStatus;
@@ -1294,7 +1289,7 @@
     // cached copy of the backing in the canvas's ImageBuffer.
     RenderingContext()->PaintRenderingResultsToCanvas(kBackBuffer);
     if (webgl_buffer_) {
-      image = webgl_buffer_->NewImageSnapshot(hint, reason);
+      image = webgl_buffer_->NewImageSnapshot(hint);
     } else {
       image = CreateTransparentImage(Size());
     }
@@ -1305,7 +1300,7 @@
         canvas2d_buffer_->IsAccelerated()) {
       DisableAcceleration();
     }
-    image = RenderingContext()->GetImage(hint, reason);
+    image = RenderingContext()->GetImage(hint);
     if (!image) {
       image = CreateTransparentImage(Size());
     }
@@ -1326,8 +1321,7 @@
 FloatSize HTMLCanvasElement::ElementSize(const FloatSize&) const {
   if (context_ && context_->GetContextType() ==
                       CanvasRenderingContext::kContextImageBitmap) {
-    scoped_refptr<Image> image =
-        context_->GetImage(kPreferNoAcceleration, kSnapshotReasonDrawImage);
+    scoped_refptr<Image> image = context_->GetImage(kPreferNoAcceleration);
     if (image)
       return FloatSize(image->width(), image->height());
     return FloatSize(0, 0);
@@ -1547,8 +1541,8 @@
 void HTMLCanvasElement::ReplaceExistingCanvas2DBuffer(
     std::unique_ptr<Canvas2DLayerBridge> new_buffer) {
   if (canvas2d_buffer_) {
-    scoped_refptr<StaticBitmapImage> image = canvas2d_buffer_->NewImageSnapshot(
-        kPreferNoAcceleration, kSnapshotReasonPaint);
+    scoped_refptr<StaticBitmapImage> image =
+        canvas2d_buffer_->NewImageSnapshot(kPreferNoAcceleration);
 
     // image can be null if alloaction failed in which case we should just
     // abort the surface switch to reatain the old surface which is still
@@ -1561,12 +1555,11 @@
 }
 
 scoped_refptr<StaticBitmapImage> HTMLCanvasElement::NewImageSnapshot(
-    AccelerationHint hint,
-    SnapshotReason reason) {
+    AccelerationHint hint) {
   if (canvas2d_buffer_)
-    return canvas2d_buffer_->NewImageSnapshot(hint, reason);
+    return canvas2d_buffer_->NewImageSnapshot(hint);
   if (webgl_buffer_)
-    return webgl_buffer_->NewImageSnapshot(hint, reason);
+    return webgl_buffer_->NewImageSnapshot(hint);
   return nullptr;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index 9f4faa1c..d206db35 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -147,9 +147,7 @@
     return context_.Get();
   }
 
-  scoped_refptr<Image> CopiedImage(SourceDrawingBuffer,
-                                   AccelerationHint,
-                                   SnapshotReason);
+  scoped_refptr<Image> CopiedImage(SourceDrawingBuffer, AccelerationHint);
   void ClearCopiedImage();
 
   bool OriginClean() const;
@@ -188,7 +186,6 @@
   // CanvasImageSource implementation
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) override;
   bool WouldTaintOrigin(const SecurityOrigin*) const override;
   FloatSize ElementSize(const FloatSize&) const override;
@@ -321,8 +318,7 @@
   CanvasColorParams ColorParams() const;
 
   scoped_refptr<StaticBitmapImage> ToStaticBitmapImage(SourceDrawingBuffer,
-                                                       AccelerationHint,
-                                                       SnapshotReason) const;
+                                                       AccelerationHint) const;
 
   String ToDataURLInternal(const String& mime_type,
                            const double& quality,
@@ -351,8 +347,7 @@
   std::unique_ptr<AcceleratedImageBufferSurface> webgl_buffer_;
   void ReplaceExistingCanvas2DBuffer(std::unique_ptr<Canvas2DLayerBridge>);
 
-  scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint,
-                                                    SnapshotReason);
+  scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint);
 
   // FIXME: This is temporary for platforms that have to copy the image buffer
   // to render (and for CSSCanvasValue).
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
index 57482ab12..7c3179b 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
@@ -50,7 +50,6 @@
 #include "core/layout/AdjustForAbsoluteZoom.h"
 #include "core/layout/LayoutBlockFlow.h"
 #include "core/layout/LayoutImage.h"
-#include "core/layout/api/LayoutImageItem.h"
 #include "core/layout/ng/layout_ng_block_flow.h"
 #include "core/loader/resource/ImageResourceContent.h"
 #include "core/media_type_names.h"
@@ -235,8 +234,8 @@
     UseCounter::Count(GetDocument(), WebFeature::kSrcsetXDescriptor);
   }
   if (GetLayoutObject() && GetLayoutObject()->IsImage()) {
-    LayoutImageItem(ToLayoutImage(GetLayoutObject()))
-        .SetImageDevicePixelRatio(image_device_pixel_ratio_);
+    ToLayoutImage(GetLayoutObject())
+        ->SetImageDevicePixelRatio(image_device_pixel_ratio_);
 
     if (old_image_device_pixel_ratio != image_device_pixel_ratio_)
       ToLayoutImage(GetLayoutObject())->IntrinsicSizeChanged();
diff --git a/third_party/WebKit/Source/core/html/HTMLProgressElement.cpp b/third_party/WebKit/Source/core/html/HTMLProgressElement.cpp
index 9bd35568..5272290 100644
--- a/third_party/WebKit/Source/core/html/HTMLProgressElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLProgressElement.cpp
@@ -28,7 +28,6 @@
 #include "core/html/shadow/ProgressShadowElement.h"
 #include "core/html_names.h"
 #include "core/layout/LayoutProgress.h"
-#include "core/layout/api/LayoutProgressItem.h"
 
 namespace blink {
 
@@ -83,8 +82,8 @@
 
 void HTMLProgressElement::AttachLayoutTree(AttachContext& context) {
   LabelableElement::AttachLayoutTree(context);
-  if (LayoutProgressItem layout_item = LayoutProgressItem(GetLayoutProgress()))
-    layout_item.UpdateFromElement();
+  if (LayoutProgress* layout_progress = GetLayoutProgress())
+    layout_progress->UpdateFromElement();
 }
 
 double HTMLProgressElement::value() const {
@@ -127,8 +126,8 @@
 
 void HTMLProgressElement::DidElementStateChange() {
   SetValueWidthPercentage(position() * 100);
-  if (LayoutProgressItem layout_item = LayoutProgressItem(GetLayoutProgress()))
-    layout_item.UpdateFromElement();
+  if (LayoutProgress* layout_progress = GetLayoutProgress())
+    layout_progress->UpdateFromElement();
 }
 
 void HTMLProgressElement::DidAddUserAgentShadowRoot(ShadowRoot& root) {
diff --git a/third_party/WebKit/Source/core/html/ListItemOrdinal.cpp b/third_party/WebKit/Source/core/html/ListItemOrdinal.cpp
index cb4ef64..c7b46149 100644
--- a/third_party/WebKit/Source/core/html/ListItemOrdinal.cpp
+++ b/third_party/WebKit/Source/core/html/ListItemOrdinal.cpp
@@ -30,7 +30,6 @@
 #include "core/dom/LayoutTreeBuilderTraversal.h"
 #include "core/html/HTMLOListElement.h"
 #include "core/layout/LayoutListItem.h"
-#include "core/layout/api/LayoutLIItem.h"
 #include "core/layout/ng/layout_ng_list_item.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h b/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
index 66f038f..a161794 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasImageSource.h
@@ -52,7 +52,6 @@
  public:
   virtual scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                        AccelerationHint,
-                                                       SnapshotReason,
                                                        const FloatSize&) = 0;
 
   // IMPORTANT: Result must be independent of whether destinationContext is
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index de687106..411d054 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -89,8 +89,7 @@
 
   const CanvasColorParams& ColorParams() const { return color_params_; }
 
-  virtual scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
-                                                    SnapshotReason) const = 0;
+  virtual scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint) const = 0;
   virtual ContextType GetContextType() const = 0;
   virtual bool IsComposited() const = 0;
   virtual bool IsAccelerated() const = 0;
diff --git a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
index 80c3645..6e839c7 100644
--- a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
@@ -43,7 +43,6 @@
 scoped_refptr<Image> ImageElementBase::GetSourceImageForCanvas(
     SourceImageStatus* status,
     AccelerationHint,
-    SnapshotReason,
     const FloatSize& default_object_size) {
   ImageResourceContent* image_content = CachedImage();
   if (!GetImageLoader().ImageComplete() || !image_content) {
diff --git a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h
index 8294257..0cdaa5a2 100644
--- a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h
+++ b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.h
@@ -35,7 +35,6 @@
 
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) override;
 
   bool WouldTaintOrigin(
diff --git a/third_party/WebKit/Source/core/html/forms/FileInputType.cpp b/third_party/WebKit/Source/core/html/forms/FileInputType.cpp
index fb41f49..021128f0 100644
--- a/third_party/WebKit/Source/core/html/forms/FileInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/FileInputType.cpp
@@ -153,6 +153,7 @@
   if (ChromeClient* chrome_client = GetChromeClient()) {
     WebFileChooserParams params;
     HTMLInputElement& input = GetElement();
+    Document& document = input.GetDocument();
     bool is_directory = input.FastHasAttribute(webkitdirectoryAttr);
     params.directory = is_directory;
     params.need_local_path = is_directory;
@@ -161,10 +162,14 @@
     params.selected_files = file_list_->PathsForUserVisibleFiles();
     params.use_media_capture = RuntimeEnabledFeatures::MediaCaptureEnabled() &&
                                input.FastHasAttribute(captureAttr);
-    params.requestor = input.GetDocument().Url();
+    params.requestor = document.Url();
 
-    chrome_client->OpenFileChooser(input.GetDocument().GetFrame(),
-                                   NewFileChooser(params));
+    UseCounter::Count(
+        document, document.IsSecureContext()
+                      ? WebFeature::kInputTypeFileSecureOriginOpenChooser
+                      : WebFeature::kInputTypeFileInsecureOriginOpenChooser);
+
+    chrome_client->OpenFileChooser(document.GetFrame(), NewFileChooser(params));
   }
   event->SetDefaultHandled();
 }
diff --git a/third_party/WebKit/Source/core/html/forms/FormController.h b/third_party/WebKit/Source/core/html/forms/FormController.h
index c21565d5..3b0fe50 100644
--- a/third_party/WebKit/Source/core/html/forms/FormController.h
+++ b/third_party/WebKit/Source/core/html/forms/FormController.h
@@ -28,7 +28,6 @@
 #include "platform/heap/HeapAllocator.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Forward.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/AtomicStringHash.h"
 
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
index e7103ec7..2f5c35b8 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
@@ -990,10 +990,9 @@
   // unchecked to match other browsers. DOM is not a useful standard for this
   // because it says only to fire change events at "lose focus" time, which is
   // definitely wrong in practice for these types of elements.
-  if (event_behavior != kDispatchNoEvent && isConnected() &&
+  if (event_behavior == kDispatchInputAndChangeEvent && isConnected() &&
       input_type_->ShouldSendChangeEventAfterCheckedChanged()) {
-    if (event_behavior == kDispatchInputAndChangeEvent)
-      DispatchInputEvent();
+    DispatchInputEvent();
   }
 
   PseudoStateChanged(CSSSelector::kPseudoChecked);
diff --git a/third_party/WebKit/Source/core/html/forms/TextControlInnerElements.cpp b/third_party/WebKit/Source/core/html/forms/TextControlInnerElements.cpp
index c1d1da1..96b3a82 100644
--- a/third_party/WebKit/Source/core/html/forms/TextControlInnerElements.cpp
+++ b/third_party/WebKit/Source/core/html/forms/TextControlInnerElements.cpp
@@ -40,7 +40,6 @@
 #include "core/html_names.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/LayoutTextControlSingleLine.h"
-#include "core/layout/api/LayoutTextControlItem.h"
 
 namespace blink {
 
@@ -146,11 +145,9 @@
   LayoutObject* parent_layout_object = OwnerShadowHost()->GetLayoutObject();
   if (!parent_layout_object || !parent_layout_object->IsTextControl())
     return OriginalStyleForLayoutObject();
-  LayoutTextControlItem text_control_layout_item =
-      LayoutTextControlItem(ToLayoutTextControl(parent_layout_object));
+  LayoutTextControl* text_control = ToLayoutTextControl(parent_layout_object);
   scoped_refptr<ComputedStyle> inner_editor_style =
-      text_control_layout_item.CreateInnerEditorStyle(
-          text_control_layout_item.StyleRef());
+      text_control->CreateInnerEditorStyle(text_control->StyleRef());
   // Using StyleAdjuster::adjustComputedStyle updates unwanted style. We'd like
   // to apply only editing-related and alignment-related.
   StyleAdjuster::AdjustStyleForEditing(*inner_editor_style);
diff --git a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp
index e0d4906..7679ca2 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp
+++ b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp
@@ -442,7 +442,6 @@
 scoped_refptr<Image> HTMLVideoElement::GetSourceImageForCanvas(
     SourceImageStatus* status,
     AccelerationHint,
-    SnapshotReason,
     const FloatSize&) {
   if (!HasAvailableVideoFrame()) {
     *status = kInvalidSourceImageStatus;
diff --git a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h
index 45c9451..def38d5 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h
+++ b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.h
@@ -121,7 +121,6 @@
   // CanvasImageSource implementation
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) override;
   bool IsVideoElement() const override { return true; }
   bool WouldTaintOrigin(const SecurityOrigin*) const override;
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
index 194ee6ed..3397512 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
@@ -535,8 +535,7 @@
                          const ImageBitmapOptions& options) {
   SourceImageStatus status;
   scoped_refptr<Image> image_input = canvas->GetSourceImageForCanvas(
-      &status, kPreferAcceleration, kSnapshotReasonCreateImageBitmap,
-      FloatSize());
+      &status, kPreferAcceleration, FloatSize());
   if (status != kNormalSourceImageStatus)
     return;
   DCHECK(image_input->IsStaticBitmapImage());
@@ -561,8 +560,7 @@
                          const ImageBitmapOptions& options) {
   SourceImageStatus status;
   scoped_refptr<Image> raw_input = offscreen_canvas->GetSourceImageForCanvas(
-      &status, kPreferNoAcceleration, kSnapshotReasonCreateImageBitmap,
-      FloatSize(offscreen_canvas->Size()));
+      &status, kPreferNoAcceleration, FloatSize(offscreen_canvas->Size()));
   DCHECK(raw_input->IsStaticBitmapImage());
   scoped_refptr<StaticBitmapImage> input =
       static_cast<StaticBitmapImage*>(raw_input.get());
@@ -993,7 +991,6 @@
 scoped_refptr<Image> ImageBitmap::GetSourceImageForCanvas(
     SourceImageStatus* status,
     AccelerationHint,
-    SnapshotReason,
     const FloatSize&) {
   *status = kNormalSourceImageStatus;
   if (!image_)
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
index 2e3b97e..36aeaed 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
@@ -107,7 +107,6 @@
   // CanvasImageSource implementation
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) override;
   bool WouldTaintOrigin(const SecurityOrigin*) const override {
     return !image_->OriginClean();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
index 32c6e53..8dfcc5b 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -79,7 +79,6 @@
 #include "core/xml/DocumentXPathEvaluator.h"
 #include "core/xml/XPathResult.h"
 #include "platform/graphics/Color.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/PtrUtil.h"
 #include "platform/wtf/text/CString.h"
 #include "platform/wtf/text/WTFString.h"
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
index ce94001..c91e1e1 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -72,7 +72,6 @@
 #include "platform/loader/fetch/TextResourceDecoderOptions.h"
 #include "platform/network/mime/MIMETypeRegistry.h"
 #include "platform/weborigin/SecurityOrigin.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/Time.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/Base64.h"
diff --git a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
index 3647013..74d218a 100644
--- a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
+++ b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
@@ -342,9 +342,6 @@
 }
 
 XHRReplayData* NetworkResourcesData::XhrReplayData(const String& request_id) {
-  if (reused_xhr_replay_data_request_ids_.Contains(request_id))
-    return XhrReplayData(reused_xhr_replay_data_request_ids_.at(request_id));
-
   ResourceData* resource_data = ResourceDataForRequestId(request_id);
   if (!resource_data)
     return nullptr;
@@ -363,16 +360,8 @@
 void NetworkResourcesData::SetXHRReplayData(const String& request_id,
                                             XHRReplayData* xhr_replay_data) {
   ResourceData* resource_data = ResourceDataForRequestId(request_id);
-  if (!resource_data) {
-    Vector<String> result;
-    for (auto& request : reused_xhr_replay_data_request_ids_) {
-      if (request.value == request_id)
-        SetXHRReplayData(request.key, xhr_replay_data);
-    }
-    return;
-  }
-
-  resource_data->SetXHRReplayData(xhr_replay_data);
+  if (resource_data)
+    resource_data->SetXHRReplayData(xhr_replay_data);
 }
 
 HeapVector<Member<NetworkResourcesData::ResourceData>>
@@ -419,8 +408,6 @@
       preserved_map.Set(resource.key, resource.value);
   }
   request_id_to_resource_data_map_.swap(preserved_map);
-
-  reused_xhr_replay_data_request_ids_.clear();
 }
 
 void NetworkResourcesData::SetResourcesDataSizeLimits(
diff --git a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h
index cfc36ee66..eb75b9d 100644
--- a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h
+++ b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.h
@@ -253,8 +253,6 @@
 
   Deque<String> request_ids_deque_;
 
-  typedef HashMap<String, String> ReusedRequestIds;
-  ReusedRequestIds reused_xhr_replay_data_request_ids_;
   typedef HeapHashMap<String, Member<ResourceData>> ResourceDataMap;
   ResourceDataMap request_id_to_resource_data_map_;
   size_t content_size_;
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 974781c..bcc20615 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -10245,6 +10245,11 @@
                     "description": "Force the page stop all navigations and pending resource fetches."
                 },
                 {
+                    "name": "crash",
+                    "description": "Crashes renderer on the IO thread, generates minidumps.",
+                    "experimental": true
+                },
+                {
                     "name": "stopScreencast",
                     "description": "Stops sending each frame in the `screencastFrame`.",
                     "experimental": true
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.pdl b/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
index aadbc02..fbde1ca 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
@@ -4688,6 +4688,9 @@
   # Force the page stop all navigations and pending resource fetches.
   command stopLoading
 
+  # Crashes renderer on the IO thread, generates minidumps.
+  experimental command crash
+
   # Stops sending each frame in the `screencastFrame`.
   experimental command stopScreencast
 
diff --git a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
index a41535d..7cc7e78 100644
--- a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
+++ b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
@@ -80,7 +80,7 @@
             {
                 "domain": "Page",
                 "exclude": ["getNavigationHistory", "navigateToHistoryEntry", "captureScreenshot", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled",
-                            "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront", "setDownloadBehavior", "navigate"],
+                            "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront", "setDownloadBehavior", "navigate", "crash"],
                 "async": ["getResourceContent", "searchInResource"],
                 "exclude_events": ["screencastFrame", "screencastVisibilityChanged", "colorPicked", "interstitialShown", "interstitialHidden", "javascriptDialogOpening", "javascriptDialogClosed", "navigationRequested"]
             },
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn
index 4ee2429..4704047 100644
--- a/third_party/WebKit/Source/core/layout/BUILD.gn
+++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -244,21 +244,6 @@
     "ViewFragmentationContext.cpp",
     "ViewFragmentationContext.h",
     "api/HitTestAction.h",
-    "api/LayoutAPIShim.h",
-    "api/LayoutBlockItem.h",
-    "api/LayoutBoxItem.h",
-    "api/LayoutBoxModel.h",
-    "api/LayoutFullScreenItem.h",
-    "api/LayoutImageItem.h",
-    "api/LayoutItem.h",
-    "api/LayoutLIItem.h",
-    "api/LayoutMenuListItem.h",
-    "api/LayoutProgressItem.h",
-    "api/LayoutSliderItem.cpp",
-    "api/LayoutSliderItem.h",
-    "api/LayoutTextControlItem.h",
-    "api/LayoutTextFragmentItem.h",
-    "api/LayoutTextItem.h",
     "api/LineLayoutAPIShim.h",
     "api/LineLayoutBR.h",
     "api/LineLayoutBlockFlow.h",
diff --git a/third_party/WebKit/Source/core/layout/Grid.h b/third_party/WebKit/Source/core/layout/Grid.h
index 508482a1..8098b46 100644
--- a/third_party/WebKit/Source/core/layout/Grid.h
+++ b/third_party/WebKit/Source/core/layout/Grid.h
@@ -10,7 +10,7 @@
 #include "core/style/GridArea.h"
 #include "core/style/GridPositionsResolver.h"
 #include "platform/wtf/Assertions.h"
-#include "platform/wtf/ListHashSet.h"
+#include "platform/wtf/LinkedHashSet.h"
 #include "platform/wtf/Vector.h"
 
 namespace blink {
@@ -18,7 +18,7 @@
 // TODO(svillar): Perhaps we should use references here.
 typedef Vector<LayoutBox*, 1> GridCell;
 typedef Vector<Vector<GridCell>> GridAsMatrix;
-typedef ListHashSet<size_t> OrderedTrackIndexSet;
+typedef LinkedHashSet<size_t> OrderedTrackIndexSet;
 
 class LayoutGrid;
 class GridIterator;
@@ -62,7 +62,7 @@
   size_t AutoRepeatTracks(GridTrackSizingDirection) const;
   void SetAutoRepeatTracks(size_t auto_repeat_rows, size_t auto_repeat_columns);
 
-  typedef ListHashSet<size_t> OrderedTrackIndexSet;
+  typedef LinkedHashSet<size_t> OrderedTrackIndexSet;
   void SetAutoRepeatEmptyColumns(std::unique_ptr<OrderedTrackIndexSet>);
   void SetAutoRepeatEmptyRows(std::unique_ptr<OrderedTrackIndexSet>);
 
diff --git a/third_party/WebKit/Source/core/layout/HitTestLocation.h b/third_party/WebKit/Source/core/layout/HitTestLocation.h
index 0e36d42..e92adc7 100644
--- a/third_party/WebKit/Source/core/layout/HitTestLocation.h
+++ b/third_party/WebKit/Source/core/layout/HitTestLocation.h
@@ -29,7 +29,6 @@
 #include "platform/geometry/LayoutRect.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Forward.h"
-#include "platform/wtf/ListHashSet.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/layout/HitTestResult.h b/third_party/WebKit/Source/core/layout/HitTestResult.h
index 576b23a..0e1e50a 100644
--- a/third_party/WebKit/Source/core/layout/HitTestResult.h
+++ b/third_party/WebKit/Source/core/layout/HitTestResult.h
@@ -31,7 +31,6 @@
 #include "platform/heap/Handle.h"
 #include "platform/text/TextDirection.h"
 #include "platform/wtf/Forward.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/VectorTraits.h"
 #include "platform/wtf/text/WTFString.h"
 
diff --git a/third_party/WebKit/Source/core/layout/IntersectionGeometry.cpp b/third_party/WebKit/Source/core/layout/IntersectionGeometry.cpp
index c77cfef..ca6d8bf 100644
--- a/third_party/WebKit/Source/core/layout/IntersectionGeometry.cpp
+++ b/third_party/WebKit/Source/core/layout/IntersectionGeometry.cpp
@@ -9,7 +9,6 @@
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/paint/PaintLayer.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 3b7b0be..9a0ed7abda 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -51,7 +51,6 @@
 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
 #include "core/layout/LayoutTableCell.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/layout/api/LineLayoutBlockFlow.h"
 #include "core/layout/api/LineLayoutBox.h"
 #include "core/layout/ng/geometry/ng_box_strut.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
index 0532559e..8f35323 100644
--- a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
@@ -35,7 +35,6 @@
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutAnalyzer.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/page/scrolling/RootScrollerUtil.h"
 #include "core/paint/EmbeddedContentPainter.h"
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlowThread.h b/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
index 3f1c776..ee681aaa 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
+++ b/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
@@ -32,13 +32,13 @@
 
 #include "core/CoreExport.h"
 #include "core/layout/LayoutBlockFlow.h"
-#include "platform/wtf/ListHashSet.h"
+#include "platform/wtf/LinkedHashSet.h"
 
 namespace blink {
 
 class LayoutMultiColumnSet;
 
-typedef ListHashSet<LayoutMultiColumnSet*> LayoutMultiColumnSetList;
+typedef LinkedHashSet<LayoutMultiColumnSet*> LayoutMultiColumnSetList;
 
 // Layout state for multicol. To be stored when laying out a block child, so
 // that we can roll back to the initial state if we need to re-lay out said
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index eeb9575d..78abe66d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -75,7 +75,6 @@
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutTheme.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/layout/ng/layout_ng_block_flow.h"
 #include "core/layout/ng/layout_ng_list_item.h"
 #include "core/layout/ng/layout_ng_table_cell.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
index 7b95352..7cdef1eb 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
@@ -31,7 +31,6 @@
 #include "core/layout/LayoutScrollbarPart.h"
 #include "core/layout/LayoutScrollbarTheme.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "platform/graphics/GraphicsContext.h"
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index d90573d..65f3745 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -1883,10 +1883,20 @@
                                               int row_height) {
   // Force percent height children to lay themselves out again.
   // This will cause these children to grow to fill the cell.
+  // FIXME: There is still more work to do here to fully match WinIE (should
+  // it become necessary to do so).  In quirks mode, WinIE behaves like we
+  // do, but it will clip the cells that spill out of the table section.
+  // strict mode, Mozilla and WinIE both regrow the table to accommodate the
+  // new height of the cell (thus letting the percentages cause growth one
+  // time only). We may also not be handling row-spanning cells correctly.
+  //
+  // Note also the oddity where replaced elements always flex, and yet blocks/
+  // tables do not necessarily flex. WinIE is crazy and inconsistent, and we
+  // can't hope to match the behavior perfectly, but we'll continue to refine it
+  // as we discover new bugs. :)
   bool cell_children_flex = false;
   bool flex_all_children = CellHasExplicitlySpecifiedHeight(cell) ||
-                           (GetDocument().InQuirksMode() &&
-                            !Table()->Style()->LogicalHeight().IsAuto() &&
+                           (!Table()->Style()->LogicalHeight().IsAuto() &&
                             row_height != cell.LogicalHeight());
 
   for (LayoutObject* child = cell.FirstChild(); child;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
index a257cfa0..04e5f86 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
@@ -14,7 +14,6 @@
 #include "core/frame/Settings.h"
 #include "core/html/HTMLElement.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/loader/EmptyClients.h"
 #include "core/testing/PageTestBase.h"
 #include "platform/testing/UseMockScrollbarSettings.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp
index fa61137..b6e9557 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -36,7 +36,6 @@
 #include "core/layout/LayoutGeometryMap.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/ViewFragmentationContext.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
diff --git a/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp b/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp
index 82dfc73..66d6535 100644
--- a/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp
@@ -12,8 +12,8 @@
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/UseCounter.h"
 #include "core/layout/LayoutBlockFlow.h"
+#include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutTable.h"
-#include "core/layout/api/LayoutBoxItem.h"
 #include "core/layout/line/InlineTextBox.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/PaintLayerScrollableArea.h"
@@ -47,17 +47,12 @@
   ClearSelf();
 }
 
-// TODO(pilgrim): Replace all instances of scrollerLayoutBox with
-// scrollerLayoutBoxItem, https://crbug.com/499321
 static LayoutBox* ScrollerLayoutBox(const ScrollableArea* scroller) {
   LayoutBox* box = scroller->GetLayoutBox();
   DCHECK(box);
   return box;
 }
 
-static LayoutBoxItem ScrollerLayoutBoxItem(const ScrollableArea* scroller) {
-  return LayoutBoxItem(ScrollerLayoutBox(scroller));
-}
 
 // TODO(skobes): Storing a "corner" doesn't make much sense anymore since we
 // adjust only on the block flow axis.  This could probably be refactored to
@@ -294,7 +289,7 @@
 
   LayoutRect candidate_rect = RelativeBounds(candidate, scroller_);
   LayoutRect visible_rect =
-      ScrollerLayoutBoxItem(scroller_).OverflowClipRect(LayoutPoint());
+      ScrollerLayoutBox(scroller_)->OverflowClipRect(LayoutPoint());
 
   bool occupies_space =
       candidate_rect.Width() > 0 && candidate_rect.Height() > 0;
diff --git a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
index 84f8ec5..f0132c8 100644
--- a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
+++ b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
@@ -46,7 +46,6 @@
 #include "core/layout/LayoutTable.h"
 #include "core/layout/LayoutTableCell.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "platform/geometry/IntRect.h"
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutAPIShim.h b/third_party/WebKit/Source/core/layout/api/LayoutAPIShim.h
deleted file mode 100644
index 8ad075b4..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutAPIShim.h
+++ /dev/null
@@ -1,29 +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 LayoutAPIShim_h
-#define LayoutAPIShim_h
-
-#include "core/layout/api/LayoutItem.h"
-
-namespace blink {
-
-class LayoutObject;
-
-// TODO(pilgrim): Remove this kludge once clients have a real API and no longer
-// need access to the underlying LayoutObject.
-class LayoutAPIShim {
- public:
-  static LayoutObject* LayoutObjectFrom(LayoutItem item) {
-    return item.GetLayoutObject();
-  }
-
-  static const LayoutObject* ConstLayoutObjectFrom(LayoutItem item) {
-    return item.GetLayoutObject();
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutAPIShim_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h
deleted file mode 100644
index 8a0ee80..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h
+++ /dev/null
@@ -1,46 +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 LayoutBlockItem_h
-#define LayoutBlockItem_h
-
-#include "core/layout/LayoutBlock.h"
-#include "core/layout/api/LayoutBoxItem.h"
-
-namespace blink {
-
-class LayoutBlockItem : public LayoutBoxItem {
- public:
-  explicit LayoutBlockItem(LayoutBlock* layout_block)
-      : LayoutBoxItem(layout_block) {}
-
-  explicit LayoutBlockItem(const LayoutBoxItem& item) : LayoutBoxItem(item) {
-    SECURITY_DCHECK(!item || item.IsLayoutBlock());
-  }
-
-  explicit LayoutBlockItem(std::nullptr_t) : LayoutBoxItem(nullptr) {}
-
-  LayoutBlockItem() {}
-
-  void FlipForWritingMode(LayoutRect& rect) const {
-    ToBlock()->FlipForWritingMode(rect);
-  }
-
-  bool RecalcOverflowAfterStyleChange() {
-    return ToBlock()->RecalcOverflowAfterStyleChange();
-  }
-
-  LayoutItem FirstChild() const { return LayoutItem(ToBlock()->FirstChild()); }
-
- private:
-  LayoutBlock* ToBlock() { return ToLayoutBlock(GetLayoutObject()); }
-  const LayoutBlock* ToBlock() const {
-    return ToLayoutBlock(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutBlockItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h
deleted file mode 100644
index 93fea42..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h
+++ /dev/null
@@ -1,77 +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 LayoutBoxItem_h
-#define LayoutBoxItem_h
-
-#include "core/layout/LayoutBox.h"
-#include "core/layout/api/LayoutBoxModel.h"
-#include "platform/scroll/ScrollTypes.h"
-
-namespace blink {
-
-class LayoutPoint;
-class LayoutSize;
-class LayoutUnit;
-
-class LayoutBoxItem : public LayoutBoxModel {
- public:
-  explicit LayoutBoxItem(LayoutBox* layout_box) : LayoutBoxModel(layout_box) {}
-
-  explicit LayoutBoxItem(const LayoutItem& item) : LayoutBoxModel(item) {
-    SECURITY_DCHECK(!item || item.IsBox());
-  }
-
-  explicit LayoutBoxItem(std::nullptr_t) : LayoutBoxModel(nullptr) {}
-
-  LayoutBoxItem() {}
-
-  LayoutBoxItem EnclosingBox() const {
-    return LayoutBoxItem(ToBox()->EnclosingBox());
-  }
-
-  ScrollResult Scroll(ScrollGranularity granularity, const FloatSize& delta) {
-    return ToBox()->Scroll(granularity, delta);
-  }
-
-  LayoutSize Size() const { return ToBox()->Size(); }
-
-  LayoutPoint Location() const { return ToBox()->Location(); }
-
-  LayoutUnit LogicalWidth() const { return ToBox()->LogicalWidth(); }
-
-  LayoutUnit LogicalHeight() const { return ToBox()->LogicalHeight(); }
-
-  LayoutUnit MinPreferredLogicalWidth() const {
-    return ToBox()->MinPreferredLogicalWidth();
-  }
-
-  LayoutRect OverflowClipRect(const LayoutPoint& location,
-                              OverlayScrollbarClipBehavior behavior =
-                                  kIgnorePlatformOverlayScrollbarSize) const {
-    return ToBox()->OverflowClipRect(location, behavior);
-  }
-
-  LayoutSize ContentBoxOffset() const { return ToBox()->ContentBoxOffset(); }
-
-  void MapLocalToAncestor(
-      const LayoutBoxModelObject* ancestor,
-      TransformState& state,
-      MapCoordinatesFlags flags = kApplyContainerFlip) const {
-    ToBox()->MapLocalToAncestor(ancestor, state, flags);
-  }
-
-  FloatQuad AbsoluteContentQuad(MapCoordinatesFlags flags = 0) const {
-    return ToBox()->AbsoluteContentQuad(flags);
-  }
-
- private:
-  LayoutBox* ToBox() { return ToLayoutBox(GetLayoutObject()); }
-
-  const LayoutBox* ToBox() const { return ToLayoutBox(GetLayoutObject()); }
-};
-
-}  // namespace blink
-
-#endif  // LayoutBoxItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h b/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h
deleted file mode 100644
index 19d4f06..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h
+++ /dev/null
@@ -1,53 +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 LayoutBoxModel_h
-#define LayoutBoxModel_h
-
-#include "core/layout/LayoutBoxModelObject.h"
-#include "core/layout/api/LayoutItem.h"
-
-namespace blink {
-
-class LayoutBoxModelObject;
-
-class LayoutBoxModel : public LayoutItem {
- public:
-  explicit LayoutBoxModel(LayoutBoxModelObject* layout_box)
-      : LayoutItem(layout_box) {}
-
-  explicit LayoutBoxModel(const LayoutItem& item) : LayoutItem(item) {
-    SECURITY_DCHECK(!item || item.IsBoxModelObject());
-  }
-
-  explicit LayoutBoxModel(std::nullptr_t) : LayoutItem(nullptr) {}
-
-  LayoutBoxModel() {}
-
-  PaintLayer* Layer() const { return ToBoxModel()->Layer(); }
-
-  PaintLayerScrollableArea* GetScrollableArea() const {
-    return ToBoxModel()->GetScrollableArea();
-  }
-
-  LayoutUnit BorderTop() const { return ToBoxModel()->BorderTop(); }
-
-  LayoutUnit BorderLeft() const { return ToBoxModel()->BorderLeft(); }
-
-  LayoutUnit PaddingTop() const { return ToBoxModel()->PaddingTop(); }
-
-  LayoutUnit PaddingLeft() const { return ToBoxModel()->PaddingLeft(); }
-
- private:
-  LayoutBoxModelObject* ToBoxModel() {
-    return ToLayoutBoxModelObject(GetLayoutObject());
-  }
-  const LayoutBoxModelObject* ToBoxModel() const {
-    return ToLayoutBoxModelObject(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutBoxModel_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h b/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h
deleted file mode 100644
index 545e421..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h
+++ /dev/null
@@ -1,42 +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 LayoutFullScreenItem_h
-#define LayoutFullScreenItem_h
-
-#include "core/layout/LayoutBlock.h"
-#include "core/layout/LayoutFullScreen.h"
-#include "core/layout/api/LayoutBlockItem.h"
-
-namespace blink {
-
-class LayoutFullScreenItem : public LayoutBlockItem {
- public:
-  explicit LayoutFullScreenItem(LayoutBlock* layout_block)
-      : LayoutBlockItem(layout_block) {}
-
-  explicit LayoutFullScreenItem(const LayoutBlockItem& item)
-      : LayoutBlockItem(item) {
-    SECURITY_DCHECK(!item || item.IsLayoutFullScreen());
-  }
-
-  explicit LayoutFullScreenItem(std::nullptr_t) : LayoutBlockItem(nullptr) {}
-
-  LayoutFullScreenItem() {}
-
-  void UnwrapLayoutObject() { return ToFullScreen()->UnwrapLayoutObject(); }
-
- private:
-  LayoutFullScreen* ToFullScreen() {
-    return ToLayoutFullScreen(GetLayoutObject());
-  }
-  const LayoutFullScreen* ToFullScreen() const {
-    return ToLayoutFullScreen(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutFullScreenItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h b/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h
deleted file mode 100644
index 06da2a7a..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h
+++ /dev/null
@@ -1,40 +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 LayoutImageItem_h
-#define LayoutImageItem_h
-
-#include "core/layout/LayoutImage.h"
-#include "core/layout/api/LayoutBoxItem.h"
-
-namespace blink {
-
-class LayoutImageItem : public LayoutBoxItem {
- public:
-  explicit LayoutImageItem(LayoutImage* layout_image)
-      : LayoutBoxItem(layout_image) {}
-
-  explicit LayoutImageItem(const LayoutItem& item) : LayoutBoxItem(item) {
-    SECURITY_DCHECK(!item || item.IsImage());
-  }
-
-  explicit LayoutImageItem(std::nullptr_t) : LayoutBoxItem(nullptr) {}
-
-  LayoutImageItem() {}
-
-  void SetImageDevicePixelRatio(float factor) {
-    ToImage()->SetImageDevicePixelRatio(factor);
-  }
-
- private:
-  LayoutImage* ToImage() { return ToLayoutImage(GetLayoutObject()); }
-
-  const LayoutImage* ToImage() const {
-    return ToLayoutImage(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutImageItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutItem.h b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
deleted file mode 100644
index ec2f19d7b..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutItem.h
+++ /dev/null
@@ -1,246 +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 LayoutItem_h
-#define LayoutItem_h
-
-#include "core/inspector/InspectorTraceEvents.h"
-#include "core/layout/LayoutObject.h"
-
-#include "platform/wtf/Allocator.h"
-
-namespace blink {
-
-class LayoutAPIShim;
-class LocalFrame;
-class LocalFrameView;
-class LayoutViewItem;
-class Node;
-
-class LayoutItem {
-  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-
- public:
-  explicit LayoutItem(LayoutObject* layout_object)
-      : layout_object_(layout_object) {}
-
-  LayoutItem(std::nullptr_t) : layout_object_(nullptr) {}
-
-  LayoutItem() : layout_object_(nullptr) {}
-
-  // TODO(leviw): This should be "explicit operator bool", but
-  // using this operator allows the API to be landed in pieces.
-  // https://crbug.com/499321
-  operator LayoutObject*() const { return layout_object_; }
-
-  // TODO(pilgrim): Remove this when we replace the operator above with
-  // operator bool.
-  bool IsNull() const { return !layout_object_; }
-
-  String DebugName() const { return layout_object_->DebugName(); }
-
-  bool IsDescendantOf(LayoutItem item) const {
-    return layout_object_->IsDescendantOf(item.GetLayoutObject());
-  }
-
-  bool IsBoxModelObject() const { return layout_object_->IsBoxModelObject(); }
-
-  bool IsBox() const { return layout_object_->IsBox(); }
-
-  bool IsBR() const { return layout_object_->IsBR(); }
-
-  bool IsLayoutBlock() const { return layout_object_->IsLayoutBlock(); }
-
-  bool IsText() const { return layout_object_->IsText(); }
-
-  bool IsTextControl() const { return layout_object_->IsTextControl(); }
-
-  bool IsLayoutEmbeddedContent() const {
-    return layout_object_->IsLayoutEmbeddedContent();
-  }
-
-  bool IsEmbeddedObject() const { return layout_object_->IsEmbeddedObject(); }
-
-  bool IsImage() const { return layout_object_->IsImage(); }
-
-  bool IsLayoutFullScreen() const {
-    return layout_object_->IsLayoutFullScreen();
-  }
-
-  bool IsListItem() const { return layout_object_->IsListItem(); }
-
-  bool IsMedia() const { return layout_object_->IsMedia(); }
-
-  bool IsMenuList() const { return layout_object_->IsMenuList(); }
-
-  bool IsProgress() const { return layout_object_->IsProgress(); }
-
-  bool IsSlider() const { return layout_object_->IsSlider(); }
-
-  bool IsLayoutView() const { return layout_object_->IsLayoutView(); }
-
-  bool NeedsLayout() { return layout_object_->NeedsLayout(); }
-
-  void UpdateLayout() { layout_object_->UpdateLayout(); }
-
-  LayoutItem Container() const {
-    return LayoutItem(layout_object_->Container());
-  }
-
-  Node* GetNode() const { return layout_object_->GetNode(); }
-
-  Document& GetDocument() const { return layout_object_->GetDocument(); }
-
-  LocalFrame* GetFrame() const { return layout_object_->GetFrame(); }
-
-  LayoutItem NextInPreOrder() const {
-    return LayoutItem(layout_object_->NextInPreOrder());
-  }
-
-  void UpdateStyleAndLayout() {
-    return layout_object_->GetDocument().UpdateStyleAndLayout();
-  }
-
-  const ComputedStyle& StyleRef() const { return layout_object_->StyleRef(); }
-
-  ComputedStyle* MutableStyle() const { return layout_object_->MutableStyle(); }
-
-  ComputedStyle& MutableStyleRef() const {
-    return layout_object_->MutableStyleRef();
-  }
-
-  void SetStyle(scoped_refptr<ComputedStyle> style) {
-    layout_object_->SetStyle(std::move(style));
-  }
-
-  LayoutSize OffsetFromContainer(const LayoutItem& item) const {
-    return layout_object_->OffsetFromContainer(item.GetLayoutObject());
-  }
-
-  LayoutViewItem View() const;
-
-  LocalFrameView* GetFrameView() const {
-    return layout_object_->GetDocument().View();
-  }
-
-  const ComputedStyle* Style() const { return layout_object_->Style(); }
-
-  PaintLayer* EnclosingLayer() const {
-    return layout_object_->EnclosingLayer();
-  }
-
-  bool HasLayer() const { return layout_object_->HasLayer(); }
-
-  void SetNeedsLayout(LayoutInvalidationReasonForTracing reason,
-                      MarkingBehavior marking = kMarkContainerChain,
-                      SubtreeLayoutScope* scope = nullptr) {
-    layout_object_->SetNeedsLayout(reason, marking, scope);
-  }
-
-  void SetNeedsLayoutAndFullPaintInvalidation(
-      LayoutInvalidationReasonForTracing reason,
-      MarkingBehavior behavior = kMarkContainerChain,
-      SubtreeLayoutScope* scope = nullptr) {
-    layout_object_->SetNeedsLayoutAndFullPaintInvalidation(reason, behavior,
-                                                           scope);
-  }
-
-  void SetNeedsLayoutAndPrefWidthsRecalc(
-      LayoutInvalidationReasonForTracing reason) {
-    layout_object_->SetNeedsLayoutAndPrefWidthsRecalc(reason);
-  }
-
-  void SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
-      LayoutInvalidationReasonForTracing reason) {
-    layout_object_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
-        reason);
-  }
-
-  void SetMayNeedPaintInvalidation() {
-    layout_object_->SetMayNeedPaintInvalidation();
-  }
-
-  void SetShouldDoFullPaintInvalidation(
-      PaintInvalidationReason reason = PaintInvalidationReason::kFull) {
-    layout_object_->SetShouldDoFullPaintInvalidation(reason);
-  }
-
-  void SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants() {
-    layout_object_
-        ->SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
-  }
-
-  void ComputeLayerHitTestRects(LayerHitTestRects& layer_rects,
-                                TouchAction supported_fast_actions) const {
-    layout_object_->ComputeLayerHitTestRects(layer_rects,
-                                             supported_fast_actions);
-  }
-
-  FloatPoint LocalToAbsolute(const FloatPoint& local_point = FloatPoint(),
-                             MapCoordinatesFlags mode = 0) const {
-    return layout_object_->LocalToAbsolute(local_point, mode);
-  }
-
-  FloatQuad LocalToAbsoluteQuad(const FloatQuad& quad,
-                                MapCoordinatesFlags mode = 0) const {
-    return layout_object_->LocalToAbsoluteQuad(quad, mode);
-  }
-
-  FloatPoint AbsoluteToLocal(const FloatPoint& point,
-                             MapCoordinatesFlags mode = 0) const {
-    return layout_object_->AbsoluteToLocal(point, mode);
-  }
-
-  bool WasNotifiedOfSubtreeChange() const {
-    return layout_object_->WasNotifiedOfSubtreeChange();
-  }
-
-  void HandleSubtreeModifications() {
-    layout_object_->HandleSubtreeModifications();
-  }
-
-  bool NeedsOverflowRecalcAfterStyleChange() const {
-    return layout_object_->NeedsOverflowRecalcAfterStyleChange();
-  }
-
-  CompositingState GetCompositingState() const {
-    return layout_object_->GetCompositingState();
-  }
-
-  bool MapToVisualRectInAncestorSpace(
-      const LayoutBoxModelObject* ancestor,
-      LayoutRect& layout_rect,
-      VisualRectFlags flags = kDefaultVisualRectFlags) const {
-    return layout_object_->MapToVisualRectInAncestorSpace(ancestor, layout_rect,
-                                                          flags);
-  }
-
-  Color ResolveColor(const CSSProperty& color_property) const {
-    return layout_object_->ResolveColor(color_property);
-  }
-
-  void InvalidatePaintRectangle(const LayoutRect& dirty_rect) const {
-    layout_object_->InvalidatePaintRectangle(dirty_rect);
-  }
-
-  scoped_refptr<ComputedStyle> GetUncachedPseudoStyle(
-      const PseudoStyleRequest& pseudo_style_request,
-      const ComputedStyle* parent_style = nullptr) const {
-    return layout_object_->GetUncachedPseudoStyle(pseudo_style_request,
-                                                  parent_style);
-  }
-
- protected:
-  LayoutObject* GetLayoutObject() { return layout_object_; }
-  const LayoutObject* GetLayoutObject() const { return layout_object_; }
-
- private:
-  LayoutObject* layout_object_;
-
-  friend class LayoutAPIShim;
-};
-
-}  // namespace blink
-
-#endif  // LayoutItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h b/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h
deleted file mode 100644
index fb32af8b..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h
+++ /dev/null
@@ -1,38 +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 LayoutLIItem_h
-#define LayoutLIItem_h
-
-#include "core/layout/LayoutListItem.h"
-#include "core/layout/api/LayoutBoxItem.h"
-
-namespace blink {
-
-class LayoutLIItem : public LayoutBoxItem {
- public:
-  explicit LayoutLIItem(LayoutListItem* layout_list_item)
-      : LayoutBoxItem(layout_list_item) {}
-
-  explicit LayoutLIItem(const LayoutItem& item) : LayoutBoxItem(item) {
-    SECURITY_DCHECK(!item || item.IsListItem());
-  }
-
-  explicit LayoutLIItem(std::nullptr_t) : LayoutBoxItem(nullptr) {}
-
-  LayoutLIItem() {}
-
-  ListItemOrdinal& Ordinal() { return ToListItem()->Ordinal(); }
-
- private:
-  LayoutListItem* ToListItem() { return ToLayoutListItem(GetLayoutObject()); }
-
-  const LayoutListItem* ToListItem() const {
-    return ToLayoutListItem(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutLIItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h b/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h
deleted file mode 100644
index 7fb4056..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h
+++ /dev/null
@@ -1,39 +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 LayoutMenuListItem_h
-#define LayoutMenuListItem_h
-
-#include "core/layout/LayoutMenuList.h"
-#include "core/layout/api/LayoutBlockItem.h"
-
-namespace blink {
-
-class LayoutMenuListItem : public LayoutBlockItem {
- public:
-  explicit LayoutMenuListItem(LayoutBlock* layout_block)
-      : LayoutBlockItem(layout_block) {}
-
-  explicit LayoutMenuListItem(const LayoutBlockItem& item)
-      : LayoutBlockItem(item) {
-    SECURITY_DCHECK(!item || item.IsMenuList());
-  }
-
-  explicit LayoutMenuListItem(std::nullptr_t) : LayoutBlockItem(nullptr) {}
-
-  LayoutMenuListItem() {}
-
-  String GetText() const { return ToMenuList()->GetText(); }
-
- private:
-  LayoutMenuList* ToMenuList() { return ToLayoutMenuList(GetLayoutObject()); }
-  const LayoutMenuList* ToMenuList() const {
-    return ToLayoutMenuList(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutMenuListItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h b/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h
deleted file mode 100644
index 51829e0a..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h
+++ /dev/null
@@ -1,41 +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 LayoutProgressItem_h
-#define LayoutProgressItem_h
-
-#include "core/layout/LayoutProgress.h"
-#include "core/layout/api/LayoutBlockItem.h"
-
-namespace blink {
-
-class LayoutProgressItem : public LayoutBlockItem {
- public:
-  explicit LayoutProgressItem(LayoutProgress* layout_progress)
-      : LayoutBlockItem(layout_progress) {}
-
-  explicit LayoutProgressItem(const LayoutBlockItem& item)
-      : LayoutBlockItem(item) {
-    SECURITY_DCHECK(!item || item.IsProgress());
-  }
-
-  explicit LayoutProgressItem(std::nullptr_t) : LayoutBlockItem(nullptr) {}
-
-  LayoutProgressItem() {}
-
-  bool IsDeterminate() const { return ToProgress()->IsDeterminate(); }
-
-  void UpdateFromElement() { return ToProgress()->UpdateFromElement(); }
-
- private:
-  LayoutProgress* ToProgress() { return ToLayoutProgress(GetLayoutObject()); }
-  const LayoutProgress* ToProgress() const {
-    return ToLayoutProgress(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutProgressItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.cpp b/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.cpp
deleted file mode 100644
index 413de55..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.cpp
+++ /dev/null
@@ -1,35 +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 "core/layout/api/LayoutSliderItem.h"
-
-#include "core/layout/LayoutSlider.h"
-
-namespace blink {
-
-LayoutSliderItem::LayoutSliderItem(LayoutSlider* layout_slider)
-    : LayoutBlockItem(layout_slider) {}
-
-LayoutSliderItem::LayoutSliderItem(const LayoutBlockItem& item)
-    : LayoutBlockItem(item) {
-  SECURITY_DCHECK(!item || item.IsSlider());
-}
-
-LayoutSliderItem::LayoutSliderItem(std::nullptr_t) : LayoutBlockItem(nullptr) {}
-
-LayoutSliderItem::LayoutSliderItem() = default;
-
-bool LayoutSliderItem::InDragMode() const {
-  return ToSlider()->InDragMode();
-}
-
-LayoutSlider* LayoutSliderItem::ToSlider() {
-  return ToLayoutSlider(GetLayoutObject());
-}
-
-const LayoutSlider* LayoutSliderItem::ToSlider() const {
-  return ToLayoutSlider(GetLayoutObject());
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h b/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h
deleted file mode 100644
index cc4c7890..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h
+++ /dev/null
@@ -1,34 +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 LayoutSliderItem_h
-#define LayoutSliderItem_h
-
-#include "core/CoreExport.h"
-#include "core/layout/api/LayoutBlockItem.h"
-
-namespace blink {
-
-class LayoutSlider;
-
-class CORE_EXPORT LayoutSliderItem : public LayoutBlockItem {
- public:
-  explicit LayoutSliderItem(LayoutSlider*);
-
-  explicit LayoutSliderItem(const LayoutBlockItem&);
-
-  explicit LayoutSliderItem(std::nullptr_t);
-
-  LayoutSliderItem();
-
-  bool InDragMode() const;
-
- private:
-  LayoutSlider* ToSlider();
-  const LayoutSlider* ToSlider() const;
-};
-
-}  // namespace blink
-
-#endif  // LayoutSliderItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.h
deleted file mode 100644
index 379481b..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.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 LayoutTextControlItem_h
-#define LayoutTextControlItem_h
-
-#include "core/layout/LayoutTextControl.h"
-#include "core/layout/api/LayoutBoxModel.h"
-#include "platform/scroll/ScrollTypes.h"
-
-namespace blink {
-
-class LayoutTextControlItem : public LayoutBoxModel {
- public:
-  explicit LayoutTextControlItem(LayoutTextControl* layout_text_control)
-      : LayoutBoxModel(layout_text_control) {}
-
-  explicit LayoutTextControlItem(const LayoutItem& item)
-      : LayoutBoxModel(item) {
-    SECURITY_DCHECK(!item || item.IsTextControl());
-  }
-
-  explicit LayoutTextControlItem(std::nullptr_t) : LayoutBoxModel(nullptr) {}
-
-  LayoutTextControlItem() {}
-
-  scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
-      const ComputedStyle& start_style) const {
-    return ToTextControl()->CreateInnerEditorStyle(start_style);
-  }
-
- private:
-  LayoutTextControl* ToTextControl() {
-    return ToLayoutTextControl(GetLayoutObject());
-  }
-
-  const LayoutTextControl* ToTextControl() const {
-    return ToLayoutTextControl(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutTextControlItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h
deleted file mode 100644
index 7d6f84a..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h
+++ /dev/null
@@ -1,50 +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 LayoutTextFragmentItem_h
-#define LayoutTextFragmentItem_h
-
-#include "core/layout/LayoutTextFragment.h"
-#include "core/layout/api/LayoutTextItem.h"
-
-namespace blink {
-
-class FirstLetterPseudoElement;
-
-class LayoutTextFragmentItem : public LayoutTextItem {
- public:
-  explicit LayoutTextFragmentItem(LayoutTextFragment* layout_text_fragment)
-      : LayoutTextItem(layout_text_fragment) {}
-
-  explicit LayoutTextFragmentItem(const LayoutTextItem& item)
-      : LayoutTextItem(item) {
-    SECURITY_DCHECK(!item || item.IsTextFragment());
-  }
-
-  explicit LayoutTextFragmentItem(std::nullptr_t) : LayoutTextItem(nullptr) {}
-
-  LayoutTextFragmentItem() {}
-
-  void SetTextFragment(scoped_refptr<StringImpl> text,
-                       unsigned start,
-                       unsigned length) {
-    ToTextFragment()->SetTextFragment(std::move(text), start, length);
-  }
-
-  FirstLetterPseudoElement* GetFirstLetterPseudoElement() const {
-    return ToTextFragment()->GetFirstLetterPseudoElement();
-  }
-
- private:
-  LayoutTextFragment* ToTextFragment() {
-    return ToLayoutTextFragment(GetLayoutObject());
-  }
-  const LayoutTextFragment* ToTextFragment() const {
-    return ToLayoutTextFragment(GetLayoutObject());
-  }
-};
-
-}  // namespace blink
-
-#endif  // LayoutTextFragmentItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h
deleted file mode 100644
index c2329cf..0000000
--- a/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h
+++ /dev/null
@@ -1,47 +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 LayoutTextItem_h
-#define LayoutTextItem_h
-
-#include "core/layout/LayoutText.h"
-#include "core/layout/api/LayoutItem.h"
-
-namespace blink {
-
-class ComputedStyle;
-
-class LayoutTextItem : public LayoutItem {
- public:
-  explicit LayoutTextItem(LayoutText* layout_text) : LayoutItem(layout_text) {}
-
-  explicit LayoutTextItem(const LayoutItem& item) : LayoutItem(item) {
-    SECURITY_DCHECK(!item || item.IsText());
-  }
-
-  explicit LayoutTextItem(std::nullptr_t) : LayoutItem(nullptr) {}
-
-  LayoutTextItem() {}
-
-  void SetStyle(scoped_refptr<ComputedStyle> style) {
-    ToText()->SetStyle(std::move(style));
-  }
-
-  void SetText(scoped_refptr<StringImpl> text, bool force = false) {
-    ToText()->SetText(std::move(text), force);
-  }
-
-  bool IsTextFragment() const { return ToText()->IsTextFragment(); }
-
-  void DirtyLineBoxes() { ToText()->DirtyLineBoxes(); }
-
- private:
-  LayoutText* ToText() { return ToLayoutText(GetLayoutObject()); }
-  const LayoutText* ToText() const { return ToLayoutText(GetLayoutObject()); }
-};
-
-}  // namespace blink
-
-#endif  // LayoutTextItem_h
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc
index 223e988..7b20850 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -116,15 +116,29 @@
   items->push_back(NGInlineItem(type, start, end, style, layout_object));
 }
 
+static inline bool ShouldIgnore(UChar c) {
+  // Ignore carriage return and form feed.
+  // https://drafts.csswg.org/css-text-3/#white-space-processing
+  // https://github.com/w3c/csswg-drafts/issues/855
+  //
+  // Unicode Default_Ignorable is not included because we need some of them
+  // in the line breaker (e.g., SOFT HYPHEN.) HarfBuzz ignores them while
+  // shaping.
+  return c == kCarriageReturnCharacter || c == kFormFeedCharacter;
+}
+
 static inline bool IsCollapsibleSpace(UChar c) {
-  return c == kSpaceCharacter || c == kTabulationCharacter ||
-         c == kNewlineCharacter;
+  return c == kSpaceCharacter || c == kNewlineCharacter ||
+         c == kTabulationCharacter || c == kCarriageReturnCharacter;
 }
 
 // Characters needing a separate control item than other text items.
 // It makes the line breaker easier to handle.
 static inline bool IsControlItemCharacter(UChar c) {
-  return c == kTabulationCharacter || c == kNewlineCharacter;
+  return c == kNewlineCharacter || c == kTabulationCharacter ||
+         // Include ignorable character here to avoids shaping/rendering
+         // these glyphs, and to help the line breaker to ignore them.
+         ShouldIgnore(c);
 }
 
 template <typename OffsetMappingBuilder>
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc
index 6427f1d..bf200d5 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder_test.cc
@@ -13,6 +13,11 @@
 
 namespace {
 
+#define EXPECT_ITEM_OFFSET(item, type, start, end) \
+  EXPECT_EQ(type, (item).Type());                  \
+  EXPECT_EQ(start, (item).StartOffset());          \
+  EXPECT_EQ(end, (item).EndOffset());
+
 static scoped_refptr<ComputedStyle> CreateWhitespaceStyle(
     EWhiteSpace whitespace) {
   scoped_refptr<ComputedStyle> style(ComputedStyle::Create());
@@ -363,6 +368,28 @@
   EXPECT_EQ(NGInlineItem::kControl, items_[5].Type());
 }
 
+TEST_F(NGInlineItemsBuilderTest, IgnorablePre) {
+  SetWhiteSpace(EWhiteSpace::kPre);
+  EXPECT_EQ(
+      "apple"
+      "\x0c"
+      "orange"
+      "\n"
+      "grape",
+      TestAppend("apple"
+                 "\x0c"
+                 "orange"
+                 "\n"
+                 "grape"));
+  EXPECT_EQ("{}", collapsed_);
+  EXPECT_EQ(5u, items_.size());
+  EXPECT_ITEM_OFFSET(items_[0], NGInlineItem::kText, 0u, 5u);
+  EXPECT_ITEM_OFFSET(items_[1], NGInlineItem::kControl, 5u, 6u);
+  EXPECT_ITEM_OFFSET(items_[2], NGInlineItem::kText, 6u, 12u);
+  EXPECT_ITEM_OFFSET(items_[3], NGInlineItem::kControl, 12u, 13u);
+  EXPECT_ITEM_OFFSET(items_[4], NGInlineItem::kText, 13u, 18u);
+}
+
 TEST_F(NGInlineItemsBuilderTest, Empty) {
   Vector<NGInlineItem> items;
   NGInlineItemsBuilderForOffsetMapping builder(&items);
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index 1f9b0687..e156753e 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -504,6 +504,12 @@
       item_result->can_break_after = true;
       break;
     }
+    case kCarriageReturnCharacter:
+    case kFormFeedCharacter:
+      // Ignore carriage return and form feed.
+      // https://drafts.csswg.org/css-text-3/#white-space-processing
+      // https://github.com/w3c/csswg-drafts/issues/855
+      break;
     default:
       NOTREACHED();
       break;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp
index ca1bba93..6b11efce 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp
@@ -36,8 +36,9 @@
     return SVGLayoutSupport::IsLayoutableTextNode(child);
 
   if (IsSVGAElement(*GetNode())) {
+    Node* child_node = child->GetNode();
     // Disallow direct descendant 'a'.
-    if (IsSVGAElement(*child->GetNode()))
+    if (child_node && IsSVGAElement(*child_node))
       return false;
   }
 
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp
index c59a722ed..e9830df 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGTransformableContainer.cpp
@@ -45,19 +45,21 @@
     LayoutObject* child,
     const ComputedStyle& style) const {
   DCHECK(GetElement());
+  Node* child_node = child->GetNode();
   if (IsSVGSwitchElement(*GetElement())) {
-    Node* node = child->GetNode();
     // Reject non-SVG/non-valid elements.
-    if (!node->IsSVGElement() || !ToSVGElement(node)->IsValid())
+    if (!child_node || !child_node->IsSVGElement() ||
+        !ToSVGElement(child_node)->IsValid()) {
       return false;
+    }
     // Reject this child if it isn't the first valid node.
-    if (HasValidPredecessor(node))
+    if (HasValidPredecessor(child_node))
       return false;
   } else if (IsSVGAElement(*GetElement())) {
     // http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
     // The 'a' element may contain any element that its parent may contain,
     // except itself.
-    if (IsSVGAElement(*child->GetNode()))
+    if (child_node && IsSVGAElement(*child_node))
       return false;
     if (Parent() && Parent()->IsSVG())
       return Parent()->IsChildAllowed(child, style);
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
index ccfec56..b30cb08 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGViewportContainer.h
@@ -42,6 +42,10 @@
 
   const char* GetName() const override { return "LayoutSVGViewportContainer"; }
 
+  AffineTransform LocalToSVGParentTransform() const override {
+    return local_to_parent_transform_;
+  }
+
  private:
   bool IsOfType(LayoutObjectType type) const override {
     return type == kLayoutObjectSVGViewportContainer ||
@@ -50,10 +54,6 @@
 
   void UpdateLayout() override;
 
-  AffineTransform LocalToSVGParentTransform() const override {
-    return local_to_parent_transform_;
-  }
-
   SVGTransformChange CalculateLocalTransform() override;
 
   bool NodeAtFloatPoint(HitTestResult&,
diff --git a/third_party/WebKit/Source/core/loader/README.md b/third_party/WebKit/Source/core/loader/README.md
new file mode 100644
index 0000000..6495406
--- /dev/null
+++ b/third_party/WebKit/Source/core/loader/README.md
@@ -0,0 +1,6 @@
+High-level fetching code.
+
+Fetching/loading code is divided into:
+- core/fetch: Fetch API
+- core/loader: high-level fetching
+- platform/loader/fetch: low-level fetching
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index 523082f..5ce9190 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -117,7 +117,6 @@
 scoped_refptr<Image> OffscreenCanvas::GetSourceImageForCanvas(
     SourceImageStatus* status,
     AccelerationHint hint,
-    SnapshotReason reason,
     const FloatSize& size) {
   if (!context_) {
     *status = kInvalidSourceImageStatus;
@@ -130,7 +129,7 @@
     *status = kZeroSizeCanvasSourceImageStatus;
     return nullptr;
   }
-  scoped_refptr<Image> image = context_->GetImage(hint, reason);
+  scoped_refptr<Image> image = context_->GetImage(hint);
   if (!image)
     image = CreateTransparentImage(Size());
   *status = image ? kNormalSourceImageStatus : kInvalidSourceImageStatus;
@@ -389,9 +388,8 @@
 
   CanvasAsyncBlobCreator* async_creator = nullptr;
   scoped_refptr<StaticBitmapImage> snapshot =
-      context_
-          ? context_->GetImage(kPreferNoAcceleration, kSnapshotReasonUnknown)
-          : CreateTransparentImage(size_);
+      context_ ? context_->GetImage(kPreferNoAcceleration)
+               : CreateTransparentImage(size_);
   if (snapshot) {
     String encoding_mime_type = ImageEncoderUtils::ToEncodingMimeType(
         options.type(), ImageEncoderUtils::kEncodeReasonConvertToBlobPromise);
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
index d4a95b97..c32411a42 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
@@ -136,7 +136,6 @@
   // CanvasImageSource implementation
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) final;
   bool WouldTaintOrigin(const SecurityOrigin*) const final {
     return !origin_clean_;
diff --git a/third_party/WebKit/Source/core/paint/PaintInfo.h b/third_party/WebKit/Source/core/paint/PaintInfo.h
index ded8bc5..f0314ef2 100644
--- a/third_party/WebKit/Source/core/paint/PaintInfo.h
+++ b/third_party/WebKit/Source/core/paint/PaintInfo.h
@@ -43,7 +43,6 @@
 #include "platform/transforms/AffineTransform.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/HashMap.h"
-#include "platform/wtf/ListHashSet.h"
 
 #include <limits>
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index 8354194..ad66b87 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -68,7 +68,6 @@
 #include "core/layout/LayoutScrollbarPart.h"
 #include "core/layout/LayoutTheme.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutBoxItem.h"
 #include "core/layout/ng/legacy_layout_tree_walking.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/page/ChromeClient.h"
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 9765dfc..2a032bf 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -16,6 +16,7 @@
 #include "core/layout/LayoutView.h"
 #include "core/layout/svg/LayoutSVGResourceMasker.h"
 #include "core/layout/svg/LayoutSVGRoot.h"
+#include "core/layout/svg/LayoutSVGViewportContainer.h"
 #include "core/layout/svg/SVGLayoutSupport.h"
 #include "core/layout/svg/SVGResources.h"
 #include "core/layout/svg/SVGResourcesCache.h"
@@ -960,9 +961,12 @@
 }
 
 static bool NeedsOverflowClip(const LayoutObject& object) {
-  return object.IsBox() && ToLayoutBox(object).ShouldClipOverflow() &&
-         (!object.IsLayoutView() ||
-          NeedsFrameContentClip(*ToLayoutView(object).GetFrame()));
+  if (object.IsBox() && ToLayoutBox(object).ShouldClipOverflow()) {
+    return !object.IsLayoutView() ||
+           NeedsFrameContentClip(*ToLayoutView(object).GetFrame());
+  }
+  return object.IsSVGViewportContainer() &&
+         SVGLayoutSupport::IsOverflowHidden(&object);
 }
 
 static bool NeedsInnerBorderRadiusClip(const LayoutObject& object) {
@@ -1048,17 +1052,25 @@
       full_context_.force_subtree_update) {
     bool clip_added_or_removed;
     if (NeedsOverflowClip(object_)) {
-      const LayoutBox& box = ToLayoutBox(object_);
-      LayoutRect clip_rect;
-      clip_rect = box.OverflowClipRect(context_.current.paint_offset);
-      FloatRoundedRect clipping_rect((FloatRect(clip_rect)));
+      FloatRoundedRect clip_rect;
+      if (object_.IsBox()) {
+        clip_rect =
+            FloatRoundedRect(FloatRect(ToLayoutBox(object_).OverflowClipRect(
+                context_.current.paint_offset)));
+      } else {
+        DCHECK(object_.IsSVGViewportContainer());
+        const auto& viewport_container = ToLayoutSVGViewportContainer(object_);
+        clip_rect = FloatRoundedRect(
+            viewport_container.LocalToSVGParentTransform().Inverse().MapRect(
+                viewport_container.Viewport()));
+      }
+
       if (!full_context_.clip_changed && properties_->OverflowClip() &&
-          clipping_rect != properties_->OverflowClip()->ClipRect())
+          clip_rect != properties_->OverflowClip()->ClipRect())
         full_context_.clip_changed = true;
 
       auto result = properties_->UpdateOverflowClip(
-          context_.current.clip, context_.current.transform,
-          FloatRoundedRect(FloatRect(clip_rect)));
+          context_.current.clip, context_.current.transform, clip_rect);
       clip_added_or_removed = result.NewNodeCreated();
     } else {
       clip_added_or_removed = properties_->ClearOverflowClip();
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index 147046bf..6b79140 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -1189,6 +1189,64 @@
             div_with_transform_properties->Transform()->Parent());
 }
 
+TEST_P(PaintPropertyTreeBuilderTest, SVGViewportContainer) {
+  SetBodyInnerHTML(R"HTML(
+    <svg id='svg'>
+      <svg id='container1' width='30' height='30'></svg>
+      <svg id='container2'
+          width='30' height='30' x='40' y='50' viewBox='0 0 60 60'></svg>
+      <svg id='container3' overflow='visible' width='30' height='30'></svg>
+      <svg id='container4' overflow='visible'
+          width='30' height='30' x='20' y='30'></svg>
+    </svg>
+  )HTML");
+
+  const auto* svg_properties = PaintPropertiesForElement("svg");
+  ASSERT_NE(nullptr, svg_properties);
+  const auto* parent_transform = svg_properties->PaintOffsetTranslation();
+  const auto* parent_clip = svg_properties->OverflowClip();
+
+  // overflow: hidden and zero offset: OverflowClip only.
+  const auto* properties1 = PaintPropertiesForElement("container1");
+  ASSERT_NE(nullptr, properties1);
+  const auto* clip = properties1->OverflowClip();
+  const auto* transform = properties1->Transform();
+  ASSERT_NE(nullptr, clip);
+  EXPECT_EQ(nullptr, transform);
+  EXPECT_EQ(parent_clip, clip->Parent());
+  EXPECT_EQ(FloatRect(0, 0, 30, 30), clip->ClipRect().Rect());
+  EXPECT_EQ(parent_transform, clip->LocalTransformSpace());
+
+  // overflow: hidden and non-zero offset and viewport scale:
+  // both Transform and OverflowClip.
+  const auto* properties2 = PaintPropertiesForElement("container2");
+  ASSERT_NE(nullptr, properties2);
+  clip = properties2->OverflowClip();
+  transform = properties2->Transform();
+  ASSERT_NE(nullptr, clip);
+  ASSERT_NE(nullptr, transform);
+  EXPECT_EQ(parent_clip, clip->Parent());
+  EXPECT_EQ(FloatRect(0, 0, 60, 60), clip->ClipRect().Rect());
+  EXPECT_EQ(transform, clip->LocalTransformSpace());
+  EXPECT_EQ(TransformationMatrix().Translate(40, 50).Scale(0.5),
+            transform->Matrix());
+  EXPECT_EQ(parent_transform, transform->Parent());
+
+  // overflow: visible and zero offset: no paint properties.
+  const auto* properties3 = PaintPropertiesForElement("container3");
+  EXPECT_EQ(nullptr, properties3);
+
+  // overflow: visible and non-zero offset: Transform only.
+  const auto* properties4 = PaintPropertiesForElement("container4");
+  ASSERT_NE(nullptr, properties4);
+  clip = properties4->OverflowClip();
+  transform = properties4->Transform();
+  EXPECT_EQ(nullptr, clip);
+  ASSERT_NE(nullptr, transform);
+  EXPECT_EQ(TransformationMatrix().Translate(20, 30), transform->Matrix());
+  EXPECT_EQ(parent_transform, transform->Parent());
+}
+
 TEST_P(PaintPropertyTreeBuilderTest,
        PaintOffsetTranslationSVGHTMLBoundaryMulticol) {
   SetBodyInnerHTML(R"HTML(
diff --git a/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp b/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
index dccde27..f136d14 100644
--- a/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
@@ -45,14 +45,24 @@
       layout_svg_container_.LocalToSVGParentTransform());
   {
     Optional<FloatClipRecorder> clip_recorder;
+    Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
     if (layout_svg_container_.IsSVGViewportContainer() &&
         SVGLayoutSupport::IsOverflowHidden(&layout_svg_container_)) {
-      FloatRect viewport =
-          layout_svg_container_.LocalToSVGParentTransform().Inverse().MapRect(
-              ToLayoutSVGViewportContainer(layout_svg_container_).Viewport());
-      clip_recorder.emplace(paint_info_before_filtering.context,
-                            layout_svg_container_,
-                            paint_info_before_filtering.phase, viewport);
+      if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
+        const auto* properties =
+            layout_svg_container_.FirstFragment().PaintProperties();
+        DCHECK(properties && properties->OverflowClip());
+        scoped_paint_chunk_properties.emplace(
+            paint_info.context.GetPaintController(), properties->OverflowClip(),
+            layout_svg_container_, paint_info.DisplayItemTypeForClipping());
+      } else {
+        FloatRect viewport =
+            layout_svg_container_.LocalToSVGParentTransform().Inverse().MapRect(
+                ToLayoutSVGViewportContainer(layout_svg_container_).Viewport());
+        clip_recorder.emplace(paint_info_before_filtering.context,
+                              layout_svg_container_,
+                              paint_info_before_filtering.phase, viewport);
+      }
     }
 
     SVGPaintContext paint_context(layout_svg_container_,
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
index 1b71bdd..4068233 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
@@ -47,7 +47,6 @@
 #include "core/layout/LayoutInline.h"
 #include "core/layout/LayoutVideo.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/loader/resource/ImageResourceContent.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index aef84a1..7638480 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -107,7 +107,6 @@
 #include "core/layout/LayoutObject.h"
 #include "core/layout/LayoutTreeAsText.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutMenuListItem.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/HistoryItem.h"
@@ -2988,9 +2987,8 @@
   if (!layout_object || !layout_object->IsMenuList())
     return String();
 
-  LayoutMenuListItem menu_list_item =
-      LayoutMenuListItem(ToLayoutMenuList(layout_object));
-  return menu_list_item.GetText();
+  LayoutMenuList* menu_list = ToLayoutMenuList(layout_object);
+  return menu_list->GetText();
 }
 
 bool Internals::isSelectPopupVisible(Node* node) {
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index 09fd8bc1..4ae352d 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -39,7 +39,6 @@
 #include "core/workers/WorkerSettings.h"
 #include "platform/heap/Handle.h"
 #include "platform/loader/fetch/CachedMetadataHandler.h"
-#include "platform/wtf/ListHashSet.h"
 #include "services/network/public/interfaces/fetch_api.mojom-shared.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/interfaces/interface_provider.mojom-blink.h"
diff --git a/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js b/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
index eca0abb6..c57f1b57 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
@@ -93,6 +93,19 @@
   }
 
   /**
+   * @param {string} fileURL
+   * @param {boolean} isWindows
+   * @return {string}
+   */
+  static urlToPlatformPath(fileURL, isWindows) {
+    console.assert(fileURL.startsWith('file://'), 'This must be a file URL.');
+    var path = fileURL.substr(7);  // Strip off 'file://'.
+    if (isWindows)
+      return path.replace(/\//g, '\\');
+    return path;
+  }
+
+  /**
    * @param {string} url
    * @return {string}
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js b/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js
index 4e89b71..10594ac17 100644
--- a/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js
+++ b/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js
@@ -490,6 +490,14 @@
 
     /**
      * @override
+     * @param {string} fileSystemPath
+     */
+    showItemInFolder(fileSystemPath) {
+      DevToolsAPI.sendMessageToEmbedder('showItemInFolder', [fileSystemPath], null);
+    }
+
+    /**
+     * @override
      * @param {string} url
      * @param {string} content
      * @param {boolean} forceSaveAs
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ColorSwatchPopoverIcon.js b/third_party/WebKit/Source/devtools/front_end/elements/ColorSwatchPopoverIcon.js
index 68cd7b24..81a8f03 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ColorSwatchPopoverIcon.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ColorSwatchPopoverIcon.js
@@ -17,6 +17,7 @@
 
     this._swatch.iconElement().title = Common.UIString('Open cubic bezier editor.');
     this._swatch.iconElement().addEventListener('click', this._iconClick.bind(this), false);
+    this._swatch.iconElement().addEventListener('mousedown', event => event.consume(), false);
 
     this._boundBezierChanged = this._bezierChanged.bind(this);
     this._boundOnScroll = this._onScroll.bind(this);
@@ -102,6 +103,7 @@
     var shiftClickMessage = Common.UIString('Shift + Click to change color format.');
     this._swatch.iconElement().title = Common.UIString('Open color picker. %s', shiftClickMessage);
     this._swatch.iconElement().addEventListener('click', this._iconClick.bind(this));
+    this._swatch.iconElement().addEventListener('mousedown', event => event.consume(), false);
     this._contrastInfo = null;
 
     this._boundSpectrumChanged = this._spectrumChanged.bind(this);
@@ -225,6 +227,7 @@
 
     this._iconElement.title = Common.UIString('Open shadow editor.');
     this._iconElement.addEventListener('click', this._iconClick.bind(this), false);
+    this._iconElement.addEventListener('mousedown', event => event.consume(), false);
 
     this._boundShadowChanged = this._shadowChanged.bind(this);
     this._boundOnScroll = this._onScroll.bind(this);
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
index d502c631..b7e1136 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -62,11 +62,6 @@
     /** @type {?RegExp} */
     this._filterRegex = null;
 
-    /** @type {?Elements.StylePropertyTreeElement} */
-    this._mouseDownTreeElement = null;
-    this._mouseDownTreeElementIsName = false;
-    this._mouseDownTreeElementIsValue = false;
-
     this.contentElement.classList.add('styles-pane');
 
     /** @type {!Array<!Elements.SectionBlock>} */
@@ -1462,7 +1457,11 @@
       event.consume();
       return;
     }
-    this.addNewBlankProperty().startEditing();
+    var deepTarget = event.deepElementFromPoint();
+    if (deepTarget.treeElement)
+      this.addNewBlankProperty(deepTarget.treeElement.property.index + 1).startEditing();
+    else
+      this.addNewBlankProperty().startEditing();
     event.consume(true);
   }
 
@@ -2300,30 +2299,15 @@
   onattach() {
     this.updateTitle();
 
-    this.listItemElement.addEventListener('mousedown', this._mouseDown.bind(this));
-    this.listItemElement.addEventListener('mouseup', this._resetMouseDownElement.bind(this));
-    this.listItemElement.addEventListener('click', this._mouseClick.bind(this));
-  }
-
-  /**
-   * @param {!Event} event
-   */
-  _mouseDown(event) {
-    if (this._parentPane) {
-      this._parentPane._mouseDownTreeElement = this;
-      this._parentPane._mouseDownTreeElementIsName =
-          this.nameElement && this.nameElement.isSelfOrAncestor(event.target);
-      this._parentPane._mouseDownTreeElementIsValue =
-          this.valueElement && this.valueElement.isSelfOrAncestor(event.target);
-    }
-  }
-
-  _resetMouseDownElement() {
-    if (this._parentPane) {
-      this._parentPane._mouseDownTreeElement = null;
-      this._parentPane._mouseDownTreeElementIsName = false;
-      this._parentPane._mouseDownTreeElementIsValue = false;
-    }
+    this.listItemElement.addEventListener('mousedown', event => {
+      if (event.which === 1)
+        this._parentPane[Elements.StylePropertyTreeElement.ActiveSymbol] = this;
+    }, false);
+    this.listItemElement.addEventListener('mouseup', this._mouseUp.bind(this));
+    this.listItemElement.addEventListener('click', event => {
+      if (!event.target.hasSelection() && event.target !== this.listItemElement)
+        event.consume(true);
+    });
   }
 
   /**
@@ -2399,6 +2383,7 @@
       enabledCheckboxElement.className = 'enabled-button';
       enabledCheckboxElement.type = 'checkbox';
       enabledCheckboxElement.checked = !this.property.disabled;
+      enabledCheckboxElement.addEventListener('mousedown', event => event.consume(), false);
       enabledCheckboxElement.addEventListener('click', this._toggleEnabled.bind(this), false);
       this.listItemElement.insertBefore(enabledCheckboxElement, this.listItemElement.firstChild);
     }
@@ -2407,22 +2392,20 @@
   /**
    * @param {!Event} event
    */
-  _mouseClick(event) {
-    if (event.target.hasSelection())
+  _mouseUp(event) {
+    var activeTreeElement = this._parentPane[Elements.StylePropertyTreeElement.ActiveSymbol];
+    this._parentPane[Elements.StylePropertyTreeElement.ActiveSymbol] = null;
+    if (activeTreeElement !== this)
+      return;
+    if (this.listItemElement.hasSelection())
+      return;
+    if (UI.isBeingEdited(/** @type {!Node} */ (event.target)))
       return;
 
     event.consume(true);
 
-    if (event.target === this.listItemElement) {
-      var section = this.section();
-      if (!section || !section.editable)
-        return;
-
-      if (section._checkWillCancelEditing())
-        return;
-      section.addNewBlankProperty(this.property.index + 1).startEditing();
+    if (event.target === this.listItemElement)
       return;
-    }
 
     if (UI.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */ (event)) && this.section().navigable) {
       this._navigateToSource(/** @type {!Element} */ (event.target));
@@ -2545,18 +2528,10 @@
      * @this {Elements.StylePropertyTreeElement}
      */
     function blurListener(context, event) {
-      var treeElement = this._parentPane._mouseDownTreeElement;
-      var moveDirection = '';
-      if (treeElement === this) {
-        if (isEditingName && this._parentPane._mouseDownTreeElementIsValue)
-          moveDirection = 'forward';
-        if (!isEditingName && this._parentPane._mouseDownTreeElementIsName)
-          moveDirection = 'backward';
-      }
       var text = event.target.textContent;
       if (!context.isEditingName)
         text = this.value || text;
-      this._editingCommitted(text, context, moveDirection);
+      this._editingCommitted(text, context, '');
     }
 
     this._originalPropertyText = this.property.propertyText;
@@ -2690,8 +2665,6 @@
    * @param {!Elements.StylePropertyTreeElement.Context} context
    */
   editingEnded(context) {
-    this._resetMouseDownElement();
-
     this.setExpandable(context.hasChildren);
     if (context.expanded)
       this.expand();
@@ -2969,6 +2942,7 @@
 
 /** @typedef {{expanded: boolean, hasChildren: boolean, isEditingName: boolean, previousContent: string}} */
 Elements.StylePropertyTreeElement.Context;
+Elements.StylePropertyTreeElement.ActiveSymbol = Symbol('ActiveSymbol');
 
 Elements.StylesSidebarPane.CSSPropertyPrompt = class extends UI.TextPrompt {
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js
index 45a8df3..fcaff2c 100644
--- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js
+++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js
@@ -172,6 +172,14 @@
 
   /**
    * @override
+   * @param {string} fileSystemPath
+   */
+  showItemInFolder(fileSystemPath) {
+    Common.console.error('Show item in folder is not enabled in hosted mode. Please inspect using chrome://inspect');
+  }
+
+  /**
+   * @override
    * @param {string} url
    * @param {string} content
    * @param {boolean} forceSaveAs
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
index eff255ed..caa1d51 100644
--- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
+++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -165,6 +165,11 @@
   /**
    * @param {string} fileSystemPath
    */
+  showItemInFolder(fileSystemPath) {},
+
+  /**
+   * @param {string} fileSystemPath
+   */
   removeFileSystem(fileSystemPath) {},
 
   requestFileSystems() {},
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/PersistenceActions.js b/third_party/WebKit/Source/devtools/front_end/persistence/PersistenceActions.js
index f60f805..00bd1b4 100644
--- a/third_party/WebKit/Source/devtools/front_end/persistence/PersistenceActions.js
+++ b/third_party/WebKit/Source/devtools/front_end/persistence/PersistenceActions.js
@@ -29,6 +29,10 @@
     if (contentProvider.contentType().isDocumentOrScriptOrStyleSheet())
       contextMenu.saveSection().appendItem(Common.UIString('Save as...'), saveAs);
 
+    var path = Common.ParsedURL.urlToPlatformPath(contentProvider.contentURL(), Host.isWin());
+    contextMenu.saveSection().appendItem(
+        Common.UIString('Open in containing folder'), () => InspectorFrontendHost.showItemInFolder(path));
+
     // Retrieve uiSourceCode by URL to pick network resources everywhere.
     var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(contentProvider.contentURL());
     if (uiSourceCode && Persistence.networkPersistenceManager.canSaveUISourceCodeForOverrides(uiSourceCode)) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index b5e5e7c..a7a8d90 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -746,7 +746,7 @@
    * @param {!Sources.NavigatorFolderTreeNode} node
    */
   handleFolderContextMenu(event, node) {
-    var path = node._folderPath;
+    var path = node._folderPath || '';
     var project = node._project;
 
     var contextMenu = new UI.ContextMenu(event);
@@ -755,6 +755,10 @@
     if (project.type() !== Workspace.projectTypes.FileSystem)
       return;
 
+    var folderPath = Common.ParsedURL.urlToPlatformPath(
+        Persistence.FileSystemWorkspaceBinding.completeURL(project, path), Host.isWin());
+    contextMenu.saveSection().appendItem(
+        Common.UIString('Open folder'), () => InspectorFrontendHost.showItemInFolder(folderPath));
     contextMenu.defaultSection().appendItem(
         Common.UIString('New file'), this._handleContextMenuCreate.bind(this, project, path));
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index 1ce940a..6f2d2fa 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -75,7 +75,6 @@
 #include "core/layout/LayoutTextControl.h"
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutAPIShim.h"
 #include "core/layout/api/LineLayoutAPIShim.h"
 #include "core/loader/ProgressTracker.h"
 #include "core/page/Page.h"
diff --git a/third_party/WebKit/Source/modules/cachestorage/DEPS b/third_party/WebKit/Source/modules/cachestorage/DEPS
index 6bc2447..009800b 100644
--- a/third_party/WebKit/Source/modules/cachestorage/DEPS
+++ b/third_party/WebKit/Source/modules/cachestorage/DEPS
@@ -4,7 +4,6 @@
     "+modules/EventTargetModules.h",
     "+modules/ModulesExport.h",
     "+modules/cachestorage",
-    "+modules/fetch",
     "+modules/serviceworkers",
     "+services/network/public/interfaces",
 ]
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
index 4211a00..e4f6e11 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
@@ -1204,7 +1204,6 @@
                                 ? kPreferAcceleration
                                 : kPreferNoAcceleration;
     image = image_source->GetSourceImageForCanvas(&source_image_status, hint,
-                                                  kSnapshotReasonDrawImage,
                                                   default_object_size);
     if (source_image_status == kUndecodableSourceImageStatus) {
       exception_state.ThrowDOMException(
@@ -1381,7 +1380,6 @@
   FloatSize default_object_size(Width(), Height());
   scoped_refptr<Image> image_for_rendering =
       image_source->GetSourceImageForCanvas(&status, kPreferNoAcceleration,
-                                            kSnapshotReasonCreatePattern,
                                             default_object_size);
 
   switch (status) {
@@ -1591,8 +1589,7 @@
   WTF::ArrayBufferContents contents;
 
   const CanvasColorParams& color_params = ColorParams();
-  scoped_refptr<StaticBitmapImage> snapshot =
-      GetImage(kPreferNoAcceleration, kSnapshotReasonGetImageData);
+  scoped_refptr<StaticBitmapImage> snapshot = GetImage(kPreferNoAcceleration);
 
   if (!StaticBitmapImage::ConvertToArrayBufferContents(
           snapshot, contents, image_data_rect, color_params, IsAccelerated())) {
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
index 7030d01..15528d5 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
@@ -354,8 +354,7 @@
     NOTREACHED();
     return false;
   }
-  virtual scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
-                                                    SnapshotReason) const {
+  virtual scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint) const {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp
index e1af78cf..fb4b6865d 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp
@@ -629,11 +629,10 @@
 }
 
 scoped_refptr<StaticBitmapImage> blink::CanvasRenderingContext2D::GetImage(
-    AccelerationHint hint,
-    SnapshotReason reason) const {
+    AccelerationHint hint) const {
   if (!HasCanvas2DBuffer())
     return nullptr;
-  return canvas()->Canvas2DBuffer()->NewImageSnapshot(hint, reason);
+  return canvas()->Canvas2DBuffer()->NewImageSnapshot(hint);
 }
 
 bool CanvasRenderingContext2D::ParseColorOrCurrentColor(
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h
index cf65e78..1fface0 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h
@@ -181,8 +181,7 @@
   void DisableDeferral(DisableDeferralReason) final;
 
   void DidDraw(const SkIRect& dirty_rect) final;
-  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
-                                            SnapshotReason) const final;
+  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint) const final;
 
   bool StateHasFilter() final;
   sk_sp<PaintFilter> StateGetFilter() final;
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp
index da37583a..58c89d1a 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -53,7 +53,6 @@
 
   scoped_refptr<Image> GetSourceImageForCanvas(SourceImageStatus*,
                                                AccelerationHint,
-                                               SnapshotReason,
                                                const FloatSize&) override;
 
   bool WouldTaintOrigin(
@@ -86,7 +85,6 @@
 scoped_refptr<Image> FakeImageSource::GetSourceImageForCanvas(
     SourceImageStatus* status,
     AccelerationHint,
-    SnapshotReason,
     const FloatSize&) {
   if (status)
     *status = kNormalSourceImageStatus;
@@ -1097,8 +1095,7 @@
 
   EXPECT_TRUE(CanvasElement().Canvas2DBuffer()->IsAccelerated());
   // Take a snapshot to trigger lazy resource provider creation
-  CanvasElement().Canvas2DBuffer()->NewImageSnapshot(kPreferAcceleration,
-                                                     kSnapshotReasonUnknown);
+  CanvasElement().Canvas2DBuffer()->NewImageSnapshot(kPreferAcceleration);
   EXPECT_TRUE(CanvasElement().GetLayoutBoxModelObject());
   PaintLayer* layer = CanvasElement().GetLayoutBoxModelObject()->Layer();
   EXPECT_TRUE(layer);
diff --git a/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.cpp b/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.cpp
index 059e0a6..f4611d12 100644
--- a/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.cpp
@@ -59,8 +59,7 @@
 }
 
 scoped_refptr<StaticBitmapImage> ImageBitmapRenderingContext::GetImage(
-    AccelerationHint,
-    SnapshotReason) const {
+    AccelerationHint) const {
   return image_layer_bridge_->GetImage();
 }
 
diff --git a/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.h b/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.h
index 0585a22..ce19434a 100644
--- a/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.h
+++ b/third_party/WebKit/Source/modules/canvas/imagebitmap/ImageBitmapRenderingContext.h
@@ -52,8 +52,7 @@
   void SetIsHidden(bool) override {}
   bool isContextLost() const override { return false; }
   void SetCanvasGetContextResult(RenderingContext&) final;
-  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
-                                            SnapshotReason) const final;
+  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint) const final;
   bool IsComposited() const final { return true; }
   bool IsAccelerated() const final;
 
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index fcea669..cab16ef 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -139,12 +139,12 @@
 }
 
 scoped_refptr<StaticBitmapImage> OffscreenCanvasRenderingContext2D::GetImage(
-    AccelerationHint hint,
-    SnapshotReason reason) const {
+    AccelerationHint hint) const {
   if (!HasCanvas2DBuffer())
     return nullptr;
   scoped_refptr<StaticBitmapImage> image =
       GetCanvasResourceProvider()->Snapshot();
+
   return image;
 }
 
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
index 31bac2b..e76e909 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -61,8 +61,7 @@
   void ClearRect(double x, double y, double width, double height) override {
     BaseRenderingContext2D::clearRect(x, y, width, height);
   }
-  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
-                                            SnapshotReason) const final;
+  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint) const final;
   void Reset() override;
   void RestoreCanvasMatrixClipStack(PaintCanvas* c) const override {
     RestoreMatrixClipStack(c);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementsHelper.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementsHelper.cpp
index ac0a509..57fcd2e 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementsHelper.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlElementsHelper.cpp
@@ -9,7 +9,6 @@
 #include "core/html/media/HTMLMediaElement.h"
 #include "core/layout/LayoutSlider.h"
 #include "core/layout/LayoutView.h"
-#include "core/layout/api/LayoutSliderItem.h"
 #include "modules/media_controls/elements/MediaControlDivElement.h"
 #include "modules/media_controls/elements/MediaControlInputElement.h"
 #include "public/platform/WebSize.h"
@@ -37,13 +36,12 @@
     return true;
 
   // Some events are only captured during a slider drag.
-  const LayoutSliderItem& slider =
-      LayoutSliderItem(ToLayoutSlider(layout_object));
+  const LayoutSlider* slider = ToLayoutSlider(layout_object);
   // TODO(crbug.com/695459#c1): LayoutSliderItem::inDragMode is incorrectly
   // false for drags that start from the track instead of the thumb.
   // Use SliderThumbElement::m_inDragMode and
   // SliderContainerElement::m_touchStarted instead.
-  if (!slider.IsNull() && !slider.InDragMode())
+  if (slider && !slider->InDragMode())
     return false;
 
   const AtomicString& type = event->type();
diff --git a/third_party/WebKit/Source/modules/serviceworkers/DEPS b/third_party/WebKit/Source/modules/serviceworkers/DEPS
index 3b5a86b6..273f2cf 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/DEPS
+++ b/third_party/WebKit/Source/modules/serviceworkers/DEPS
@@ -3,7 +3,6 @@
     "+modules/EventModules.h",
     "+modules/EventTargetModules.h",
     "+modules/ModulesExport.h",
-    "+modules/fetch",
     "+modules/serviceworkers",
     "+mojo/public/cpp/system/data_pipe.h",
     "+services/network/public/interfaces",
diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
index 690b011f..989f79f0 100644
--- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
@@ -92,8 +92,7 @@
 
   SourceImageStatus source_image_status = kInvalidSourceImageStatus;
   scoped_refptr<Image> image = canvas_image_source->GetSourceImageForCanvas(
-      &source_image_status, kPreferNoAcceleration, kSnapshotReasonDrawImage,
-      size);
+      &source_image_status, kPreferNoAcceleration, size);
   if (!image || source_image_status != kNormalSourceImageStatus) {
     resolver->Reject(
         DOMException::Create(kInvalidStateError, "Invalid element or state."));
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 07c463e..8f5d00f 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -650,8 +650,7 @@
     // We get a non-texture-backed image when running layout tests
     // on desktop builds. Add a slow fallback so that these continue
     // working.
-    image_ref = rendering_context_->GetImage(kPreferAcceleration,
-                                             kSnapshotReasonCreateImageBitmap);
+    image_ref = rendering_context_->GetImage(kPreferAcceleration);
     if (!image_ref.get() || !image_ref->IsTextureBacked()) {
       NOTREACHED()
           << "WebXR requires hardware-accelerated rendering to texture";
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 34ae1a8..522109d 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -759,8 +759,7 @@
 }
 
 scoped_refptr<StaticBitmapImage> WebGLRenderingContextBase::GetImage(
-    AccelerationHint hint,
-    SnapshotReason reason) const {
+    AccelerationHint hint) const {
   if (!GetDrawingBuffer())
     return nullptr;
   // If on the main thread, directly access the drawing buffer and create the
@@ -779,7 +778,7 @@
       NOTREACHED();
       return nullptr;
     }
-    return surface->NewImageSnapshot(hint, reason);
+    return surface->NewImageSnapshot(hint);
   }
 
   // If on a worker thread, create a copy from the drawing buffer and create
@@ -4952,22 +4951,6 @@
   return true;
 }
 
-SnapshotReason WebGLRenderingContextBase::FunctionIDToSnapshotReason(
-    TexImageFunctionID id) {
-  switch (id) {
-    case kTexImage2D:
-      return kSnapshotReasonWebGLTexImage2D;
-    case kTexSubImage2D:
-      return kSnapshotReasonWebGLTexSubImage2D;
-    case kTexImage3D:
-      return kSnapshotReasonWebGLTexImage3D;
-    case kTexSubImage3D:
-      return kSnapshotReasonWebGLTexSubImage3D;
-  }
-  NOTREACHED();
-  return kSnapshotReasonUnknown;
-}
-
 void WebGLRenderingContextBase::TexImageCanvasByGPU(
     TexImageFunctionID function_id,
     HTMLCanvasElement* canvas,
@@ -4980,8 +4963,7 @@
     if (Extensions3DUtil::CanUseCopyTextureCHROMIUM(target) &&
         canvas->TryCreateImageBuffer()) {
       scoped_refptr<StaticBitmapImage> image =
-          canvas->Canvas2DBuffer()->NewImageSnapshot(
-              kPreferAcceleration, FunctionIDToSnapshotReason(function_id));
+          canvas->Canvas2DBuffer()->NewImageSnapshot(kPreferAcceleration);
       if (!!image && image->CopyToTexture(
                          ContextGL(), target, target_texture,
                          unpack_premultiply_alpha_, unpack_flip_y_,
@@ -5144,10 +5126,7 @@
     if (!canvas->IsAccelerated() || !CanUseTexImageByGPU(format, type)) {
       TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
                    zoffset, format, type,
-                   canvas
-                       ->CopiedImage(kBackBuffer, kPreferAcceleration,
-                                     FunctionIDToSnapshotReason(function_id))
-                       .get(),
+                   canvas->CopiedImage(kBackBuffer, kPreferAcceleration).get(),
                    WebGLImageConversion::kHtmlDomCanvas, unpack_flip_y_,
                    unpack_premultiply_alpha_, source_sub_rectangle, 1, 0);
       return;
@@ -5178,10 +5157,7 @@
     // textures, and elements of 2D texture arrays.
     TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
                  zoffset, format, type,
-                 canvas
-                     ->CopiedImage(kBackBuffer, kPreferAcceleration,
-                                   FunctionIDToSnapshotReason(function_id))
-                     .get(),
+                 canvas->CopiedImage(kBackBuffer, kPreferAcceleration).get(),
                  WebGLImageConversion::kHtmlDomCanvas, unpack_flip_y_,
                  unpack_premultiply_alpha_, source_sub_rectangle, depth,
                  unpack_image_height);
@@ -5349,8 +5325,8 @@
                      video->videoHeight(), 0, format, type, nullptr);
 
       if (Extensions3DUtil::CanUseCopyTextureCHROMIUM(target)) {
-        scoped_refptr<StaticBitmapImage> image = surface->NewImageSnapshot(
-            kPreferAcceleration, FunctionIDToSnapshotReason(function_id));
+        scoped_refptr<StaticBitmapImage> image =
+            surface->NewImageSnapshot(kPreferAcceleration);
         if (!!image &&
             image->CopyToTexture(
                 ContextGL(), target, texture->Object(),
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 0d5b02f4..37b7188 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -590,8 +590,7 @@
     // object.
   };
 
-  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
-                                            SnapshotReason) const override;
+  scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint) const override;
   void SetFilterQuality(SkFilterQuality) override;
   bool IsWebGL2OrHigher() { return Version() >= 2; }
 
@@ -1012,8 +1011,6 @@
     kTexSubImage3D
   };
 
-  static SnapshotReason FunctionIDToSnapshotReason(TexImageFunctionID);
-
   enum TexImageDimension { kTex2D, kTex3D };
   void TexImage2DBase(GLenum target,
                       GLint level,
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 05d0740..59be242 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -732,8 +732,7 @@
 }
 
 scoped_refptr<StaticBitmapImage> Canvas2DLayerBridge::NewImageSnapshot(
-    AccelerationHint hint,
-    SnapshotReason) {
+    AccelerationHint hint) {
   if (snapshot_state_ == kInitialSnapshotState)
     snapshot_state_ = kDidAcquireSnapshot;
   if (IsHibernating())
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index 405880b..c6ce276 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -123,8 +123,7 @@
 
   bool HasRecordedDrawCommands() { return have_recorded_draw_commands_; }
 
-  scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint,
-                                                    SnapshotReason);
+  scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint);
   bool WasDrawnToAfterSnapshot() const {
     return snapshot_state_ == kDrawnToAfterSnapshot;
   }
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index 640f29a..dfe18cd3 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -160,9 +160,7 @@
 
     const GrGLTextureInfo* texture_info =
         skia::GrBackendObjectToGrGLTextureInfo(
-            bridge
-                ->NewImageSnapshot(kPreferAcceleration,
-                                   kSnapshotReasonUnitTests)
+            bridge->NewImageSnapshot(kPreferAcceleration)
                 ->PaintImageForCurrentFrame()
                 .GetSkImage()
                 ->getTextureHandle(true));
@@ -187,8 +185,8 @@
           CanvasColorParams())));
       EXPECT_TRUE(bridge->IsValid());
       EXPECT_TRUE(bridge->IsAccelerated());
-      scoped_refptr<StaticBitmapImage> snapshot = bridge->NewImageSnapshot(
-          kPreferAcceleration, kSnapshotReasonUnitTests);
+      scoped_refptr<StaticBitmapImage> snapshot =
+          bridge->NewImageSnapshot(kPreferAcceleration);
       EXPECT_TRUE(bridge->IsAccelerated());
       EXPECT_TRUE(snapshot->IsTextureBacked());
     }
@@ -207,8 +205,8 @@
       // This will cause SkSurface_Gpu creation to fail without
       // Canvas2DLayerBridge otherwise detecting that anything was disabled.
       gr->abandonContext();
-      scoped_refptr<StaticBitmapImage> snapshot = bridge->NewImageSnapshot(
-          kPreferAcceleration, kSnapshotReasonUnitTests);
+      scoped_refptr<StaticBitmapImage> snapshot =
+          bridge->NewImageSnapshot(kPreferAcceleration);
       EXPECT_FALSE(bridge->IsAccelerated());
       EXPECT_FALSE(snapshot->IsTextureBacked());
     }
@@ -233,7 +231,7 @@
     EXPECT_EQ(nullptr, bridge->GetOrCreateResourceProvider());
     // The following passes by not crashing
     bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags);
-    bridge->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
+    bridge->NewImageSnapshot(kPreferAcceleration);
   }
 
   void PrepareMailboxWhenContextIsLost() {
@@ -350,8 +348,8 @@
           CanvasColorParams())));
       PaintFlags flags;
       bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags);
-      scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(
-          kPreferAcceleration, kSnapshotReasonUnitTests);
+      scoped_refptr<StaticBitmapImage> image =
+          bridge->NewImageSnapshot(kPreferAcceleration);
       EXPECT_TRUE(bridge->IsValid());
       EXPECT_TRUE(bridge->IsAccelerated());
     }
@@ -362,8 +360,8 @@
           CanvasColorParams())));
       PaintFlags flags;
       bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags);
-      scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(
-          kPreferNoAcceleration, kSnapshotReasonUnitTests);
+      scoped_refptr<StaticBitmapImage> image =
+          bridge->NewImageSnapshot(kPreferNoAcceleration);
       EXPECT_TRUE(bridge->IsValid());
       EXPECT_FALSE(bridge->IsAccelerated());
     }
@@ -427,7 +425,7 @@
   bridge->DidDraw(FloatRect(0, 0, 1, 1));
   bridge->FinalizeFrame();
   // Grabbing an image forces a flush
-  bridge->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
+  bridge->NewImageSnapshot(kPreferAcceleration);
 }
 
 #if CANVAS2D_HIBERNATION_ENABLED
@@ -829,7 +827,7 @@
 
   // Take a snapshot and verify that it is not accelerated due to hibernation
   scoped_refptr<StaticBitmapImage> image =
-      bridge->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
+      bridge->NewImageSnapshot(kPreferAcceleration);
   EXPECT_FALSE(image->IsTextureBacked());
   image = nullptr;
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
index f78de7e..18838336 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
@@ -100,28 +100,6 @@
   kPreferNoAcceleration,
 };
 
-enum SnapshotReason {
-  kSnapshotReasonUnknown,
-  kSnapshotReasonGetImageData,
-  kSnapshotReasonWebGLTexImage2D,
-  kSnapshotReasonWebGLTexSubImage2D,
-  kSnapshotReasonWebGLTexImage3D,
-  kSnapshotReasonWebGLTexSubImage3D,
-  kSnapshotReasonPaint,
-  kSnapshotReasonToDataURL,
-  kSnapshotReasonToBlob,
-  kSnapshotReasonCanvasListenerCapture,
-  kSnapshotReasonDrawImage,
-  kSnapshotReasonCreatePattern,
-  kSnapshotReasonTransferToImageBitmap,
-  kSnapshotReasonUnitTests,
-  kSnapshotReasonGetCopiedImage,
-  kSnapshotReasonWebGLDrawImageIntoBuffer,
-  kSnapshotReasonCopyToClipboard,
-  kSnapshotReasonCreateImageBitmap,
-  kSnapshotReasonLowLatencyFrame,
-};
-
 // Note: enum used directly for histogram, values must not change
 enum DisableDeferralReason {
   kDisableDeferralReasonUnknown =
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
index 6577de36..249b704 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -76,11 +76,10 @@
 }
 
 scoped_refptr<StaticBitmapImage> ImageBuffer::NewImageSnapshot(
-    AccelerationHint hint,
-    SnapshotReason reason) const {
+    AccelerationHint hint) const {
   if (!IsSurfaceValid())
     return nullptr;
-  return surface_->NewImageSnapshot(hint, reason);
+  return surface_->NewImageSnapshot(hint);
 }
 
 bool ImageBuffer::WritePixels(const SkImageInfo& orig_info,
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
index 8fbf021..e0c72ed4 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -68,8 +68,7 @@
   PaintCanvas* Canvas() const;
 
   scoped_refptr<StaticBitmapImage> NewImageSnapshot(
-      AccelerationHint = kPreferNoAcceleration,
-      SnapshotReason = kSnapshotReasonUnknown) const;
+      AccelerationHint = kPreferNoAcceleration) const;
 
   const CanvasColorParams& ColorParams() const {
     return surface_->ColorParams();
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
index fbb7079..5cbc1ef 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
@@ -66,8 +66,8 @@
 
   // May return nullptr if the surface is GPU-backed and the GPU context was
   // lost.
-  virtual scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint,
-                                                            SnapshotReason) = 0;
+  virtual scoped_refptr<StaticBitmapImage> NewImageSnapshot(
+      AccelerationHint) = 0;
 
   const IntSize& Size() const { return size_; }
   const CanvasColorParams& ColorParams() const { return color_params_; }
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.cpp
index 7030c8c..01e2fcfb 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.cpp
@@ -78,8 +78,7 @@
 }
 
 scoped_refptr<StaticBitmapImage>
-AcceleratedImageBufferSurface::NewImageSnapshot(AccelerationHint,
-                                                SnapshotReason) {
+AcceleratedImageBufferSurface::NewImageSnapshot(AccelerationHint) {
   if (!IsValid())
     return nullptr;
   // Must make a copy of the WeakPtr because CreateFromSkImage only takes
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h
index 2ef005f..06e8e08 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h
@@ -57,8 +57,7 @@
   PaintCanvas* Canvas() override { return canvas_.get(); }
   bool IsValid() const override;
   bool IsAccelerated() const override { return true; }
-  scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint,
-                                                    SnapshotReason) override;
+  scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint) override;
   GLuint GetBackingTextureHandleForOverwrite();
   bool WritePixels(const SkImageInfo& orig_info,
                    const void* pixels,
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp
index b8f27f4..7dc1521 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp
@@ -178,7 +178,7 @@
       WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
   EXPECT_TRUE(surface->IsValid());
   scoped_refptr<StaticBitmapImage> image =
-      surface->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
+      surface->NewImageSnapshot(kPreferAcceleration);
   ::testing::Mock::VerifyAndClearExpectations(&gl_);
 
   FakeMailboxGenerator mailboxGenerator;
@@ -214,7 +214,7 @@
       WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
   EXPECT_TRUE(surface->IsValid());
   scoped_refptr<StaticBitmapImage> image =
-      surface->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
+      surface->NewImageSnapshot(kPreferAcceleration);
   ::testing::Mock::VerifyAndClearExpectations(&gl_);
 
   FakeMailboxGenerator mailboxGenerator;
@@ -241,8 +241,7 @@
   // Re-creating surface should recycle the old GrTexture inside skia
   surface = WTF::WrapUnique(new AcceleratedImageBufferSurface(size));
   EXPECT_TRUE(surface->IsValid());
-  image =
-      surface->NewImageSnapshot(kPreferAcceleration, kSnapshotReasonUnitTests);
+  image = surface->NewImageSnapshot(kPreferAcceleration);
 
   ::testing::Mock::VerifyAndClearExpectations(&gl_);
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/README.md b/third_party/WebKit/Source/platform/loader/fetch/README.md
new file mode 100644
index 0000000..5e6da72
--- /dev/null
+++ b/third_party/WebKit/Source/platform/loader/fetch/README.md
@@ -0,0 +1,6 @@
+Low-level fetching code.
+
+Fetching/loading code is divided into:
+- core/fetch: Fetch API
+- core/loader: high-level fetching
+- platform/loader/fetch: low-level fetching
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
index 0643df6..3cf4eb6 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.h
@@ -41,7 +41,6 @@
 #include "platform/loader/fetch/SubstituteData.h"
 #include "platform/wtf/HashMap.h"
 #include "platform/wtf/HashSet.h"
-#include "platform/wtf/ListHashSet.h"
 #include "platform/wtf/text/StringHash.h"
 
 namespace blink {
diff --git a/third_party/WebKit/common/service_worker/service_worker.mojom b/third_party/WebKit/common/service_worker/service_worker.mojom
index 08bfd238..3adcc2f 100644
--- a/third_party/WebKit/common/service_worker/service_worker.mojom
+++ b/third_party/WebKit/common/service_worker/service_worker.mojom
@@ -5,6 +5,7 @@
 module blink.mojom;
 
 import "third_party/WebKit/common/service_worker/service_worker_error_type.mojom";
+import "third_party/WebKit/common/service_worker/service_worker_client.mojom";
 import "url/mojo/url.mojom";
 
 // Host for a running service worker execution context. Implemented in the
@@ -19,9 +20,13 @@
   // Clears V8 code cache for |url| set by the above |SetCachedMetadata| before.
   ClearCachedMetadata(url.mojom.Url url);
 
-  // TODO(xiaofeng.zhang): Impl all methods.
+  // Corresponds to Clients#matchAll(options). Gets information of all service
+  // worker clients matching |options|.
+  GetClients(ServiceWorkerClientQueryOptions options)
+    => (array<ServiceWorkerClientInfo> clients);
+
+  // TODO(leonhsl): Impl all methods.
   // GetClient();
-  // GetClients();
   // OpenNewTab();
   // OpenNewPopup();
   // PostMessageToClient();
diff --git a/third_party/WebKit/common/service_worker/service_worker_client.mojom b/third_party/WebKit/common/service_worker/service_worker_client.mojom
index 6d802ce8..0cb17550 100644
--- a/third_party/WebKit/common/service_worker/service_worker_client.mojom
+++ b/third_party/WebKit/common/service_worker/service_worker_client.mojom
@@ -19,6 +19,16 @@
   kLast = kAll
 };
 
+// Indicates the options for the service worker clients matching operation.
+// https://w3c.github.io/ServiceWorker/#dictdef-clientqueryoptions.
+struct ServiceWorkerClientQueryOptions {
+  // ClientQueryOptions#includeUncontrolled
+  bool include_uncontrolled = false;
+
+  // ClientQueryOptions#type
+  ServiceWorkerClientType client_type = ServiceWorkerClientType.kWindow;
+};
+
 // Holds the information related to a service worker window or non-window
 // client.
 // https://w3c.github.io/ServiceWorker/#client
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index e8dce48..497c720d 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1830,6 +1830,8 @@
   kDispatchMouseUpDownEventOnDisabledFormControl = 2321,
   kCSSSelectorPseudoMatches = 2322,
   kV8RTCRtpSender_ReplaceTrack_Method = 2323,
+  kInputTypeFileSecureOriginOpenChooser = 2324,
+  kInputTypeFileInsecureOriginOpenChooser = 2325,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/breakpad/symupload.exe b/third_party/breakpad/symupload.exe
index 7e0e9fb3..67e20c2 100755
--- a/third_party/breakpad/symupload.exe
+++ b/third_party/breakpad/symupload.exe
Binary files differ
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index a0f32ad..5376c62 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -178,6 +178,11 @@
   root_gen_dir = os.path.join(tempdir, 'gen')
   mkdir_p(root_gen_dir)
 
+  write_buildflag_header_manually(
+      root_gen_dir,
+      'base/synchronization/synchronization_flags.h',
+      {'ENABLE_MUTEX_PRIORITY_INHERITANCE': 'false'})
+
   write_buildflag_header_manually(root_gen_dir, 'base/allocator/features.h',
       {'USE_ALLOCATOR_SHIM': 'true' if is_linux else 'false'})
 
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 04a731d..a2836784 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -906,16 +906,16 @@
     executable_suffix = '.exe' if self.platform == 'win32' else ''
 
     cmdline = []
-    extra_files = []
+    extra_files = [
+      '../../.vpython',
+      '../../testing/test_env.py',
+    ]
 
     if test_type == 'nontest':
       self.WriteFailureAndRaise('We should not be isolating %s.' % target,
                                 output_path=None)
 
     if is_android and test_type != "script":
-      extra_files = [
-          '../../testing/test_env.py'
-      ]
       cmdline = [
           '../../testing/test_env.py',
           '../../build/android/test_wrapper/logdog_wrapper.py',
@@ -923,18 +923,12 @@
           '--logdog-bin-cmd', '../../bin/logdog_butler',
           '--store-tombstones']
     elif is_fuchsia and test_type != 'script':
-      extra_files = [
-          '../../testing/test_env.py'
-      ]
       cmdline = [
           '../../testing/test_env.py',
           os.path.join('bin', 'run_%s' % target),
       ]
     elif use_xvfb and test_type == 'windowed_test_launcher':
-      extra_files = [
-          '../../testing/test_env.py',
-          '../../testing/xvfb.py',
-      ]
+      extra_files.append('../../testing/xvfb.py')
       cmdline = [
         '../../testing/xvfb.py',
         './' + str(executable) + executable_suffix,
@@ -946,9 +940,6 @@
         '--cfi-diag=%d' % cfi_diag,
       ]
     elif test_type in ('windowed_test_launcher', 'console_test_launcher'):
-      extra_files = [
-          '../../testing/test_env.py'
-      ]
       cmdline = [
           '../../testing/test_env.py',
           './' + str(executable) + executable_suffix,
@@ -960,15 +951,11 @@
           '--cfi-diag=%d' % cfi_diag,
       ]
     elif test_type == 'script':
-      extra_files = [
-          '../../testing/test_env.py'
-      ]
       cmdline = [
           '../../testing/test_env.py',
           '../../' + self.ToSrcRelPath(isolate_map[target]['script'])
       ]
     elif test_type in ('raw'):
-      extra_files = []
       cmdline = [
           './' + str(target) + executable_suffix,
       ]
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 68ae8fbb..29ec92e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -14321,6 +14321,7 @@
   <int value="1207" label="AUTOTESTPRIVATE_GETPRINTERLIST"/>
   <int value="1208" label="DEVELOPERPRIVATE_GETEXTENSIONSIZE"/>
   <int value="1209" label="CRYPTOTOKENPRIVATE_ISAPPIDHASHINENTERPRISECONTEXT"/>
+  <int value="1210" label="CRYPTOTOKENPRIVATE_CANAPPIDGETATTESTATION"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -17372,6 +17373,8 @@
   <int value="2321" label="DispatchMouseUpDownEventOnDisabledFormControl"/>
   <int value="2322" label="CSSSelectorPseudoMatches"/>
   <int value="2323" label="V8RTCRtpSender_ReplaceTrack_Method"/>
+  <int value="2324" label="InputTypeFileSecureOriginOpenChooser"/>
+  <int value="2325" label="InputTypeFileInsecureOriginOpenChooser"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -33820,6 +33823,8 @@
   <int value="13" label="PERMISSION_MEDIASTREAM_MIC"/>
   <int value="14" label="PERMISSION_MEDIASTREAM_CAMERA"/>
   <int value="15" label="PERMISSION_ACCESSIBILITY_EVENTS"/>
+  <int value="16" label="PERMISSION_CLIPBOARD_READ"/>
+  <int value="17" label="PERMISSION_SECURITY_KEY_ATTESTATION"/>
 </enum>
 
 <enum name="PermissionStatus">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cfe90102..8ed152f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -108049,6 +108049,7 @@
       label="registerProtocolHandler permission"/>
   <suffix name="Quota" label="Quota permission"/>
   <suffix name="MultipleDownload" label="Multiple downloads permission"/>
+  <suffix name="SecurityKeyAttestation" label="Security Key attestation"/>
   <affected-histogram name="Permissions.Engagement.Accepted"/>
   <affected-histogram name="Permissions.Engagement.Denied"/>
   <affected-histogram name="Permissions.Engagement.Dismissed"/>
diff --git a/tools/perf/contrib/leak_detection/page_sets.py b/tools/perf/contrib/leak_detection/page_sets.py
index 8575be4..a64faff 100644
--- a/tools/perf/contrib/leak_detection/page_sets.py
+++ b/tools/perf/contrib/leak_detection/page_sets.py
@@ -41,9 +41,7 @@
     urls_list = [
       # Alexa top websites
       'https://www.google.com',
-      # TODO(yuzus) Disabling youtube for the moment because of a crash when
-      # running PrepareForLeakDetection with ServiceWorker. (crbug.com/795665)
-      # 'https://www.youtube.com',
+      'https://www.youtube.com',
       'https://www.facebook.com',
       'https://www.baidu.com',
       'https://www.wikipedia.org',
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 404fd8fa..3afbe55 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -68,6 +68,16 @@
 [ Nexus_5X ] loading.mobile/Dramaq [ Skip ]
 [ Nexus_7 ] loading.mobile/Facebook [ Skip ]
 
+# Benchmark: memory.leak_detection
+crbug.com/734427 [ All ] memory.leak_detection/https://www.google.com [ Skip ]
+crbug.com/734427 [ All ] memory.leak_detection/https://www.facebook.com [ Skip ]
+crbug.com/734427 [ All ] memory.leak_detection/https://www.baidu.com [ Skip ]
+crbug.com/734427 [ All ] memory.leak_detection/https://www.wikipedia.org [ Skip ]
+crbug.com/734427 [ All ] memory.leak_detection/http://www.twitter.com [ Skip ]
+crbug.com/734427 [ All ] memory.leak_detection/https://www.yahoo.com [ Skip ]
+crbug.com/734427 [ All ] memory.leak_detection/http://www.quora.com [ Skip ]
+crbug.com/795665 [ All ] memory.leak_detection/https://www.youtube.com [ Skip ]
+
 # Benchmark: memory.long_running_idle_gmail_tbmv2
 crbug.com/611167 [ Android_Svelte ] memory.long_running_idle_gmail_tbmv2/* [ Skip ]
 
diff --git a/tools/perf/metrics/speedindex.py b/tools/perf/metrics/speedindex.py
deleted file mode 100644
index 41a1f4ce..0000000
--- a/tools/perf/metrics/speedindex.py
+++ /dev/null
@@ -1,191 +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.
-
-from telemetry.util import image_util
-from telemetry.util import rgba_color
-from telemetry.value import scalar
-
-from metrics import Metric
-
-
-class SpeedIndexMetric(Metric):
-  """The speed index metric is one way of measuring page load speed.
-
-  It is meant to approximate user perception of page load speed, and it
-  is based on the amount of time that it takes to paint to the visual
-  portion of the screen. It includes paint events that occur after the
-  onload event, and it doesn't include time loading things off-screen.
-
-  This speed index metric is based on WebPageTest.org (WPT).
-  For more info see: http://goo.gl/e7AH5l
-  """
-
-  def __init__(self):
-    super(SpeedIndexMetric, self).__init__()
-    self._impl = None
-
-  @classmethod
-  def CustomizeBrowserOptions(cls, options):
-    options.AppendExtraBrowserArgs('--disable-infobars')
-
-  def Start(self, _, tab):
-    """Start recording events.
-
-    This method should be called in the WillNavigateToPage method of
-    a PageTest, so that all the events can be captured. If it's called
-    in DidNavigateToPage, that will be too late.
-    """
-    if not tab.video_capture_supported:
-      return
-    self._impl = VideoSpeedIndexImpl()
-    self._impl.Start(tab)
-
-  def Stop(self, _, tab):
-    """Stop recording."""
-    if not tab.video_capture_supported:
-      return
-    assert self._impl, 'Must call Start() before Stop()'
-    assert self.IsFinished(tab), 'Must wait for IsFinished() before Stop()'
-    self._impl.Stop(tab)
-
-  # Optional argument chart_name is not in base class Metric.
-  # pylint: disable=arguments-differ
-  def AddResults(self, tab, results, chart_name=None):
-    """Calculate the speed index and add it to the results."""
-    try:
-      if tab.video_capture_supported:
-        index = self._impl.CalculateSpeedIndex(tab)
-        none_value_reason = None
-      else:
-        index = None
-        none_value_reason = 'Video capture is not supported.'
-    finally:
-      self._impl = None  # Release the tab so that it can be disconnected.
-
-    results.AddValue(scalar.ScalarValue(
-        results.current_page, '%s_speed_index' % chart_name, 'ms', index,
-        description='Speed Index. This focuses on time when visible parts of '
-                    'page are displayed and shows the time when the '
-                    'first look is "almost" composed. If the contents of the '
-                    'testing page are composed by only static resources, load '
-                    'time can measure more accurately and speed index will be '
-                    'smaller than the load time. On the other hand, If the '
-                    'contents are composed by many XHR requests with small '
-                    'main resource and javascript, speed index will be able to '
-                    'get the features of performance more accurately than load '
-                    'time because the load time will measure the time when '
-                    'static resources are loaded. If you want to get more '
-                    'detail, please refer to http://goo.gl/Rw3d5d. Currently '
-                    'there are two implementations: for Android and for '
-                    'Desktop. The Android version uses video capture; the '
-                    'Desktop one uses paint events and has extra overhead to '
-                    'catch paint events.', none_value_reason=none_value_reason))
-
-  def IsFinished(self, tab):
-    """Decide whether the recording should be stopped.
-
-    A page may repeatedly request resources in an infinite loop; a timeout
-    should be placed in any measurement that uses this metric, e.g.:
-      def IsDone():
-        return self._speedindex.IsFinished(tab)
-      util.WaitFor(IsDone, 60)
-
-    Returns:
-      True if 2 seconds have passed since last resource received, false
-      otherwise.
-    """
-    return tab.HasReachedQuiescence()
-
-
-class SpeedIndexImpl(object):
-
-  def Start(self, tab):
-    raise NotImplementedError()
-
-  def Stop(self, tab):
-    raise NotImplementedError()
-
-  def GetTimeCompletenessList(self, tab):
-    """Returns a list of time to visual completeness tuples.
-
-    In the WPT PHP implementation, this is also called 'visual progress'.
-    """
-    raise NotImplementedError()
-
-  def CalculateSpeedIndex(self, tab):
-    """Calculate the speed index.
-
-    The speed index number conceptually represents the number of milliseconds
-    that the page was "visually incomplete". If the page were 0% complete for
-    1000 ms, then the score would be 1000; if it were 0% complete for 100 ms
-    then 90% complete (ie 10% incomplete) for 900 ms, then the score would be
-    1.0*100 + 0.1*900 = 190.
-
-    Returns:
-      A single number, milliseconds of visual incompleteness.
-    """
-    time_completeness_list = self.GetTimeCompletenessList(tab)
-    prev_completeness = 0.0
-    speed_index = 0.0
-    prev_time = time_completeness_list[0][0]
-    for time, completeness in time_completeness_list:
-      # Add the incremental value for the interval just before this event.
-      elapsed_time = time - prev_time
-      incompleteness = (1.0 - prev_completeness)
-      speed_index += elapsed_time * incompleteness
-
-      # Update variables for next iteration.
-      prev_completeness = completeness
-      prev_time = time
-    return int(speed_index)
-
-
-class VideoSpeedIndexImpl(SpeedIndexImpl):
-
-  def __init__(self, image_util_module=image_util):
-    # Allow image_util to be passed in so we can fake it out for testing.
-    super(VideoSpeedIndexImpl, self).__init__()
-    self._time_completeness_list = None
-    self._image_util_module = image_util_module
-
-  def Start(self, tab):
-    assert tab.video_capture_supported
-    # Blank out the current page so it doesn't count towards the new page's
-    # completeness.
-    tab.Highlight(rgba_color.WHITE)
-    # TODO(tonyg): Bitrate is arbitrary here. Experiment with screen capture
-    # overhead vs. speed index accuracy and set the bitrate appropriately.
-    tab.StartVideoCapture(min_bitrate_mbps=4)
-
-  def Stop(self, tab):
-    # Ignore white because Chrome may blank out the page during load and we want
-    # that to count as 0% complete. Relying on this fact, we also blank out the
-    # previous page to white. The tolerance of 8 experimentally does well with
-    # video capture at 4mbps. We should keep this as low as possible with
-    # supported video compression settings.
-    video_capture = tab.StopVideoCapture()
-    histograms = [
-        (time, self._image_util_module.GetColorHistogram(
-            image, ignore_color=rgba_color.WHITE, tolerance=8))
-        for time, image in video_capture.GetVideoFrameIter()
-    ]
-
-    start_histogram = histograms[0][1]
-    final_histogram = histograms[-1][1]
-    total_distance = start_histogram.Distance(final_histogram)
-
-    def FrameProgress(histogram):
-      if total_distance == 0:
-        if histogram.Distance(final_histogram) == 0:
-          return 1.0
-        else:
-          return 0.0
-      return 1 - histogram.Distance(final_histogram) / total_distance
-
-    self._time_completeness_list = [(time, FrameProgress(hist))
-                                    for time, hist in histograms]
-
-  def GetTimeCompletenessList(self, tab):
-    assert self._time_completeness_list, 'Must call Stop() first.'
-    return self._time_completeness_list
diff --git a/tools/perf/metrics/speedindex_unittest.py b/tools/perf/metrics/speedindex_unittest.py
deleted file mode 100644
index 2bcc5a0..0000000
--- a/tools/perf/metrics/speedindex_unittest.py
+++ /dev/null
@@ -1,125 +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.
-
-# These tests access private methods in the speedindex module.
-# pylint: disable=protected-access
-
-import unittest
-
-from telemetry.util import color_histogram
-from telemetry.util import rgba_color
-
-from metrics import speedindex
-
-
-class FakeImageUtil(object):
-
-  # pylint: disable=unused-argument
-  def GetColorHistogram(self, image, ignore_color=None, tolerance=None):
-    return image.ColorHistogram()
-
-
-class FakeVideo(object):
-
-  def __init__(self, frames):
-    self._frames = frames
-
-  def GetVideoFrameIter(self):
-    for frame in self._frames:
-      yield frame
-
-
-class FakeBitmap(object):
-
-  def __init__(self, r, g, b):
-    self._histogram = color_histogram.ColorHistogram(r, g, b, rgba_color.WHITE)
-
-  # pylint: disable=unused-argument
-  def ColorHistogram(self, ignore_color=None, tolerance=None):
-    return self._histogram
-
-
-class FakeTab(object):
-
-  def __init__(self, video_capture_result=None):
-    self._javascript_result = None
-    self._video_capture_result = FakeVideo(video_capture_result)
-
-  @property
-  def video_capture_supported(self):
-    return self._video_capture_result is not None
-
-  def SetEvaluateJavaScriptResult(self, result):
-    self._javascript_result = result
-
-  def EvaluateJavaScript(self, _):
-    return self._javascript_result
-
-  def StartVideoCapture(self, min_bitrate_mbps=1):
-    assert self.video_capture_supported
-    assert min_bitrate_mbps > 0
-
-  def StopVideoCapture(self):
-    assert self.video_capture_supported
-    return self._video_capture_result
-
-  def Highlight(self, _):
-    pass
-
-
-class SpeedIndexImplTest(unittest.TestCase):
-
-  def testVideoCompleteness(self):
-    frames = [
-        (0.0, FakeBitmap([0, 0, 0, 10], [0, 0, 0, 10], [0, 0, 0, 10])),
-        (0.1, FakeBitmap([10, 0, 0, 0], [10, 0, 0, 0], [10, 0, 0, 0])),
-        (0.2, FakeBitmap([0, 0, 2, 8], [0, 0, 4, 6], [0, 0, 1, 9])),
-        (0.3, FakeBitmap([0, 3, 2, 5], [2, 1, 0, 7], [0, 3, 0, 7])),
-        (0.4, FakeBitmap([0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0])),
-        (0.5, FakeBitmap([0, 4, 6, 0], [0, 4, 6, 0], [0, 4, 6, 0])),
-    ]
-    max_distance = 42.
-
-    tab = FakeTab(frames)
-    impl = speedindex.VideoSpeedIndexImpl(FakeImageUtil())
-    impl.Start(tab)
-    impl.Stop(tab)
-    time_completeness = impl.GetTimeCompletenessList(tab)
-    self.assertEqual(len(time_completeness), 6)
-    self.assertEqual(time_completeness[0], (0.0, 0))
-    self.assertTimeCompleteness(
-        time_completeness[1], 0.1, 1 - (16 + 16 + 16) / max_distance)
-    self.assertTimeCompleteness(
-        time_completeness[2], 0.2, 1 - (12 + 10 + 13) / max_distance)
-    self.assertTimeCompleteness(
-        time_completeness[3], 0.3, 1 - (6 + 10 + 8) / max_distance)
-    self.assertTimeCompleteness(
-        time_completeness[4], 0.4, 1 - (4 + 4 + 4) / max_distance)
-    self.assertEqual(time_completeness[5], (0.5, 1))
-
-  def testBlankPage(self):
-    frames = [
-        (0.0, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])),
-        (0.1, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])),
-        (0.2, FakeBitmap([1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1])),
-        (0.3, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])),
-    ]
-    tab = FakeTab(frames)
-    impl = speedindex.VideoSpeedIndexImpl(FakeImageUtil())
-    impl.Start(tab)
-    impl.Stop(tab)
-    time_completeness = impl.GetTimeCompletenessList(tab)
-    self.assertEqual(len(time_completeness), 4)
-    self.assertEqual(time_completeness[0], (0.0, 1.0))
-    self.assertEqual(time_completeness[1], (0.1, 1.0))
-    self.assertEqual(time_completeness[2], (0.2, 0.0))
-    self.assertEqual(time_completeness[3], (0.3, 1.0))
-
-  def assertTimeCompleteness(self, time_completeness, time, completeness):
-    self.assertEqual(time_completeness[0], time)
-    self.assertAlmostEqual(time_completeness[1], completeness)
-
-
-if __name__ == "__main__":
-  unittest.main()
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 7855804..f0a7e7d 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -67,28 +67,31 @@
                            int* width,
                            int* height,
                            int line_height,
-                           int flags) {
+                           int flags,
+                           Typesetter typesetter) {
   float fractional_width = static_cast<float>(*width);
   float factional_height = static_cast<float>(*height);
-  SizeStringFloat(text, font_list, &fractional_width,
-                  &factional_height, line_height, flags);
+  SizeStringFloat(text, font_list, &fractional_width, &factional_height,
+                  line_height, flags, typesetter);
   *width = ToCeiledInt(fractional_width);
   *height = ToCeiledInt(factional_height);
 }
 
 // static
 int Canvas::GetStringWidth(const base::string16& text,
-                           const FontList& font_list) {
+                           const FontList& font_list,
+                           Typesetter typesetter) {
   int width = 0, height = 0;
-  SizeStringInt(text, font_list, &width, &height, 0, NO_ELLIPSIS);
+  SizeStringInt(text, font_list, &width, &height, 0, NO_ELLIPSIS, typesetter);
   return width;
 }
 
 // static
 float Canvas::GetStringWidthF(const base::string16& text,
-                              const FontList& font_list) {
+                              const FontList& font_list,
+                              Typesetter typesetter) {
   float width = 0, height = 0;
-  SizeStringFloat(text, font_list, &width, &height, 0, NO_ELLIPSIS);
+  SizeStringFloat(text, font_list, &width, &height, 0, NO_ELLIPSIS, typesetter);
   return width;
 }
 
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index 15248b323..a34b6cba 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -114,7 +114,8 @@
                             int* width,
                             int* height,
                             int line_height,
-                            int flags);
+                            int flags,
+                            Typesetter typesetter = Typesetter::DEFAULT);
 
   // This is same as SizeStringInt except that fractional size is returned.
   // See comment in GetStringWidthF for its usage.
@@ -123,12 +124,14 @@
                               float* width,
                               float* height,
                               int line_height,
-                              int flags);
+                              int flags,
+                              Typesetter typesetter = Typesetter::DEFAULT);
 
   // Returns the number of horizontal pixels needed to display the specified
   // |text| with |font_list|.
   static int GetStringWidth(const base::string16& text,
-                            const FontList& font_list);
+                            const FontList& font_list,
+                            Typesetter typesetter = Typesetter::DEFAULT);
 
   // This is same as GetStringWidth except that fractional width is returned.
   // Use this method for the scenario that multiple string widths need to be
@@ -136,7 +139,8 @@
   // adding multiple ceiled widths could cause more precision loss for certain
   // platform like Mac where the fractioal width is used.
   static float GetStringWidthF(const base::string16& text,
-                               const FontList& font_list);
+                               const FontList& font_list,
+                               Typesetter typesetter = Typesetter::DEFAULT);
 
   // Returns the default text alignment to be used when drawing text on a
   // Canvas based on the directionality of the system locale language.
diff --git a/ui/gfx/canvas_notimplemented.cc b/ui/gfx/canvas_notimplemented.cc
index 868ef6f..fdbea73 100644
--- a/ui/gfx/canvas_notimplemented.cc
+++ b/ui/gfx/canvas_notimplemented.cc
@@ -14,7 +14,8 @@
                              float* width,
                              float* height,
                              int line_height,
-                             int flags) {
+                             int flags,
+                             Typesetter Typesetter) {
   NOTIMPLEMENTED();
 }
 
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index 8f24702b..eef23dce 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -97,9 +97,11 @@
 // static
 void Canvas::SizeStringFloat(const base::string16& text,
                              const FontList& font_list,
-                             float* width, float* height,
+                             float* width,
+                             float* height,
                              int line_height,
-                             int flags) {
+                             int flags,
+                             Typesetter typesetter) {
   DCHECK_GE(*width, 0);
   DCHECK_GE(*height, 0);
 
@@ -115,6 +117,9 @@
                        &strings);
     Rect rect(base::saturated_cast<int>(*width), INT_MAX);
 
+    // Note the following DCHECK can be removed when this codepath no longer
+    // uses CreateInstanceDeprecated(), which always uses PLATFORM.
+    DCHECK_EQ(Typesetter::PLATFORM, typesetter);
     // This needs to match the instance used in ElideRectangleText.
     auto render_text = RenderText::CreateInstanceDeprecated();
 
@@ -135,10 +140,7 @@
     *width = w;
     *height = h;
   } else {
-    // This is mostly used by calls from GetStringWidth(), which doesn't have
-    // the required drawing context. TODO(tapted): Ensure Cocoa UI never calls
-    // this method and change the next line to CreateHarfBuzzInstance().
-    auto render_text = RenderText::CreateInstanceDeprecated();
+    auto render_text = RenderText::CreateFor(typesetter);
 
     Rect rect(base::saturated_cast<int>(*width),
               base::saturated_cast<int>(*height));
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index f53e01e3..2c82aaa 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -196,24 +196,6 @@
     DCHECK_EQ(kIOReturnSuccess, r);
   }
 
-  bool force_color_space = false;
-
-  // Displaying an IOSurface that does not have a color space using an
-  // AVSampleBufferDisplayLayer can result in a black screen. Ensure that
-  // a color space always be specified.
-  // https://crbug.com/608879
-  if (format == gfx::BufferFormat::YUV_420_BIPLANAR)
-    force_color_space = true;
-
-  // On Sierra, all IOSurfaces are color corrected as though they are in sRGB
-  // color space by default. Prior to Sierra, IOSurfaces were not color
-  // corrected (they were treated as though they were in the display color
-  // space). Override this by defaulting IOSurfaces to be in the main display
-  // color space.
-  // https://crbug.com/654488
-  if (base::mac::IsAtLeastOS10_12())
-    force_color_space = true;
-
   // Ensure that all IOSurfaces start as sRGB.
   CGColorSpaceRef color_space = base::mac::GetSRGBColorSpace();
   base::ScopedCFTypeRef<CFDataRef> color_space_icc(
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 1f97906..4cc85ab 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -343,8 +343,14 @@
 }
 
 // static
-std::unique_ptr<RenderText> RenderText::CreateInstanceForPlatformUI() {
+std::unique_ptr<RenderText> RenderText::CreateFor(Typesetter typesetter) {
 #if defined(OS_MACOSX)
+  if (typesetter == Typesetter::TOOLTIPS)
+    return std::make_unique<RenderTextMac>();
+
+  if (typesetter == Typesetter::HARFBUZZ)
+    return CreateHarfBuzzInstance();
+
   static const bool use_native =
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableHarfBuzzRenderText);
@@ -356,7 +362,7 @@
 
 // static
 std::unique_ptr<RenderText> RenderText::CreateInstanceDeprecated() {
-  return CreateInstanceForPlatformUI();
+  return CreateFor(Typesetter::PLATFORM);
 }
 
 std::unique_ptr<RenderText> RenderText::CreateInstanceOfSameStyle(
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h
index f56a11d..62d623f 100644
--- a/ui/gfx/render_text.h
+++ b/ui/gfx/render_text.h
@@ -194,14 +194,14 @@
   // Creates an instance that renders using HarfBuzz.
   static std::unique_ptr<RenderText> CreateHarfBuzzInstance();
 
-  // Creates an instance that renders text using the native platform typesetter.
-  // CoreText on Mac is the only supported native typesetter, so this should
-  // only be used by text that may be rendered using CoreText (AppKit) on Mac.
-  static std::unique_ptr<RenderText> CreateInstanceForPlatformUI();
+  // Creates an instance by matching a gfx::Typesetter constant to the current
+  // build and runtime configuration. E.g. the result may use CoreText on Mac,
+  // which is the only supported native typesetter.
+  static std::unique_ptr<RenderText> CreateFor(Typesetter typesetter);
 
-  // Returns CreateInstanceForPlatformUI(), but indicates a caller that does not
-  // know whether the text will eventually be drawn by the native typesetter or
-  // by a RenderText instance.
+  // Returns CreateFor(Typesetter::PLATFORM), but indicates a caller that does
+  // not know whether the text will eventually be drawn by the native typesetter
+  // or by a RenderText instance.
   // TODO(tapted): Delete this.
   static std::unique_ptr<RenderText> CreateInstanceDeprecated();
 
diff --git a/ui/gfx/text_constants.h b/ui/gfx/text_constants.h
index 7d1a51f..33ae4585 100644
--- a/ui/gfx/text_constants.h
+++ b/ui/gfx/text_constants.h
@@ -114,6 +114,22 @@
   FADE_TAIL,    // Fade the string's end opposite of its horizontal alignment.
 };
 
+// The typesetter that will be used for text when displayed in UI. This can
+// influence things like string width in subtle ways and is necessary to help
+// transition Mac to the Harfbuzz typesetter (http://crbug.com/454835).
+enum class Typesetter {
+  PLATFORM,  // The platform typesetter is the one used by UI parts of the
+             // browser window on this platform.
+  HARFBUZZ,  // The Harfbuzz typesetter is typically used for secondary UI.
+  TOOLTIPS,  // The typesetter used for tooltips. Typically always native.
+
+  // The typesetter used for function default arguments. The default can be used
+  // from locations that are unaffected by the Mac Harfbuzz transition. Once all
+  // callers rendering to Cocoa UI have been updated to PLATFORM, this will
+  // switch to HARFBUZZ.
+  DEFAULT = PLATFORM
+};
+
 }  // namespace gfx
 
 #endif  // UI_GFX_TEXT_CONSTANTS_H_
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc
index a8a64de..1a7d3a27 100644
--- a/ui/gfx/text_elider.cc
+++ b/ui/gfx/text_elider.cc
@@ -146,7 +146,8 @@
 
 base::string16 ElideFilename(const base::FilePath& filename,
                              const FontList& font_list,
-                             float available_pixel_width) {
+                             float available_pixel_width,
+                             Typesetter typesetter) {
 #if defined(OS_WIN)
   base::string16 filename_utf16 = filename.value();
   base::string16 extension = filename.Extension();
@@ -166,12 +167,13 @@
 
   if (rootname.empty() || extension.empty()) {
     const base::string16 elided_name =
-        ElideText(filename_utf16, font_list, available_pixel_width, ELIDE_TAIL);
+        ElideText(filename_utf16, font_list, available_pixel_width, ELIDE_TAIL,
+                  typesetter);
     return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
   }
 
-  const float ext_width = GetStringWidthF(extension, font_list);
-  const float root_width = GetStringWidthF(rootname, font_list);
+  const float ext_width = GetStringWidthF(extension, font_list, typesetter);
+  const float root_width = GetStringWidthF(rootname, font_list, typesetter);
 
   // We may have trimmed the path.
   if (root_width + ext_width <= available_pixel_width) {
@@ -180,14 +182,15 @@
   }
 
   if (ext_width >= available_pixel_width) {
-    const base::string16 elided_name = ElideText(
-        rootname + extension, font_list, available_pixel_width, ELIDE_MIDDLE);
+    const base::string16 elided_name =
+        ElideText(rootname + extension, font_list, available_pixel_width,
+                  ELIDE_MIDDLE, typesetter);
     return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
   }
 
   float available_root_width = available_pixel_width - ext_width;
-  base::string16 elided_name =
-      ElideText(rootname, font_list, available_root_width, ELIDE_TAIL);
+  base::string16 elided_name = ElideText(
+      rootname, font_list, available_root_width, ELIDE_TAIL, typesetter);
   elided_name += extension;
   return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
 }
@@ -195,12 +198,11 @@
 base::string16 ElideText(const base::string16& text,
                          const FontList& font_list,
                          float available_pixel_width,
-                         ElideBehavior behavior) {
+                         ElideBehavior behavior,
+                         Typesetter typesetter) {
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   DCHECK_NE(behavior, FADE_TAIL);
-  // TODO(tapted): Update callers of this that draw into Cocoa UI to use
-  // RenderText directly. See http://crbug.com/791391.
-  auto render_text = RenderText::CreateInstanceDeprecated();
+  auto render_text = RenderText::CreateFor(typesetter);
 
   render_text->SetCursorEnabled(false);
   // TODO(bshe): 5000 is out dated. We should remove it. See crbug.com/551660.
diff --git a/ui/gfx/text_elider.h b/ui/gfx/text_elider.h
index aaca1dd..245c111 100644
--- a/ui/gfx/text_elider.h
+++ b/ui/gfx/text_elider.h
@@ -67,10 +67,12 @@
 };
 
 // Elides |text| to fit the |available_pixel_width| with the specified behavior.
-GFX_EXPORT base::string16 ElideText(const base::string16& text,
-                                    const gfx::FontList& font_list,
-                                    float available_pixel_width,
-                                    ElideBehavior elide_behavior);
+GFX_EXPORT base::string16 ElideText(
+    const base::string16& text,
+    const gfx::FontList& font_list,
+    float available_pixel_width,
+    ElideBehavior elide_behavior,
+    Typesetter typesetter = Typesetter::DEFAULT);
 
 // Elide a filename to fit a given pixel width, with an emphasis on not hiding
 // the extension unless we have to. If filename contains a path, the path will
@@ -78,9 +80,11 @@
 // filename is forced to have LTR directionality, which means that in RTL UI
 // the elided filename is wrapped with LRE (Left-To-Right Embedding) mark and
 // PDF (Pop Directional Formatting) mark.
-GFX_EXPORT base::string16 ElideFilename(const base::FilePath& filename,
-                                        const gfx::FontList& font_list,
-                                        float available_pixel_width);
+GFX_EXPORT base::string16 ElideFilename(
+    const base::FilePath& filename,
+    const gfx::FontList& font_list,
+    float available_pixel_width,
+    Typesetter typesetter = Typesetter::DEFAULT);
 
 // Functions to elide strings when the font information is unknown. As opposed
 // to the above functions, ElideString() and ElideRectangleString() operate in
diff --git a/ui/gfx/text_elider_unittest.cc b/ui/gfx/text_elider_unittest.cc
index 4620d06e..50fbe8e 100644
--- a/ui/gfx/text_elider_unittest.cc
+++ b/ui/gfx/text_elider_unittest.cc
@@ -207,8 +207,11 @@
     base::FilePath filepath(testcases[i].input);
     base::string16 expected = UTF8ToUTF16(testcases[i].output);
     expected = base::i18n::GetDisplayStringInLTRDirectionality(expected);
-    EXPECT_EQ(expected, ElideFilename(filepath, font_list,
-        GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list)));
+    EXPECT_EQ(expected,
+              ElideFilename(
+                  filepath, font_list,
+                  GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list),
+                  Typesetter::DEFAULT));
   }
 }
 
diff --git a/ui/gfx/text_utils.h b/ui/gfx/text_utils.h
index 7f7ef7f..010c7cab 100644
--- a/ui/gfx/text_utils.h
+++ b/ui/gfx/text_utils.h
@@ -9,6 +9,7 @@
 
 #include "base/strings/string16.h"
 #include "ui/gfx/gfx_export.h"
+#include "ui/gfx/text_constants.h"
 
 namespace gfx {
 
@@ -25,13 +26,16 @@
                                                 int* accelerated_char_span);
 
 // Returns the number of horizontal pixels needed to display the specified
-// |text| with |font_list|.
+// |text| with |font_list|. |typesetter| indicates where the text will be
+// displayed.
 GFX_EXPORT int GetStringWidth(const base::string16& text,
-                              const FontList& font_list);
+                              const FontList& font_list,
+                              Typesetter Typesetter = Typesetter::DEFAULT);
 
 // This is same as GetStringWidth except that fractional width is returned.
 GFX_EXPORT float GetStringWidthF(const base::string16& text,
-                                 const FontList& font_list);
+                                 const FontList& font_list,
+                                 Typesetter Typesetter = Typesetter::DEFAULT);
 
 // Returns a valid cut boundary at or before |index|. The surrogate pair and
 // combining characters should not be separated.
diff --git a/ui/gfx/text_utils_android.cc b/ui/gfx/text_utils_android.cc
index 93938d57..bd799d6 100644
--- a/ui/gfx/text_utils_android.cc
+++ b/ui/gfx/text_utils_android.cc
@@ -8,12 +8,16 @@
 
 namespace gfx {
 
-int GetStringWidth(const base::string16& text, const FontList& font_list) {
+int GetStringWidth(const base::string16& text,
+                   const FontList& font_list,
+                   Typesetter typesetter) {
   NOTIMPLEMENTED();
   return 0;
 }
 
-float GetStringWidthF(const base::string16& text, const FontList& font_list) {
+float GetStringWidthF(const base::string16& text,
+                      const FontList& font_list,
+                      Typesetter typesetter) {
   NOTIMPLEMENTED();
   return 0;
 }
diff --git a/ui/gfx/text_utils_ios.mm b/ui/gfx/text_utils_ios.mm
index e869ab53..0fdf2ae 100644
--- a/ui/gfx/text_utils_ios.mm
+++ b/ui/gfx/text_utils_ios.mm
@@ -14,11 +14,15 @@
 
 namespace gfx {
 
-int GetStringWidth(const base::string16& text, const FontList& font_list) {
+int GetStringWidth(const base::string16& text,
+                   const FontList& font_list,
+                   Typesetter typesetter) {
   return std::ceil(GetStringWidthF(text, font_list));
 }
 
-float GetStringWidthF(const base::string16& text, const FontList& font_list) {
+float GetStringWidthF(const base::string16& text,
+                      const FontList& font_list,
+                      Typesetter typesetter) {
   NSString* ns_text = base::SysUTF16ToNSString(text);
   NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont();
   return [ns_text cr_sizeWithFont:native_font].width;
diff --git a/ui/gfx/text_utils_skia.cc b/ui/gfx/text_utils_skia.cc
index 4ef0c23..a959fe6 100644
--- a/ui/gfx/text_utils_skia.cc
+++ b/ui/gfx/text_utils_skia.cc
@@ -8,12 +8,16 @@
 
 namespace gfx {
 
-int GetStringWidth(const base::string16& text, const FontList& font_list) {
-  return Canvas::GetStringWidth(text, font_list);
+int GetStringWidth(const base::string16& text,
+                   const FontList& font_list,
+                   Typesetter typesetter) {
+  return Canvas::GetStringWidth(text, font_list, typesetter);
 }
 
-float GetStringWidthF(const base::string16& text, const FontList& font_list) {
-  return Canvas::GetStringWidthF(text, font_list);
+float GetStringWidthF(const base::string16& text,
+                      const FontList& font_list,
+                      Typesetter typesetter) {
+  return Canvas::GetStringWidthF(text, font_list, typesetter);
 }
 
 }  // namespace gfx