diff --git a/DEPS b/DEPS
index bd9ca4b..cd6be6a 100644
--- a/DEPS
+++ b/DEPS
@@ -79,11 +79,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c0034179a1c43e33d3f2d970450c5cf9a68e471c',
+  'skia_revision': '71cba8f311f18e671ed99e6a553e2ca7e3d17466',
   # 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': 'd84f48a3a4a458ef97e819137d6ec6caff97514d',
+  'v8_revision': 'd1d3000cfe2fc2aaf0f81beacc362218cf7a0b0d',
   # 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': '93c0f344d8c568535bd56d591b3d42050c71676a',
+  'pdfium_revision': '133542fbe7c01dd296d6ffd205281702ad914506',
   # 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': 'e1f9b2c0b5761fd51e665b82f50ae96d9ded2cf3',
+  'catapult_revision': 'aaaa5510da3e1a9ce62b7731caab65f0a83e3cf6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -406,7 +406,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'a9bac57ce6c9d390a52ebaad3259f5fdb871210e',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '94d819fa3e7e71f3dd8210d428c213ddb6e2b336',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f3d25bcc2e542a10248d5a272219ed7695fe3252',
 
   'src/third_party/jsoncpp/source':
     Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248
@@ -543,7 +543,7 @@
   },
 
   'src/third_party/openh264/src':
-    Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'a180c9d4d6f1a4830ca9eed9d159d54996bd63cb',
+    Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '5a5c4f14f471b9f434a55c39e942153453f25661',
 
   'src/third_party/openmax_dl':
     Var('webrtc_git') + '/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -644,7 +644,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '24722b3c8487f92e0e7994ddf2f605cc5009a55f', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '85e6f399498aeb2bbaa7ef80337c5cb212623fe8', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 37fc763..cbb37bd 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -590,6 +590,8 @@
     "system/power/power_button_display_controller.h",
     "system/power/power_button_screenshot_controller.cc",
     "system/power/power_button_screenshot_controller.h",
+    "system/power/power_button_util.cc",
+    "system/power/power_button_util.h",
     "system/power/power_event_observer.cc",
     "system/power/power_event_observer.h",
     "system/power/power_status.cc",
diff --git a/ash/accessibility/accessibility_controller.cc b/ash/accessibility/accessibility_controller.cc
index da95299..befbf591 100644
--- a/ash/accessibility/accessibility_controller.cc
+++ b/ash/accessibility/accessibility_controller.cc
@@ -14,6 +14,8 @@
 #include "ash/session/session_observer.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
+#include "ash/system/power/backlights_forced_off_setter.h"
+#include "ash/system/power/scoped_backlights_forced_off.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -45,7 +47,7 @@
 
 AccessibilityController::AccessibilityController(
     service_manager::Connector* connector)
-    : connector_(connector), binding_(this) {
+    : connector_(connector) {
   Shell::Get()->session_controller()->AddObserver(this);
 }
 
@@ -83,7 +85,7 @@
 
 void AccessibilityController::BindRequest(
     mojom::AccessibilityControllerRequest request) {
-  binding_.Bind(std::move(request));
+  bindings_.AddBinding(this, std::move(request));
 }
 
 void AccessibilityController::SetAutoclickEnabled(bool enabled) {
@@ -165,6 +167,15 @@
   client_ = std::move(client);
 }
 
+void AccessibilityController::SetDarkenScreen(bool darken) {
+  if (darken && !scoped_backlights_forced_off_) {
+    scoped_backlights_forced_off_ =
+        Shell::Get()->backlights_forced_off_setter()->ForceBacklightsOff();
+  } else if (!darken && scoped_backlights_forced_off_) {
+    scoped_backlights_forced_off_.reset();
+  }
+}
+
 void AccessibilityController::OnSigninScreenPrefServiceInitialized(
     PrefService* prefs) {
   ObservePrefs(prefs);
diff --git a/ash/accessibility/accessibility_controller.h b/ash/accessibility/accessibility_controller.h
index 58fbbd0..25e82117 100644
--- a/ash/accessibility/accessibility_controller.h
+++ b/ash/accessibility/accessibility_controller.h
@@ -13,7 +13,7 @@
 #include "ash/session/session_observer.h"
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "ui/accessibility/ax_enums.h"
 
 class PrefChangeRegistrar;
@@ -26,6 +26,8 @@
 
 namespace ash {
 
+class ScopedBacklightsForcedOff;
+
 // The controller for accessibility features in ash. Features can be enabled
 // in chrome's webui settings or the system tray menu (see TrayAccessibility).
 // Uses preferences to communicate with chrome to support mash.
@@ -72,6 +74,7 @@
 
   // mojom::AccessibilityController:
   void SetClient(mojom::AccessibilityControllerClientPtr client) override;
+  void SetDarkenScreen(bool darken) override;
 
   // SessionObserver:
   void OnSigninScreenPrefServiceInitialized(PrefService* prefs) override;
@@ -94,7 +97,7 @@
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
 
   // Binding for mojom::AccessibilityController interface.
-  mojo::Binding<mojom::AccessibilityController> binding_;
+  mojo::BindingSet<mojom::AccessibilityController> bindings_;
 
   // Client interface in chrome browser.
   mojom::AccessibilityControllerClientPtr client_;
@@ -105,6 +108,9 @@
   int large_cursor_size_in_dip_ = kDefaultLargeCursorSize;
   bool mono_audio_enabled_ = false;
 
+  // Used to force the backlights off to darken the screen.
+  std::unique_ptr<ScopedBacklightsForcedOff> scoped_backlights_forced_off_;
+
   DISALLOW_COPY_AND_ASSIGN(AccessibilityController);
 };
 
diff --git a/ash/accessibility/accessibility_controller_unittest.cc b/ash/accessibility/accessibility_controller_unittest.cc
index 792bd50..c7729cb 100644
--- a/ash/accessibility/accessibility_controller_unittest.cc
+++ b/ash/accessibility/accessibility_controller_unittest.cc
@@ -7,11 +7,14 @@
 #include "ash/accessibility/test_accessibility_controller_client.h"
 #include "ash/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
+#include "ash/public/cpp/config.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/system/accessibility_observer.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_test_base.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_power_manager_client.h"
 #include "components/prefs/pref_service.h"
 
 namespace ash {
@@ -37,7 +40,28 @@
   DISALLOW_COPY_AND_ASSIGN(TestAccessibilityObserver);
 };
 
-using AccessibilityControllerTest = AshTestBase;
+class AccessibilityControllerTest : public AshTestBase {
+ public:
+  AccessibilityControllerTest() = default;
+  ~AccessibilityControllerTest() override = default;
+
+  void SetUp() override {
+    auto power_manager_client =
+        std::make_unique<chromeos::FakePowerManagerClient>();
+    power_manager_client_ = power_manager_client.get();
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
+        std::move(power_manager_client));
+
+    AshTestBase::SetUp();
+  }
+
+ protected:
+  // Owned by chromeos::DBusThreadManager.
+  chromeos::FakePowerManagerClient* power_manager_client_ = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AccessibilityControllerTest);
+};
 
 TEST_F(AccessibilityControllerTest, PrefsAreRegistered) {
   PrefService* prefs =
@@ -164,6 +188,18 @@
             sound_duration);
 }
 
+TEST_F(AccessibilityControllerTest, SetDarkenScreen) {
+  ASSERT_FALSE(power_manager_client_->backlights_forced_off());
+
+  AccessibilityController* controller =
+      Shell::Get()->accessibility_controller();
+  controller->SetDarkenScreen(true);
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+
+  controller->SetDarkenScreen(false);
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+}
+
 using AccessibilityControllerSigninTest = NoSessionAshTestBase;
 
 TEST_F(AccessibilityControllerSigninTest, SigninScreenPrefs) {
diff --git a/ash/public/interfaces/accessibility_controller.mojom b/ash/public/interfaces/accessibility_controller.mojom
index 36073cad..ca21573 100644
--- a/ash/public/interfaces/accessibility_controller.mojom
+++ b/ash/public/interfaces/accessibility_controller.mojom
@@ -42,6 +42,10 @@
 interface AccessibilityController {
   // Sets the client interface.
   SetClient(AccessibilityControllerClient client);
+
+  // Starts or stops darkening the screen (e.g. to allow chrome a11y extensions
+  // to darken the screen).
+  SetDarkenScreen(bool darken);
 };
 
 // Interface for ash to request accessibility service from its client (e.g.
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 193adbe..b0ffd56 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -96,6 +96,7 @@
     "notification_stylus_battery_warning.icon",
     "notification_supervised.icon",
     "notification_timer.icon",
+    "overview_window_close.icon",
     "palette_action_capture_region.1x.icon",
     "palette_action_capture_region.icon",
     "palette_action_capture_screen.1x.icon",
diff --git a/ash/resources/vector_icons/overview_window_close.icon b/ash/resources/vector_icons/overview_window_close.icon
new file mode 100644
index 0000000..07a9f48
--- /dev/null
+++ b/ash/resources/vector_icons/overview_window_close.icon
@@ -0,0 +1,19 @@
+// 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 19, 6.42f,
+LINE_TO, 17.59f, 5,
+LINE_TO, 12, 10.59f,
+LINE_TO, 6.42f, 5,
+LINE_TO, 5, 6.42f,
+LINE_TO, 10.59f, 12,
+LINE_TO, 5, 17.59f,
+LINE_TO, 6.42f, 19,
+LINE_TO, 12, 13.42f,
+LINE_TO, 17.59f, 19,
+LINE_TO, 19, 17.59f,
+LINE_TO, 13.42f, 12,
+CLOSE,
+END
diff --git a/ash/system/power/convertible_power_button_controller.cc b/ash/system/power/convertible_power_button_controller.cc
index 9cefe9cf..e28007f 100644
--- a/ash/system/power/convertible_power_button_controller.cc
+++ b/ash/system/power/convertible_power_button_controller.cc
@@ -11,6 +11,7 @@
 #include "ash/shell_delegate.h"
 #include "ash/shutdown_reason.h"
 #include "ash/system/power/power_button_display_controller.h"
+#include "ash/system/power/power_button_util.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/logging.h"
@@ -38,19 +39,8 @@
 constexpr base::TimeDelta kShutdownWhenScreenOffTimeout =
     base::TimeDelta::FromMilliseconds(2000);
 
-// Amount of time since last SuspendDone() that power button event needs to be
-// ignored.
-constexpr base::TimeDelta kIgnorePowerButtonAfterResumeDelay =
-    base::TimeDelta::FromSeconds(2);
-
 }  // namespace
 
-constexpr base::TimeDelta
-    ConvertiblePowerButtonController::kScreenStateChangeDelay;
-
-constexpr base::TimeDelta
-    ConvertiblePowerButtonController::kIgnoreRepeatedButtonUpDelay;
-
 ConvertiblePowerButtonController::ConvertiblePowerButtonController(
     PowerButtonDisplayController* display_controller,
     base::TickClock* tick_clock)
@@ -80,7 +70,8 @@
     // backlight has been turned back on before seeing the power button events
     // that woke the system. Avoid forcing off display just after resuming to
     // ensure that we don't turn the display off in response to the events.
-    if (timestamp - last_resume_time_ <= kIgnorePowerButtonAfterResumeDelay)
+    if (timestamp - last_resume_time_ <=
+        power_button_util::kIgnorePowerButtonAfterResumeDelay)
       force_off_on_button_up_ = false;
 
     // The actual display may remain off for a short period after powerd asks
@@ -88,7 +79,7 @@
     // this time, they probably intend to turn the display on. Avoid forcing off
     // in this case.
     if (timestamp - display_controller_->screen_state_last_changed() <=
-        kScreenStateChangeDelay) {
+        power_button_util::kScreenStateChangeDelay) {
       force_off_on_button_up_ = false;
     }
 
@@ -105,7 +96,8 @@
       lock_state_controller_->CancelShutdownAnimation();
 
     // Ignore the event if it comes too soon after the last one.
-    if (timestamp - previous_up_time <= kIgnoreRepeatedButtonUpDelay) {
+    if (timestamp - previous_up_time <=
+        power_button_util::kIgnoreRepeatedButtonUpDelay) {
       shutdown_timer_.Stop();
       return;
     }
@@ -114,7 +106,8 @@
       shutdown_timer_.Stop();
       if (!screen_off_when_power_button_down_ && force_off_on_button_up_) {
         display_controller_->SetBacklightsForcedOff(true);
-        LockScreenIfRequired();
+        power_button_util::LockScreenIfRequired(
+            Shell::Get()->session_controller(), lock_state_controller_);
       }
     }
   }
@@ -156,14 +149,4 @@
   lock_state_controller_->StartShutdownAnimation(ShutdownReason::POWER_BUTTON);
 }
 
-void ConvertiblePowerButtonController::LockScreenIfRequired() {
-  SessionController* session_controller = Shell::Get()->session_controller();
-  if (session_controller->ShouldLockScreenAutomatically() &&
-      session_controller->CanLockScreen() &&
-      !session_controller->IsUserSessionBlocked() &&
-      !lock_state_controller_->LockRequested()) {
-    lock_state_controller_->LockWithoutAnimation();
-  }
-}
-
 }  // namespace ash
diff --git a/ash/system/power/convertible_power_button_controller.h b/ash/system/power/convertible_power_button_controller.h
index ad2efa95..caa09643 100644
--- a/ash/system/power/convertible_power_button_controller.h
+++ b/ash/system/power/convertible_power_button_controller.h
@@ -37,17 +37,6 @@
   // Public for tests.
   static constexpr float kGravity = 9.80665f;
 
-  // Amount of time since last screen state change that power button event needs
-  // to be ignored.
-  static constexpr base::TimeDelta kScreenStateChangeDelay =
-      base::TimeDelta::FromMilliseconds(500);
-
-  // Ignore button-up events occurring within this many milliseconds of the
-  // previous button-up event. This prevents us from falling behind if the power
-  // button is pressed repeatedly.
-  static constexpr base::TimeDelta kIgnoreRepeatedButtonUpDelay =
-      base::TimeDelta::FromMilliseconds(500);
-
   ConvertiblePowerButtonController(
       PowerButtonDisplayController* display_controller,
       base::TickClock* tick_clock);
@@ -76,10 +65,6 @@
   // Called by |shutdown_timer_| to start the pre-shutdown animation.
   void OnShutdownTimeout();
 
-  // Locks the screen if the "require password to wake from sleep" pref is set
-  // and locking is possible.
-  void LockScreenIfRequired();
-
   // True if the screen was off when the power button was pressed.
   bool screen_off_when_power_button_down_ = false;
 
diff --git a/ash/system/power/convertible_power_button_controller_unittest.cc b/ash/system/power/convertible_power_button_controller_unittest.cc
index 0142d00..1b2cb485 100644
--- a/ash/system/power/convertible_power_button_controller_unittest.cc
+++ b/ash/system/power/convertible_power_button_controller_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/shell.h"
 #include "ash/system/power/convertible_power_button_controller_test_api.h"
 #include "ash/system/power/power_button_test_base.h"
+#include "ash/system/power/power_button_util.h"
 #include "ash/test_media_client.h"
 #include "ash/touch/touch_devices_controller.h"
 #include "ash/wm/lock_state_controller_test_api.h"
@@ -71,9 +72,8 @@
   // off is not ignored since we will ignore the repeated power button up if
   // they come too close.
   void AdvanceClockToAvoidIgnoring() {
-    tick_clock_->Advance(
-        ConvertiblePowerButtonController::kIgnoreRepeatedButtonUpDelay +
-        base::TimeDelta::FromMilliseconds(1));
+    tick_clock_->Advance(power_button_util::kIgnoreRepeatedButtonUpDelay +
+                         base::TimeDelta::FromMilliseconds(1));
   }
 
   DISALLOW_COPY_AND_ASSIGN(ConvertiblePowerButtonControllerTest);
@@ -644,9 +644,8 @@
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
 
   // Since display could still be off, ignore forcing off.
-  tick_clock_->Advance(
-      ConvertiblePowerButtonController::kScreenStateChangeDelay -
-      base::TimeDelta::FromMilliseconds(1));
+  tick_clock_->Advance(power_button_util::kScreenStateChangeDelay -
+                       base::TimeDelta::FromMilliseconds(1));
   PressPowerButton();
   ReleasePowerButton();
   EXPECT_FALSE(power_manager_client_->backlights_forced_off());
diff --git a/ash/system/power/power_button_util.cc b/ash/system/power/power_button_util.cc
new file mode 100644
index 0000000..986223f
--- /dev/null
+++ b/ash/system/power/power_button_util.cc
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/power/power_button_util.h"
+
+#include "ash/session/session_controller.h"
+#include "ash/shell.h"
+#include "ash/wm/lock_state_controller.h"
+
+namespace power_button_util {
+
+void LockScreenIfRequired(ash::SessionController* session_controller,
+                          ash::LockStateController* lock_state_controller) {
+  if (session_controller->ShouldLockScreenAutomatically() &&
+      session_controller->CanLockScreen() &&
+      !session_controller->IsUserSessionBlocked() &&
+      !lock_state_controller->LockRequested()) {
+    lock_state_controller->LockWithoutAnimation();
+  }
+}
+
+}  // namespace power_button_util
diff --git a/ash/system/power/power_button_util.h b/ash/system/power/power_button_util.h
new file mode 100644
index 0000000..c8d4c87
--- /dev/null
+++ b/ash/system/power/power_button_util.h
@@ -0,0 +1,40 @@
+// 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 ASH_SYSTEM_POWER_POWER_BUTTON_UTIL_H_
+#define ASH_SYSTEM_POWER_POWER_BUTTON_UTIL_H_
+
+#include "base/time/time.h"
+
+namespace ash {
+class LockStateController;
+class SessionController;
+}  // namespace ash
+
+namespace power_button_util {
+
+// Ignore button-up events occurring within this many milliseconds of the
+// previous button-up event. This prevents us from falling behind if the power
+// button is pressed repeatedly.
+static constexpr base::TimeDelta kIgnoreRepeatedButtonUpDelay =
+    base::TimeDelta::FromMilliseconds(500);
+
+// Amount of time since last screen state change that power button event needs
+// to be ignored.
+static constexpr base::TimeDelta kScreenStateChangeDelay =
+    base::TimeDelta::FromMilliseconds(500);
+
+// Amount of time since last SuspendDone() that power button event needs to be
+// ignored.
+static constexpr base::TimeDelta kIgnorePowerButtonAfterResumeDelay =
+    base::TimeDelta::FromSeconds(2);
+
+// Locks the screen if the "Show lock screen when waking from sleep" pref is set
+// and locking is possible.
+void LockScreenIfRequired(ash::SessionController* session_controller,
+                          ash::LockStateController* lock_state_controller);
+
+}  // namespace power_button_util
+
+#endif  // ASH_SYSTEM_POWER_POWER_BUTTON_UTIL_H_
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index c57c34b..bf6f280 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -43,6 +43,9 @@
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/transform_util.h"
+#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
+#include "ui/views/animation/ink_drop_impl.h"
+#include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/layout/box_layout.h"
@@ -58,65 +61,85 @@
 // In the conceptual overview table, the window margin is the space reserved
 // around the window within the cell. This margin does not overlap so the
 // closest distance between adjacent windows will be twice this amount.
-static const int kWindowMargin = 5;
+constexpr int kWindowMargin = 5;
 
 // Cover the transformed window including the gaps between the windows with a
 // transparent shield to block the input events from reaching the transformed
 // window while in overview.
-static const int kWindowSelectorMargin = kWindowMargin * 2;
+constexpr int kWindowSelectorMargin = kWindowMargin * 2;
 
 // Foreground label color.
-static const SkColor kLabelColor = SK_ColorWHITE;
+constexpr SkColor kLabelColor = SK_ColorWHITE;
 
 // Close button color.
-static const SkColor kCloseButtonColor = SK_ColorWHITE;
+constexpr SkColor kCloseButtonColor = SK_ColorWHITE;
 
 // Label background color once in overview mode.
-static const SkColor kLabelBackgroundColor = SkColorSetARGB(25, 255, 255, 255);
+constexpr SkColor kLabelBackgroundColor = SkColorSetARGB(25, 255, 255, 255);
 
 // Label background color when exiting overview mode.
-static const SkColor kLabelExitColor = SkColorSetARGB(255, 90, 90, 90);
+constexpr SkColor kLabelExitColor = SkColorSetARGB(255, 90, 90, 90);
 
 // Corner radius for the selection tiles.
 static int kLabelBackgroundRadius = 2;
 
 // Horizontal padding for the label, on both sides.
-static const int kHorizontalLabelPadding = 8;
+constexpr int kHorizontalLabelPaddingDp = 12;
 
 // Height of an item header.
-static const int kHeaderHeight = 32;
+constexpr int kHeaderHeightDp = 40;
 
 // Opacity for dimmed items.
-static const float kDimmedItemOpacity = 0.5f;
+constexpr float kDimmedItemOpacity = 0.5f;
 
 // Opacity for fading out during closing a window.
-static const float kClosingItemOpacity = 0.8f;
+constexpr float kClosingItemOpacity = 0.8f;
 
 // Opacity for the item header.
-static const float kHeaderOpacity =
-    (SkColorGetA(kLabelBackgroundColor) / 255.f);
+constexpr float kHeaderOpacity = (SkColorGetA(kLabelBackgroundColor) / 255.f);
 
 // Duration it takes for the header to shift from opaque header color to
 // |kLabelBackgroundColor|.
-static const int kSelectorColorSlideMilliseconds = 240;
+constexpr int kSelectorColorSlideMilliseconds = 240;
 
 // Duration of background opacity transition for the selected label.
-static const int kSelectorFadeInMilliseconds = 350;
+constexpr int kSelectorFadeInMilliseconds = 350;
 
 // Duration of background opacity transition when exiting overview mode.
-static const int kExitFadeInMilliseconds = 30;
+constexpr int kExitFadeInMilliseconds = 30;
 
 // Before closing a window animate both the window and the caption to shrink by
 // this fraction of size.
-static const float kPreCloseScale = 0.02f;
+constexpr float kPreCloseScale = 0.02f;
 
 // Before dragging an overview window, the window will scale up |kPreDragScale|
 // to indicate its selection.
-static const float kDragWindowScale = 0.04f;
+constexpr float kDragWindowScale = 0.04f;
 
 // The size in dp of the window icon shown on the overview window next to the
 // title.
-constexpr gfx::Size kIconSize = gfx::Size(16, 16);
+constexpr gfx::Size kIconSize = gfx::Size(24, 24);
+
+// Values for the old overview ui.
+// TODO(crbug.com/782320): Delete these values when the old ui becomes obsolete.
+constexpr int kOldHeaderHeightDp = 32;
+constexpr int kOldHorizontalLabelPaddingDp = 8;
+
+constexpr int kCloseButtonInkDropInsetDp = 2;
+
+// The colors of the close button ripple.
+constexpr SkColor kCloseButtonInkDropRippleColor =
+    SkColorSetARGBMacro(0x0F, 0xFF, 0xFF, 0xFF);
+constexpr SkColor kCloseButtonInkDropRippleHighlightColor =
+    SkColorSetARGBMacro(0x14, 0xFF, 0xFF, 0xFF);
+
+// The font delta of the overview window title.
+constexpr int kLabelFontDelta = 2;
+
+bool IsNewOverviewUi() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      ash::switches::kAshEnableNewOverviewUi);
+}
 
 // Convenience method to fade in a Window with predefined animation settings.
 // Note: The fade in animation will occur after a delay where the delay is how
@@ -226,15 +249,47 @@
 WindowSelectorItem::OverviewCloseButton::OverviewCloseButton(
     views::ButtonListener* listener)
     : views::ImageButton(listener) {
+  if (IsNewOverviewUi())
+    SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
+
   SetImage(views::Button::STATE_NORMAL,
-           gfx::CreateVectorIcon(kWindowControlCloseIcon, kCloseButtonColor));
+           gfx::CreateVectorIcon(IsNewOverviewUi() ? kOverviewWindowCloseIcon
+                                                   : kWindowControlCloseIcon,
+                                 kCloseButtonColor));
   SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                     views::ImageButton::ALIGN_MIDDLE);
-  SetMinimumImageSize(gfx::Size(kHeaderHeight, kHeaderHeight));
+  const int length = IsNewOverviewUi() ? kHeaderHeightDp : kOldHeaderHeightDp;
+  SetMinimumImageSize(gfx::Size(length, length));
 }
 
 WindowSelectorItem::OverviewCloseButton::~OverviewCloseButton() = default;
 
+std::unique_ptr<views::InkDropRipple>
+WindowSelectorItem::OverviewCloseButton::CreateInkDropRipple() const {
+  return std::make_unique<views::FloodFillInkDropRipple>(
+      size(), gfx::Insets(), GetInkDropCenterBasedOnLastEvent(),
+      kCloseButtonInkDropRippleColor, /*visible_opacity=*/1.f);
+}
+
+std::unique_ptr<views::InkDropHighlight>
+WindowSelectorItem::OverviewCloseButton::CreateInkDropHighlight() const {
+  return std::make_unique<views::InkDropHighlight>(
+      gfx::PointF(GetLocalBounds().CenterPoint()),
+      std::make_unique<views::CircleLayerDelegate>(
+          kCloseButtonInkDropRippleHighlightColor, GetInkDropRadius()));
+}
+
+std::unique_ptr<views::InkDropMask>
+WindowSelectorItem::OverviewCloseButton::CreateInkDropMask() const {
+  return std::make_unique<views::CircleInkDropMask>(
+      size(), GetLocalBounds().CenterPoint(), GetInkDropRadius());
+}
+
+int WindowSelectorItem::OverviewCloseButton::GetInkDropRadius() const {
+  return std::min(size().width(), size().height()) / 2 -
+         kCloseButtonInkDropInsetDp;
+}
+
 // A View having rounded top corners and a specified background color which is
 // only painted within the bounds defined by the rounded corners.
 // This class coordinates the transitions of the overview mode header when
@@ -412,9 +467,18 @@
     if (image_view_)
       background_->AddChildView(image_view_);
     background_->AddChildView(title_label_);
-    background_->AddChildView(close_button_);
     listener_button_->AddChildView(background_);
     AddChildView(listener_button_);
+    if (IsNewOverviewUi()) {
+      // Do not make |close_button_| a child of |background_| because
+      // |close_button_|'s hit radius should extend outside the bounds of
+      // |background_|.
+      close_button_->SetPaintToLayer();
+      close_button_->layer()->SetFillsBoundsOpaquely(false);
+      AddChildView(close_button_);
+    } else {
+      background_->AddChildView(close_button_);
+    }
 
     // Use |cannot_snap_container_| to specify the padding surrounding
     // |cannot_snap_label_| and to give the label rounded corners.
@@ -469,21 +533,27 @@
     background_bounds.set_height(visible_height);
     background_->SetBoundsRect(background_bounds);
 
+    const int label_padding = IsNewOverviewUi() ? kHorizontalLabelPaddingDp
+                                                : kOldHorizontalLabelPaddingDp;
     bounds = background_bounds;
-    bounds.Inset(kHorizontalLabelPadding + (image_view_ ? visible_height : 0),
-                 0, kHorizontalLabelPadding + visible_height, 0);
+    bounds.Inset(
+        label_padding + (image_view_ ? image_view_->size().width() : 0), 0,
+        label_padding + visible_height, 0);
     title_label_->SetBoundsRect(bounds);
 
-    bounds = background_bounds;
-    bounds.set_x(bounds.width() - visible_height);
-    bounds.set_width(visible_height);
-    close_button_->SetBoundsRect(bounds);
-
     if (image_view_) {
       bounds.set_x(0);
-      bounds.ClampToCenteredSize(image_view_->size());
+      bounds.set_width(image_view_->size().width());
       image_view_->SetBoundsRect(bounds);
     }
+
+    bounds = background_bounds;
+    bounds.set_x(bounds.width() - visible_height +
+                 (IsNewOverviewUi() ? 8 + kWindowSelectorMargin : 0));
+    if (IsNewOverviewUi())
+      bounds.set_y(kWindowSelectorMargin);
+    bounds.set_width(visible_height);
+    close_button_->SetBoundsRect(bounds);
   }
 
   const char* GetClassName() const override { return "CaptionContainerView"; }
@@ -750,6 +820,9 @@
   background_view_ = new RoundedContainerView(this, transform_window_.window(),
                                               kLabelBackgroundRadius,
                                               transform_window_.GetTopColor());
+  if (IsNewOverviewUi())
+    background_view_->set_color(SK_ColorTRANSPARENT);
+
   // |background_view_| will get added as a child to CaptionContainerView.
   views::Widget::InitParams params_label;
   params_label.type = views::Widget::InitParams::TYPE_POPUP;
@@ -781,8 +854,7 @@
   // Create an image view for and scale down the windows window icon, if it
   // exists.
   views::ImageView* image_view = nullptr;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          ash::switches::kAshEnableNewOverviewUi)) {
+  if (IsNewOverviewUi()) {
     gfx::ImageSkia* icon =
         transform_window_.window()->GetProperty(aura::client::kWindowIconKey);
     if (icon && !icon->size().IsEmpty()) {
@@ -801,6 +873,10 @@
   // background color is opaque or transparent to decide whether to use
   // subpixel rendering. Does not actually set the label's background color.
   label_view_->SetBackgroundColor(kLabelBackgroundColor);
+  if (IsNewOverviewUi()) {
+    label_view_->SetFontList(gfx::FontList().Derive(
+        kLabelFontDelta, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
+  }
 
   cannot_snap_label_view_ = new views::Label(title);
   cannot_snap_label_view_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
@@ -845,13 +921,15 @@
         // Animate the color of |background_view_| once the fade in animation of
         // |item_widget_| ends.
         layer_animation_settings.AddObserver(background_view_);
-        background_view_->set_color(kLabelBackgroundColor);
+        if (!IsNewOverviewUi())
+          background_view_->set_color(kLabelBackgroundColor);
       } else if (mode == HeaderFadeInMode::EXIT) {
         // Make the header visible above the window. It will be faded out when
         // the Shutdown() is called.
         background_view_->AnimateColor(gfx::Tween::EASE_OUT,
                                        kExitFadeInMilliseconds);
-        background_view_->set_color(kLabelExitColor);
+        if (!IsNewOverviewUi())
+          background_view_->set_color(kLabelExitColor);
       }
     }
     if (!label_view_->visible()) {
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 6e8e0c4d..5ec244f 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -44,7 +44,16 @@
     // Resets the listener so that the listener can go out of scope.
     void ResetListener() { listener_ = nullptr; }
 
+   protected:
+    // views::ImageButton:
+    std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+    std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
+        const override;
+    std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
+
    private:
+    int GetInkDropRadius() const;
+
     DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton);
   };
 
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 3c77482..998bab6 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -33,7 +33,11 @@
   return std::unique_ptr<T[]>(ptr);
 }
 
+#if defined(_MIPS_ARCH_LOONGSON)
+const size_t kTestMaxAllocation = 16384;
+#else
 const size_t kTestMaxAllocation = 4096;
+#endif
 
 bool IsLargeMemoryDevice() {
   // Treat any device with 2GiB or more of physical memory as a "large memory
@@ -1636,8 +1640,14 @@
   }
 
   // This test checks large-but-not-quite-direct allocations.
+  // kSystemPageSize is 16384 on Loongson Platform, not 4096.
   {
-    void* ptr = generic_allocator.root()->Alloc(65536 + 1, type_name);
+#if defined(_MIPS_ARCH_LOONGSON)
+    size_t requestedSize = 262144;
+#else
+    size_t requestedSize = 65536;
+#endif
+    void* ptr = generic_allocator.root()->Alloc(requestedSize + 1, type_name);
 
     {
       MockPartitionStatsDumper dumper;
@@ -1645,14 +1655,15 @@
                                           false /* detailed dump */, &dumper);
       EXPECT_TRUE(dumper.IsMemoryAllocationRecorded());
 
-      size_t slot_size = 65536 + (65536 / kGenericNumBucketsPerOrder);
+      size_t slot_size =
+          requestedSize + (requestedSize / kGenericNumBucketsPerOrder);
       const PartitionBucketMemoryStats* stats =
           dumper.GetBucketStats(slot_size);
       EXPECT_TRUE(stats);
       EXPECT_TRUE(stats->is_valid);
       EXPECT_FALSE(stats->is_direct_map);
       EXPECT_EQ(slot_size, stats->bucket_slot_size);
-      EXPECT_EQ(65536u + 1 + kExtraAllocSize, stats->active_bytes);
+      EXPECT_EQ(requestedSize + 1 + kExtraAllocSize, stats->active_bytes);
       EXPECT_EQ(slot_size, stats->resident_bytes);
       EXPECT_EQ(0u, stats->decommittable_bytes);
       EXPECT_EQ(kSystemPageSize, stats->discardable_bytes);
@@ -1670,7 +1681,8 @@
                                           false /* detailed dump */, &dumper);
       EXPECT_FALSE(dumper.IsMemoryAllocationRecorded());
 
-      size_t slot_size = 65536 + (65536 / kGenericNumBucketsPerOrder);
+      size_t slot_size =
+          requestedSize + (requestedSize / kGenericNumBucketsPerOrder);
       const PartitionBucketMemoryStats* stats =
           dumper.GetBucketStats(slot_size);
       EXPECT_TRUE(stats);
@@ -1687,7 +1699,8 @@
     }
 
     void* ptr2 =
-        generic_allocator.root()->Alloc(65536 + kSystemPageSize + 1, type_name);
+        generic_allocator.root()->Alloc(requestedSize + kSystemPageSize + 1,
+                                        type_name);
     EXPECT_EQ(ptr, ptr2);
 
     {
@@ -1696,14 +1709,15 @@
                                           false /* detailed dump */, &dumper);
       EXPECT_TRUE(dumper.IsMemoryAllocationRecorded());
 
-      size_t slot_size = 65536 + (65536 / kGenericNumBucketsPerOrder);
+      size_t slot_size =
+          requestedSize + (requestedSize / kGenericNumBucketsPerOrder);
       const PartitionBucketMemoryStats* stats =
           dumper.GetBucketStats(slot_size);
       EXPECT_TRUE(stats);
       EXPECT_TRUE(stats->is_valid);
       EXPECT_FALSE(stats->is_direct_map);
       EXPECT_EQ(slot_size, stats->bucket_slot_size);
-      EXPECT_EQ(65536u + kSystemPageSize + 1 + kExtraAllocSize,
+      EXPECT_EQ(requestedSize + kSystemPageSize + 1 + kExtraAllocSize,
                 stats->active_bytes);
       EXPECT_EQ(slot_size, stats->resident_bytes);
       EXPECT_EQ(0u, stats->decommittable_bytes);
diff --git a/base/process/launch.h b/base/process/launch.h
index 681de35..a6ed7fb 100644
--- a/base/process/launch.h
+++ b/base/process/launch.h
@@ -165,16 +165,6 @@
   // propagate FDs into the child process.
   FileHandleMappingVector fds_to_remap;
 
-  // Each element is an RLIMIT_* constant that should be raised to its
-  // rlim_max.  This pointer is owned by the caller and must live through
-  // the call to LaunchProcess().
-  const std::vector<int>* maximize_rlimits = nullptr;
-
-  // If true, start the process in a new process group, instead of
-  // inheriting the parent's process group.  The pgid of the child process
-  // will be the same as its pid.
-  bool new_process_group = false;
-
 #if defined(OS_LINUX)
   // If non-zero, start the process using clone(), using flags as provided.
   // Unlike in clone, clone_flags may not contain a custom termination signal
@@ -223,6 +213,16 @@
   // code running in this delegate essentially needs to be async-signal safe
   // (see man 7 signal for a list of allowed functions).
   PreExecDelegate* pre_exec_delegate = nullptr;
+
+  // Each element is an RLIMIT_* constant that should be raised to its
+  // rlim_max.  This pointer is owned by the caller and must live through
+  // the call to LaunchProcess().
+  const std::vector<int>* maximize_rlimits = nullptr;
+
+  // If true, start the process in a new process group, instead of
+  // inheriting the parent's process group.  The pgid of the child process
+  // will be the same as its pid.
+  bool new_process_group = false;
 #endif  // defined(OS_POSIX)
 
 #if defined(OS_CHROMEOS)
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index ed29463..c05d214c 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -69,6 +69,7 @@
 // TODO(scottmg): For temporary code in OnOutputTimeout().
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/object.h>
+#include "base/fuchsia/default_job.h"
 #endif
 
 namespace base {
@@ -261,7 +262,7 @@
   const bool kOnBot = getenv("CHROME_HEADLESS") != nullptr;
 #endif  // OS_FUCHSIA
 
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) && !defined(OS_FUCHSIA)
   // Make sure an option we rely on is present - see LaunchChildGTestProcess.
   DCHECK(options.new_process_group);
 #endif
@@ -295,7 +296,14 @@
 
     new_options.job_handle = job_handle.Get();
   }
-#endif  // defined(OS_WIN)
+#elif defined(OS_FUCHSIA)
+  DCHECK(!new_options.job_handle);
+
+  ScopedZxHandle job_handle;
+  zx_status_t result = zx_job_create(GetDefaultJob(), 0, job_handle.receive());
+  CHECK_EQ(ZX_OK, result) << "zx_job_create: " << zx_status_get_string(result);
+  new_options.job_handle = job_handle.get();
+#endif  // defined(OS_FUCHSIA)
 
 #if defined(OS_LINUX)
   // To prevent accidental privilege sharing to an untrusted child, processes
@@ -335,13 +343,14 @@
     if (!process.IsValid())
       return -1;
 
-    // TODO(rvargas) crbug.com/417532: Don't store process handles.
 #if defined(OS_FUCHSIA)  // TODO(scottmg): https://crbug.com/755282
     if (kOnBot) {
       LOG(ERROR) << base::StringPrintf("adding %x to live process list",
                                        process.Handle());
     }
 #endif  // OS_FUCHSIA
+
+    // TODO(rvargas) crbug.com/417532: Don't store process handles.
     GetLiveProcesses()->insert(std::make_pair(process.Handle(), command_line));
   }
 
@@ -372,18 +381,20 @@
     // to do that twice and trigger all kinds of log messages.
     AutoLock lock(*GetLiveProcessesLock());
 
-#if defined(OS_POSIX)
+#if defined(OS_FUCHSIA)
+    // TODO(scottmg): https://crbug.com/755282
+    if (kOnBot) {
+      LOG(ERROR) << base::StringPrintf("going to zx_task_kill(job) for %x",
+                                       process.Handle());
+    }
+
+    CHECK_EQ(zx_task_kill(job_handle.get()), ZX_OK);
+#elif defined(OS_POSIX)
     if (exit_code != 0) {
       // On POSIX, in case the test does not exit cleanly, either due to a crash
       // or due to it timing out, we need to clean up any child processes that
       // it might have created. On Windows, child processes are automatically
       // cleaned up using JobObjects.
-#if defined(OS_FUCHSIA)  // TODO(scottmg): https://crbug.com/755282
-      if (kOnBot) {
-        LOG(ERROR) << base::StringPrintf("going to KillProcessGroup() for %x",
-                                         process.Handle());
-      }
-#endif  // OS_FUCHSIA
       KillProcessGroup(process.Handle());
     }
 #endif
@@ -439,7 +450,6 @@
     }
   }
 #elif defined(OS_POSIX)
-  options.new_process_group = true;
   options.fds_to_remap = test_launch_options.fds_to_remap;
   if (redirect_stdio) {
     int output_file_fd = fileno(output_file.get());
@@ -450,6 +460,9 @@
         std::make_pair(output_file_fd, STDERR_FILENO));
   }
 
+#if !defined(OS_FUCHSIA)
+  options.new_process_group = true;
+#endif
 #if defined(OS_LINUX)
   options.kill_on_parent_death = true;
 #endif
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 8760aa8..51687c1d 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -70,6 +70,9 @@
 namespace media {
 class BlockingUrlProtocol;
 }
+namespace midi {
+class TaskService;  // https://crbug.com/796830
+}
 namespace mojo {
 class SyncCallRestrictions;
 namespace edk {
@@ -264,6 +267,7 @@
   friend class base::GetAppOutputScopedAllowBaseSyncPrimitives;
   friend class leveldb::LevelDBMojoProxy;
   friend class media::BlockingUrlProtocol;
+  friend class midi::TaskService;  // https://crbug.com/796830
   friend class net::MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
   friend class rlz_lib::FinancialPing;
   friend class shell_integration::LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
diff --git a/chrome/VERSION b/chrome/VERSION
index 5442d48..9838309 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=65
 MINOR=0
-BUILD=3316
+BUILD=3317
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index 78102b61..cf52ade 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -20,7 +20,6 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
-import org.chromium.chrome.browser.signin.AccountSigninActivity;
 import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.PersonalizedSigninPromoView;
 import org.chromium.chrome.browser.signin.ProfileDataCache;
@@ -92,8 +91,8 @@
     }
 
     /**
-     * Suppress signin promos in New Tab Page for {@link SUPPRESSION_PERIOD_MS}. This will not
-     * affect promos that were created before this call.
+     * Suppress signin promos in New Tab Page for {@link SignInPromo#SUPPRESSION_PERIOD_MS}. This
+     * will not affect promos that were created before this call.
      */
     public static void temporarilySuppressPromos() {
         ChromePreferenceManager.getInstance().setNewTabPageSigninPromoSuppressionPeriodStart(
@@ -349,54 +348,4 @@
             mSigninPromoController.setupPromoView(view.getContext(), view, profileData, null);
         }
     }
-
-    /** Defines the appearance and the behaviour of a generic Sign In Promo card. */
-    @VisibleForTesting
-    public static class GenericSigninPromoData implements StatusCardViewHolder.DataSource {
-        @Override
-        @StringRes
-        public int getHeader() {
-            return R.string.snippets_disabled_generic_prompt;
-        }
-
-        @Override
-        public String getDescription() {
-            return ContextUtils.getApplicationContext().getString(
-                    R.string.snippets_disabled_signed_out_instructions);
-        }
-
-        @Override
-        @StringRes
-        public int getActionLabel() {
-            return R.string.sign_in_button;
-        }
-
-        @Override
-        public void performAction(Context context) {
-            AccountSigninActivity.startIfAllowed(
-                    context, SigninAccessPoint.NTP_CONTENT_SUGGESTIONS);
-        }
-    }
-
-    /**
-     * View Holder for {@link SignInPromo} if the generic promo is to be shown.
-     */
-    public static class GenericPromoViewHolder extends StatusCardViewHolder {
-        public GenericPromoViewHolder(SuggestionsRecyclerView parent,
-                ContextMenuManager contextMenuManager, UiConfig config) {
-            super(parent, contextMenuManager, config);
-            if (!FeatureUtilities.isChromeHomeEnabled()) {
-                getParams().topMargin = parent.getResources().getDimensionPixelSize(
-                        R.dimen.ntp_sign_in_promo_margin_top);
-            }
-        }
-
-        @DrawableRes
-        @Override
-        protected int selectBackground(boolean hasCardAbove, boolean hasCardBelow) {
-            // Modern does not update the card background.
-            assert !SuggestionsConfig.useModernLayout();
-            return R.drawable.ntp_signin_promo_card_single;
-        }
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
index 678c8a56..72daa80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountSigninView.java
@@ -130,7 +130,7 @@
     private @UndoBehavior int mUndoBehavior;
     private String mSelectedAccountName;
     private boolean mIsDefaultAccountSelected;
-    private @StringRes int mCancelButtonTextId;
+    private @StringRes int mCancelButtonTextId = R.string.cancel;
     private boolean mIsChildAccount;
     private UserRecoverableErrorHandler.ModalDialog mGooglePlayServicesUpdateErrorHandler;
     private AlertDialog mGmsIsUpdatingDialog;
@@ -150,8 +150,6 @@
         mProfileDataCacheObserver = (String accountId) -> updateProfileData();
         mProfileDataCache = new ProfileDataCache(context,
                 context.getResources().getDimensionPixelSize(R.dimen.signin_account_image_size));
-
-        mCancelButtonTextId = R.string.no_thanks;
     }
 
     /**
@@ -219,9 +217,9 @@
     }
 
     private void initAccessPoint(@SigninAccessPoint int accessPoint) {
-        if (accessPoint == SigninAccessPoint.BOOKMARK_MANAGER
-                || accessPoint == SigninAccessPoint.RECENT_TABS) {
-            mCancelButtonTextId = R.string.cancel;
+        if (accessPoint == SigninAccessPoint.START_PAGE
+                || accessPoint == SigninAccessPoint.SIGNIN_PROMO) {
+            mCancelButtonTextId = R.string.no_thanks;
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 66c4ccd8..0f973f18 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -1951,6 +1951,7 @@
      * Tests the counter for the number of taps between opens.
      */
     @Test
+    @DisabledTest(message = "crbug.com/800334")
     @SmallTest
     @Feature({"ContextualSearch"})
     public void testTapCountDLD() throws InterruptedException, TimeoutException {
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 934cee1..b7750340 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -343,7 +343,7 @@
   return false;
 }
 
-#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
 // Show the man page if --help or -h is on the command line.
 void HandleHelpSwitches(const base::CommandLine& command_line) {
   if (command_line.HasSwitch(switches::kHelp) ||
@@ -353,7 +353,7 @@
     PLOG(FATAL) << "execlp failed";
   }
 }
-#endif
+#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
 
 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
 void SIGTERMProfilingShutdown(int signal) {
@@ -558,7 +558,7 @@
     *exit_code = 0;
     return true;  // Got a --version switch; exit with a success error code.
   }
-#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
   // This will directly exit if the user asked for help.
   HandleHelpSwitches(command_line);
 #endif
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 9744932..80584e3 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2783,6 +2783,9 @@
      flag_descriptions::kArcNativeBridgeExperimentName,
      flag_descriptions::kArcNativeBridgeExperimentDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kNativeBridgeExperimentFeature)},
+    {"arc-usb-host", flag_descriptions::kArcUsbHostName,
+     flag_descriptions::kArcUsbHostDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(arc::kUsbHostFeature)},
     {"arc-vpn", flag_descriptions::kArcVpnName,
      flag_descriptions::kArcVpnDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kVpnFeature)},
@@ -3096,7 +3099,8 @@
     {"enable-zip-archiver-packer",
      flag_descriptions::kEnableZipArchiverPackerName,
      flag_descriptions::kEnableZipArchiverPackerDescription, kOsCrOS,
-     SINGLE_VALUE_TYPE(chromeos::switches::kEnableZipArchiverPacker)},
+     ENABLE_DISABLE_VALUE_TYPE(chromeos::switches::kEnableZipArchiverPacker,
+                               chromeos::switches::kDisableZipArchiverPacker)},
     {"enable-zip-archiver-unpacker",
      flag_descriptions::kZipArchiverUnpackerName,
      flag_descriptions::kZipArchiverUnpackerDescription, kOsCrOS,
diff --git a/chrome/browser/chrome_content_renderer_manifest_overlay.json b/chrome/browser/chrome_content_renderer_manifest_overlay.json
index 2ef0ce1..6e4734bf 100644
--- a/chrome/browser/chrome_content_renderer_manifest_overlay.json
+++ b/chrome/browser/chrome_content_renderer_manifest_overlay.json
@@ -21,8 +21,8 @@
           "autofill::mojom::PasswordAutofillAgent",
           "autofill::mojom::PasswordGenerationAgent",
           "blink::mojom::document_metadata::CopylessPaste",
-          "chrome::mojom::InsecureContentRenderer",
           "chrome::mojom::ChromeRenderFrame",
+          "chrome::mojom::ContentSettingsRenderer",
           "dom_distiller::mojom::DistillerPageNotifierService",
           "extensions::mojom::AppWindow",
           "spellcheck::mojom::SpellCheckPanel"
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index cba873a8..718b581f 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -15,13 +15,12 @@
 #include "ash/autoclick/autoclick_controller.h"
 #include "ash/autoclick/mus/public/interfaces/autoclick.mojom.h"
 #include "ash/public/cpp/ash_pref_names.h"
+#include "ash/public/interfaces/constants.mojom.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/sticky_keys/sticky_keys_controller.h"
-#include "ash/system/power/backlights_forced_off_setter.h"
-#include "ash/system/power/scoped_backlights_forced_off.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
@@ -331,6 +330,11 @@
       extension_misc::kSwitchAccessExtensionId,
       resources_path.Append(extension_misc::kSwitchAccessExtensionPath),
       base::Closure()));
+
+  // Connect to ash's AccessibilityController interface.
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindInterface(ash::mojom::kServiceName, &accessibility_controller_);
 }
 
 AccessibilityManager::~AccessibilityManager() {
@@ -778,17 +782,7 @@
 }
 
 void AccessibilityManager::SetDarkenScreen(bool darken) {
-  // TODO(mash): Support forcing backlights off from within Chrome:
-  // https://crbug.com/793112
-  if (GetAshConfig() == ash::Config::MASH)
-    return;
-
-  if (darken && !scoped_backlights_forced_off_) {
-    scoped_backlights_forced_off_ =
-        ash::Shell::Get()->backlights_forced_off_setter()->ForceBacklightsOff();
-  } else if (!darken && scoped_backlights_forced_off_) {
-    scoped_backlights_forced_off_.reset();
-  }
+  accessibility_controller_->SetDarkenScreen(darken);
 }
 
 void AccessibilityManager::SetCaretHighlightEnabled(bool enabled) {
@@ -1472,7 +1466,7 @@
   }
 
   // In case the user darkened the screen, undarken it now.
-  scoped_backlights_forced_off_.reset();
+  SetDarkenScreen(false);
 
   keyboard_state_setter_.reset();
 }
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index f21dda3..a1b21e9 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -8,6 +8,7 @@
 #include <set>
 
 #include "ash/public/cpp/accessibility_types.h"
+#include "ash/public/interfaces/accessibility_controller.mojom.h"
 #include "ash/shell_observer.h"
 #include "base/callback_forward.h"
 #include "base/callback_list.h"
@@ -29,10 +30,6 @@
 
 class Profile;
 
-namespace ash {
-class ScopedBacklightsForcedOff;
-}  // namespace ash
-
 namespace gfx {
 class Rect;
 }  // namespace gfx
@@ -443,11 +440,11 @@
   std::unique_ptr<chromeos::SwitchAccessEventHandler>
       switch_access_event_handler_;
 
-  // Used to force the backlights off to darken the screen.
-  std::unique_ptr<ash::ScopedBacklightsForcedOff> scoped_backlights_forced_off_;
-
   std::unique_ptr<ScopedKeyboardStateSetter> keyboard_state_setter_;
 
+  // Ash's mojom::AccessibilityController used to SetDarkenScreen.
+  ash::mojom::AccessibilityControllerPtr accessibility_controller_;
+
   base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AccessibilityManager);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 75fd96d..324093a 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -180,10 +180,9 @@
     QuickView,
     FileManagerBrowserTest,
     ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "openQuickView"),
-                      TestParameter(NOT_IN_GUEST_MODE, "closeQuickView")));
-// Disabled due to strong flakyness (crbug.com/798772):
-//                      TestParameter(NOT_IN_GUEST_MODE,
-//                                    "openQuickViewForFoldersAfterClose")
+                      TestParameter(NOT_IN_GUEST_MODE, "closeQuickView"),
+                      TestParameter(NOT_IN_GUEST_MODE,
+                                    "openQuickViewForFoldersAfterClose")));
 
 #if defined(DISABLE_SLOW_FILESAPP_TESTS)
 #define MAYBE_DirectoryTreeContextMenu DISABLED_DirectoryTreeContextMenu
diff --git a/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm.cc b/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm.cc
index cf13997..a72ef63 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm.cc
@@ -63,8 +63,7 @@
       .SetLastActivityDay(event.features().last_activity_day())
       .SetRecentTimeActive(event.features().recent_time_active_sec())
       .SetDeviceType(event.features().device_type())
-      .SetDeviceMode(event.features().device_mode())
-      .SetOnBattery(event.features().on_battery());
+      .SetDeviceMode(event.features().device_mode());
 
   if (event.features().has_last_user_activity_time_sec()) {
     user_activity.SetLastUserActivityTime(
@@ -78,8 +77,15 @@
     user_activity.SetTimeSinceLastKey(
         event.features().time_since_last_key_sec());
   }
-  user_activity.SetBatteryPercent(
-      BucketEveryFivePercents(std::floor(event.features().battery_percent())));
+
+  if (event.features().has_on_battery()) {
+    user_activity.SetOnBattery(event.features().on_battery());
+  }
+
+  if (event.features().has_battery_percent()) {
+    user_activity.SetBatteryPercent(BucketEveryFivePercents(
+        std::floor(event.features().battery_percent())));
+  }
 
   user_activity.Record(ukm_recorder_);
 
diff --git a/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm_unittest.cc b/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm_unittest.cc
index eafcce9..45aa728 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_logger_delegate_ukm_unittest.cc
@@ -7,13 +7,77 @@
 #include <memory>
 #include <vector>
 
+#include "chrome/browser/chromeos/power/ml/user_activity_event.pb.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_ukm_test_helper.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/web_contents_tester.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
 namespace power {
 namespace ml {
 
-TEST(UserActivityLoggerDelegateUkmTest, CheckValues) {
+using ukm::builders::UserActivity;
+using ukm::builders::UserActivityId;
+using content::WebContentsTester;
+
+class UserActivityLoggerDelegateUkmTest : public TabActivityTestBase {
+ public:
+  UserActivityLoggerDelegateUkmTest() {
+    UserActivityEvent::Event* event = user_activity_event_.mutable_event();
+    event->set_type(UserActivityEvent::Event::REACTIVATE);
+    event->set_reason(UserActivityEvent::Event::USER_ACTIVITY);
+    UserActivityEvent::Features* features =
+        user_activity_event_.mutable_features();
+    features->set_last_activity_time_sec(730);
+    features->set_last_user_activity_time_sec(380);
+    features->set_last_activity_day(UserActivityEvent::Features::MON);
+    features->set_time_since_last_mouse_sec(100);
+    features->set_recent_time_active_sec(10);
+    features->set_device_type(UserActivityEvent::Features::CHROMEBOOK);
+    features->set_device_mode(UserActivityEvent::Features::CLAMSHELL);
+    features->set_battery_percent(96.0);
+  }
+
+  void UpdateOpenTabsURLs() {
+    user_activity_logger_delegate_ukm_.UpdateOpenTabsURLs();
+  }
+
+  void LogActivity() {
+    user_activity_logger_delegate_ukm_.LogActivity(user_activity_event_);
+  }
+
+ protected:
+  using UkmMetricMap = std::map<const char*, int64_t>;
+
+  UkmEntryChecker ukm_entry_checker_;
+  const GURL url0_ = GURL("https://example1.com/");
+  const GURL url1_ = GURL("https://example2.com/");
+
+  const UkmMetricMap user_activity_values_ = {
+      {UserActivity::kEventTypeName, 1},    // REACTIVATE
+      {UserActivity::kEventReasonName, 1},  // USER_ACTIVITY
+      {UserActivity::kLastActivityTimeName, 2},
+      {UserActivity::kLastUserActivityTimeName, 1},
+      {UserActivity::kLastActivityDayName, 1},  // MON
+      {UserActivity::kTimeSinceLastMouseName, 100},
+      {UserActivity::kRecentTimeActiveName, 10},
+      {UserActivity::kDeviceTypeName, 1},  // CHROMEBOOK
+      {UserActivity::kDeviceModeName, 2},  // CLAMSHELL
+      {UserActivity::kBatteryPercentName, 95}};
+
+ private:
+  UserActivityEvent user_activity_event_;
+  UserActivityLoggerDelegateUkm user_activity_logger_delegate_ukm_;
+  DISALLOW_COPY_AND_ASSIGN(UserActivityLoggerDelegateUkmTest);
+};
+
+TEST_F(UserActivityLoggerDelegateUkmTest, CheckValues) {
   const std::vector<int> original_values = {0, 14, 15, 100};
   const std::vector<int> buckets = {0, 10, 15, 100};
   for (size_t i = 0; i < original_values.size(); ++i) {
@@ -23,6 +87,80 @@
   }
 }
 
+TEST_F(UserActivityLoggerDelegateUkmTest, Basic) {
+  Browser::CreateParams params(profile(), true);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
+  TabStripModel* tab_strip_model = browser->tab_strip_model();
+  content::WebContents* fg_contents =
+      AddWebContentsAndNavigate(tab_strip_model, url0_);
+  tab_strip_model->ActivateTabAt(0, false);
+  WebContentsTester::For(fg_contents)->TestSetIsLoading(false);
+  const ukm::SourceId source_id0 = ukm_entry_checker_.GetSourceIdForUrl(url0_);
+
+  content::WebContents* bg_contents =
+      AddWebContentsAndNavigate(tab_strip_model, url1_);
+  WebContentsTester::For(bg_contents)->TestSetIsLoading(false);
+  const ukm::SourceId source_id1 = ukm_entry_checker_.GetSourceIdForUrl(url1_);
+
+  UpdateOpenTabsURLs();
+  LogActivity();
+
+  EXPECT_EQ(1,
+            ukm_entry_checker_.NumNewEntriesRecorded(UserActivity::kEntryName));
+  EXPECT_EQ(
+      2, ukm_entry_checker_.NumNewEntriesRecorded(UserActivityId::kEntryName));
+
+  ukm_entry_checker_.ExpectNewEntry(UserActivity::kEntryName, GURL(""),
+                                    user_activity_values_);
+
+  const ukm::mojom::UkmEntry* last_activity_entry =
+      ukm_entry_checker_.LastUkmEntry(UserActivity::kEntryName);
+
+  // Explicitly check kTimeSinceLastKeyName is not recorded.
+  ASSERT_FALSE(ukm::TestUkmRecorder::FindMetric(
+      last_activity_entry, UserActivity::kTimeSinceLastKeyName));
+
+  const ukm::SourceId kSourceId = last_activity_entry->source_id;
+
+  const UkmMetricMap kUserActivityIdValues({
+      {UserActivityId::kActivityIdName, kSourceId},
+  });
+
+  const std::map<ukm::SourceId, std::pair<GURL, UkmMetricMap>> expected_data({
+      {source_id0, std::make_pair(url0_, kUserActivityIdValues)},
+      {source_id1, std::make_pair(url1_, kUserActivityIdValues)},
+  });
+
+  ukm_entry_checker_.ExpectNewEntries(UserActivityId::kEntryName,
+                                      expected_data);
+
+  tab_strip_model->CloseAllTabs();
+}
+
+TEST_F(UserActivityLoggerDelegateUkmTest, NoOpenTabs) {
+  Browser::CreateParams params(profile(), true);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
+
+  UpdateOpenTabsURLs();
+  LogActivity();
+
+  EXPECT_EQ(1,
+            ukm_entry_checker_.NumNewEntriesRecorded(UserActivity::kEntryName));
+  EXPECT_EQ(
+      0, ukm_entry_checker_.NumNewEntriesRecorded(UserActivityId::kEntryName));
+
+  ukm_entry_checker_.ExpectNewEntry(UserActivity::kEntryName, GURL(""),
+                                    user_activity_values_);
+
+  const ukm::mojom::UkmEntry* last_activity_entry =
+      ukm_entry_checker_.LastUkmEntry(UserActivity::kEntryName);
+
+  ASSERT_FALSE(ukm::TestUkmRecorder::FindMetric(
+      last_activity_entry, UserActivity::kTimeSinceLastKeyName));
+}
+
 }  // namespace ml
 }  // namespace power
 }  // namespace chromeos
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index 69e0290..95b0bade 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/content_settings_renderer.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/renderer_configuration.mojom.h"
@@ -52,6 +53,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/canonical_cookie.h"
 #include "storage/common/fileapi/file_system_types.h"
+#include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h"
 #include "url/origin.h"
 
 using content::BrowserThread;
@@ -808,8 +810,10 @@
     content::RenderFrameHost* render_frame_host) {
   // We want to tell the renderer-side code to ignore content settings for this
   // page.
-  render_frame_host->Send(new ChromeViewMsg_SetAsInterstitial(
-      render_frame_host->GetRoutingID()));
+  chrome::mojom::ContentSettingsRendererAssociatedPtr content_settings_renderer;
+  render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
+      &content_settings_renderer);
+  content_settings_renderer->SetAsInterstitial();
 }
 
 bool TabSpecificContentSettings::OnMessageReceived(
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 7b8e2be..ca8d6f42 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -324,8 +324,7 @@
 void ComponentLoader::AddZipArchiverExtension() {
 #if defined(OS_CHROMEOS)
   base::FilePath resources_path;
-  if ((base::CommandLine::ForCurrentProcess()->HasSwitch(
-           chromeos::switches::kEnableZipArchiverPacker) ||
+  if ((chromeos::switches::IsZipArchiverPackerEnabled() ||
        chromeos::switches::IsZipArchiverUnpackerEnabled()) &&
       PathService::Get(chrome::DIR_RESOURCES, &resources_path)) {
     AddWithNameAndDescriptionFromDir(
diff --git a/chrome/browser/feature_engagement/new_tab/new_tab_tracker_browsertest.cc b/chrome/browser/feature_engagement/new_tab/new_tab_tracker_browsertest.cc
index acccdbf..2b10e1b 100644
--- a/chrome/browser/feature_engagement/new_tab/new_tab_tracker_browsertest.cc
+++ b/chrome/browser/feature_engagement/new_tab/new_tab_tracker_browsertest.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/tabs/new_tab_button.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "components/feature_engagement/public/event_constants.h"
@@ -107,13 +107,8 @@
       .WillRepeatedly(::testing::Return(false));
   chrome::FocusLocationBar(browser());
 
-  // At the top this test should be a no-op if the experimental controller is
-  // used. Otherwise, we know the cast from TabStrip->TabStripImpl is safe.
-  TabStripImpl* tab_strip = BrowserView::GetBrowserViewForBrowser(browser())
-                                ->tabstrip()
-                                ->AsTabStripImpl();
-  ASSERT_TRUE(tab_strip);
-
+  TabStrip* tab_strip =
+      BrowserView::GetBrowserViewForBrowser(browser())->tabstrip();
   EXPECT_TRUE(
       tab_strip->new_tab_button()->new_tab_promo()->GetWidget()->IsVisible());
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 154b6e8..057c824b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2420,6 +2420,10 @@
 const char kArcNativeBridgeExperimentDescription[] =
     "Enables experimental native bridge feature.";
 
+const char kArcUsbHostName[] = "Enable ARC USB host integration";
+const char kArcUsbHostDescription[] =
+    "Allow Android apps to use USB host feature on ChromeOS devices.";
+
 const char kArcVpnName[] = "Enable ARC VPN integration";
 const char kArcVpnDescription[] =
     "Allow Android VPN clients to tunnel Chrome traffic.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e30487c1..d2bf2e5 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1497,6 +1497,9 @@
 extern const char kArcNativeBridgeExperimentName[];
 extern const char kArcNativeBridgeExperimentDescription[];
 
+extern const char kArcUsbHostName[];
+extern const char kArcUsbHostDescription[];
+
 extern const char kArcVpnName[];
 extern const char kArcVpnDescription[];
 
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index 39bf2307..05144ed 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -18,6 +18,8 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/pepper_broker_infobar_delegate.h"
 #include "chrome/browser/plugins/hung_plugin_infobar_delegate.h"
+#include "chrome/browser/plugins/plugin_infobar_delegates.h"
+#include "chrome/browser/plugins/plugin_metadata.h"
 #include "chrome/browser/plugins/plugin_observer.h"
 #include "chrome/browser/plugins/reload_plugin_infobar_delegate.h"
 #include "chrome/browser/previews/previews_infobar_delegate.h"
@@ -220,6 +222,7 @@
       {"extension_dev_tools", IBD::EXTENSION_DEV_TOOLS_INFOBAR_DELEGATE},
       {"nacl", IBD::NACL_INFOBAR_DELEGATE},
       {"pepper_broker", IBD::PEPPER_BROKER_INFOBAR_DELEGATE},
+      {"outdated_plugin", IBD::OUTDATED_PLUGIN_INFOBAR_DELEGATE},
       {"reload_plugin", IBD::RELOAD_PLUGIN_INFOBAR_DELEGATE},
       {"plugin_observer", IBD::PLUGIN_OBSERVER_INFOBAR_DELEGATE},
       {"file_access_disabled", IBD::FILE_ACCESS_DISABLED_INFOBAR_DELEGATE},
@@ -273,6 +276,13 @@
           base::ASCIIToUTF16("Test Plugin"), nullptr, nullptr,
           base::Callback<void(bool)>());
       break;
+    case IBD::OUTDATED_PLUGIN_INFOBAR_DELEGATE:
+      OutdatedPluginInfoBarDelegate::Create(
+          GetInfoBarService(), nullptr,
+          std::make_unique<PluginMetadata>(
+              "test-plugin", base::ASCIIToUTF16("Test Plugin"), true, GURL(),
+              GURL(), base::ASCIIToUTF16("Test"), std::string()));
+      break;
     case IBD::RELOAD_PLUGIN_INFOBAR_DELEGATE:
       ReloadPluginInfoBarDelegate::Create(
           GetInfoBarService(), nullptr,
@@ -415,6 +425,10 @@
   ShowAndVerifyUi();
 }
 
+IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_outdated_plugin) {
+  ShowAndVerifyUi();
+}
+
 IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_reload_plugin) {
   ShowAndVerifyUi();
 }
diff --git a/chrome/browser/plugins/plugin_installer_observer.cc b/chrome/browser/plugins/plugin_installer_observer.cc
index f864934..9579838 100644
--- a/chrome/browser/plugins/plugin_installer_observer.cc
+++ b/chrome/browser/plugins/plugin_installer_observer.cc
@@ -8,11 +8,13 @@
 
 PluginInstallerObserver::PluginInstallerObserver(PluginInstaller* installer)
     : installer_(installer) {
-  installer->AddObserver(this);
+  if (installer_)
+    installer_->AddObserver(this);
 }
 
 PluginInstallerObserver::~PluginInstallerObserver() {
-  installer_->RemoveObserver(this);
+  if (installer_)
+    installer_->RemoveObserver(this);
 }
 
 void PluginInstallerObserver::DownloadFinished() {
@@ -20,11 +22,13 @@
 
 WeakPluginInstallerObserver::WeakPluginInstallerObserver(
     PluginInstaller* installer) : PluginInstallerObserver(installer) {
-  installer->AddWeakObserver(this);
+  if (installer)
+    installer->AddWeakObserver(this);
 }
 
 WeakPluginInstallerObserver::~WeakPluginInstallerObserver() {
-  installer()->RemoveWeakObserver(this);
+  if (installer())
+    installer()->RemoveWeakObserver(this);
 }
 
 void WeakPluginInstallerObserver::OnlyWeakObserversLeft() {
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index d8b300125..50f8fca4 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -2830,8 +2830,16 @@
 
 // Checks that non-http/https/chrome-extension subresource cancels the
 // prerender.
+// Disabled on ChromeOS due to flakyness. See https://crbug.com/800311.
+#if defined(OS_CHROMEOS)
+#define MAYBE_PrerenderCancelSubresourceUnsupportedScheme \
+  DISABLED_PrerenderCancelSubresourceUnsupportedScheme
+#else
+#define MAYBE_PrerenderCancelSubresourceUnsupportedScheme \
+  PrerenderCancelSubresourceUnsupportedScheme
+#endif
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
-                       PrerenderCancelSubresourceUnsupportedScheme) {
+                       MAYBE_PrerenderCancelSubresourceUnsupportedScheme) {
   GURL image_url = GURL("invalidscheme://www.google.com/test.jpg");
   base::StringPairs replacement_text;
   replacement_text.push_back(
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
index 78d2c27..3eec557 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_observer.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit.h"
 #include "chrome/browser/resource_coordinator/time.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -84,8 +84,8 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-    tab_strip_model_ = std::make_unique<TabStripModelImpl>(
-        &tab_strip_model_delegate_, profile());
+    tab_strip_model_ =
+        std::make_unique<TabStripModel>(&tab_strip_model_delegate_, profile());
     tab_strip_model_->AddObserver(&source_);
   }
 
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
index 544982d8..5d2d574 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h"
 #include "chrome/browser/resource_coordinator/time.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -62,8 +62,8 @@
     // Commit an URL to allow discarding.
     web_contents_->SetLastCommittedURL(GURL("https://www.example.com"));
 
-    tab_strip_model_ = std::make_unique<TabStripModelImpl>(
-        &tab_strip_model_delegate_, profile());
+    tab_strip_model_ =
+        std::make_unique<TabStripModel>(&tab_strip_model_delegate_, profile());
     tab_strip_model_->AppendWebContents(web_contents_.get(), false);
     web_contents_->WasHidden();
     tab_strip_model_->AppendWebContents(web_contents(), false);
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index ee463aa3..e166d00 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -33,7 +33,7 @@
 #include "chrome/browser/resource_coordinator/time.h"
 #include "chrome/browser/sessions/tab_loader.h"
 #include "chrome/browser/ui/tab_ui_helper.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -414,7 +414,7 @@
 TEST_F(TabManagerTest, DiscardWebContentsAt) {
   // Create a tab strip in a visible and active window.
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   tabstrip.AddObserver(tab_manager_);
 
   BrowserInfo browser_info;
@@ -479,7 +479,7 @@
   // the web content instead and therefore should be handled by WebContentsData
   // (which observes the web content).
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
 
   // Create 2 tabs because the active tab cannot be discarded.
   tabstrip.AppendWebContents(CreateWebContents(), true);
@@ -507,7 +507,7 @@
 // discarded.
 TEST_F(TabManagerTest, DiscardedTabKeepsLastActiveTime) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   tabstrip.AddObserver(tab_manager_);
 
   tabstrip.AppendWebContents(CreateWebContents(), true);
@@ -538,7 +538,7 @@
 
 TEST_F(TabManagerTest, ShouldPurgeAtDefaultTime) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   tabstrip.AddObserver(tab_manager_);
 
   WebContents* test_contents = CreateWebContents();
@@ -572,7 +572,7 @@
 
 TEST_F(TabManagerTest, ActivateTabResetPurgeState) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   tabstrip.AddObserver(tab_manager_);
 
   BrowserInfo browser_info;
@@ -621,11 +621,11 @@
   WebContents* web_contents2b = CreateWebContents();
 
   // Create 2 TabStripModels.
-  TabStripModelImpl tab_strip1(&delegate, profile());
+  TabStripModel tab_strip1(&delegate, profile());
   tab_strip1.AppendWebContents(web_contents1a, true);
   tab_strip1.AppendWebContents(web_contents1b, false);
 
-  TabStripModelImpl tab_strip2(&delegate, profile());
+  TabStripModel tab_strip2(&delegate, profile());
   tab_strip2.AppendWebContents(web_contents2a, true);
   tab_strip2.AppendWebContents(web_contents2b, false);
 
@@ -680,11 +680,11 @@
   TabStripDummyDelegate delegate;
 
   // Create 2 TabStripModels.
-  TabStripModelImpl tab_strip1(&delegate, profile());
+  TabStripModel tab_strip1(&delegate, profile());
   tab_strip1.AppendWebContents(CreateWebContents(), true);
   tab_strip1.AppendWebContents(CreateWebContents(), false);
 
-  TabStripModelImpl tab_strip2(&delegate, profile());
+  TabStripModel tab_strip2(&delegate, profile());
   tab_strip2.AppendWebContents(CreateWebContents(), true);
   tab_strip2.AppendWebContents(CreateWebContents(), false);
 
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.js b/chrome/browser/resources/chromeos/login/offline_gaia.js
index 717a1126..91dce7ab 100644
--- a/chrome/browser/resources/chromeos/login/offline_gaia.js
+++ b/chrome/browser/resources/chromeos/login/offline_gaia.js
@@ -81,7 +81,7 @@
     },
 
     onForgotPasswordCloseTap_: function() {
-      this.$$('#.forgotPasswordDlg').close();
+      this.$$('#forgotPasswordDlg').close();
     },
 
     onDialogOverlayClosed_: function() {
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js
index 9b3906779..87f53af 100644
--- a/chrome/browser/resources/interventions_internals/index.js
+++ b/chrome/browser/resources/interventions_internals/index.js
@@ -110,27 +110,21 @@
 }
 
 /**
- * Helper method to expand all logs in the message-logs-table.
+ * Helper method to expand or collapse all logs in the message-logs-table.
+ *
+ * @param {boolean} expanding True for expand all log messages, and false to
+ * collapse all log messages.
  */
-function expandAllLogs() {
+function logExpansionHelper(expanding) {
   let rows = $('message-logs-table').rows;
   for (let i = 1; i < rows.length; i++) {
     if (rows[i].className.includes('expansion-row')) {
-      rows[i].className = rows[i].className.replace('hide', 'show');
-      rows[i - 1].querySelector('.arrow').className = 'arrow up';
-    }
-  }
-}
-
-/**
- * Helper method to collapse all logs in the message-logs-table.
- */
-function collapseAllLogs() {
-  let rows = $('message-logs-table').rows;
-  for (let i = 1; i < rows.length; i++) {
-    if (rows[i].className.includes('expansion-row')) {
-      rows[i].className = rows[i].className.replace('show', 'hide');
-      rows[i - 1].querySelector('.arrow').className = 'arrow down';
+      rows[i].className = expand ? 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';
+      }
     }
   }
 }
@@ -311,7 +305,7 @@
   $('log-search-bar').addEventListener('keyup', () => {
     let keyword = $('log-search-bar').value.toUpperCase();
     let rows = $('message-logs-table').rows;
-    expandAllLogs();
+    logExpansionHelper(true /* expanding */);
 
     for (let i = 1; i < rows.length; i++) {
       rows[i].style.display =
@@ -336,7 +330,7 @@
 function setupExpandLogs() {
   // Expand all button.
   $('expand-log-button').addEventListener('click', () => {
-    expandAllLogs();
+    logExpansionHelper(true /* expanding */);
     $('collapse-log-button').style.display = '';
     $('expand-log-button').style.display = 'none';
   });
@@ -344,7 +338,7 @@
   // Collapse all button.
   $('collapse-log-button').style.display = 'none';
   $('collapse-log-button').addEventListener('click', () => {
-    collapseAllLogs();
+    logExpansionHelper(false /* expanding */);
     $('collapse-log-button').style.display = 'none';
     $('expand-log-button').style.display = '';
   });
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js
index 07a7a18..e48aadd8 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.js
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js
@@ -19,32 +19,29 @@
       /** @private {!Array<Command>} */
       menuCommands_: {
         type: Array,
-        value: function() {
-          return [
-            Command.EDIT,
-            Command.COPY_URL,
-            Command.SHOW_IN_FOLDER,
-            Command.DELETE,
-            // <hr>
-            Command.OPEN_NEW_TAB,
-            Command.OPEN_NEW_WINDOW,
-            Command.OPEN_INCOGNITO,
-          ];
-        },
+        computed: 'computeMenuCommands_(menuSource_)',
       },
 
       /** @private {Set<string>} */
       menuIds_: {
         type: Object,
-        observer: 'onMenuIdsChanged_',
       },
 
       /** @private */
       hasAnySublabel_: {
         type: Boolean,
         reflectToAttribute: true,
+        computed: 'computeHasAnySublabel_(menuCommands_, menuIds_)',
       },
 
+      /**
+       * Indicates where the context menu was opened from. Will be NONE if
+       * menu is not open, indicating that commands are from keyboard shortcuts
+       * or elsewhere in the UI.
+       * @private {MenuSource}
+       */
+      menuSource_: MenuSource.NONE,
+
       /** @private */
       globalCanEdit_: Boolean,
     },
@@ -62,8 +59,9 @@
       this.updateFromStore();
 
       /** @private {function(!Event)} */
-      this.boundOnOpenItemMenu_ = this.onOpenItemMenu_.bind(this);
-      document.addEventListener('open-item-menu', this.boundOnOpenItemMenu_);
+      this.boundOnOpenCommandMenu_ = this.onOpenCommandMenu_.bind(this);
+      document.addEventListener(
+          'open-command-menu', this.boundOnOpenCommandMenu_);
 
       /** @private {function()} */
       this.boundOnCommandUndo_ = () => {
@@ -75,14 +73,6 @@
       this.boundOnKeydown_ = this.onKeydown_.bind(this);
       document.addEventListener('keydown', this.boundOnKeydown_);
 
-      /**
-       * Indicates where the context menu was opened from. Will be NONE if
-       * menu is not open, indicating that commands are from keyboard shortcuts
-       * or elsewhere in the UI.
-       * @private {MenuSource}
-       */
-      this.menuSource_ = MenuSource.NONE;
-
       /** @private {!Map<Command, cr.ui.KeyboardShortcutList>} */
       this.shortcuts_ = new Map();
 
@@ -106,7 +96,8 @@
 
     detached: function() {
       CommandManager.instance_ = null;
-      document.removeEventListener('open-item-menu', this.boundOnOpenItemMenu_);
+      document.removeEventListener(
+          'open-command-menu', this.boundOnOpenCommandMenu_);
       document.removeEventListener('command-undo', this.boundOnCommandUndo_);
       document.removeEventListener('keydown', this.boundOnKeydown_);
     },
@@ -213,7 +204,7 @@
         case Command.DELETE:
           return itemIds.size > 0 && this.globalCanEdit_;
         case Command.SHOW_IN_FOLDER:
-          return this.menuSource_ == MenuSource.LIST && itemIds.size == 1 &&
+          return this.menuSource_ == MenuSource.ITEM && itemIds.size == 1 &&
               this.getState().search.term != '' &&
               !this.containsMatchingNode_(itemIds, function(node) {
                 return !node.parentId || node.parentId == ROOT_NODE_ID;
@@ -222,6 +213,12 @@
         case Command.OPEN_NEW_WINDOW:
         case Command.OPEN_INCOGNITO:
           return itemIds.size > 0;
+        case Command.ADD_BOOKMARK:
+        case Command.ADD_FOLDER:
+        case Command.SORT:
+        case Command.EXPORT:
+        case Command.IMPORT:
+          return true;
         default:
           return false;
       }
@@ -234,10 +231,10 @@
      *     menu.
      */
     isCommandEnabled_: function(command, itemIds) {
+      const state = this.getState();
       switch (command) {
         case Command.EDIT:
         case Command.DELETE:
-          const state = this.getState();
           return !this.containsMatchingNode_(itemIds, function(node) {
             return !bookmarks.util.canEditNode(state, node.id);
           });
@@ -246,14 +243,33 @@
           return this.expandUrls_(itemIds).length > 0;
         case Command.OPEN_INCOGNITO:
           return this.expandUrls_(itemIds).length > 0 &&
-              this.getState().prefs.incognitoAvailability !=
+              state.prefs.incognitoAvailability !=
               IncognitoAvailability.DISABLED;
+        case Command.SORT:
+          return this.canChangeList_() &&
+              state.nodes[state.selectedFolder].children.length > 1;
+        case Command.ADD_BOOKMARK:
+        case Command.ADD_FOLDER:
+          return this.canChangeList_();
+        case Command.IMPORT:
+          return this.globalCanEdit_;
         default:
           return true;
       }
     },
 
     /**
+     * Returns whether the currently displayed bookmarks list can be changed.
+     * @private
+     * @return {boolean}
+     */
+    canChangeList_: function() {
+      const state = this.getState();
+      return state.search.term == '' &&
+          bookmarks.util.canReorderChildren(state, state.selectedFolder);
+    },
+
+    /**
      * @param {Command} command
      * @param {!Set<string>} itemIds
      */
@@ -356,6 +372,26 @@
               selectedFolder, Array.from(selectedItems),
               bookmarks.ApiListener.highlightUpdatedItems);
           break;
+        case Command.SORT:
+          chrome.bookmarkManagerPrivate.sortChildren(
+              assert(state.selectedFolder));
+          bookmarks.ToastManager.getInstance().show(
+              loadTimeData.getString('toastFolderSorted'), true);
+          break;
+        case Command.ADD_BOOKMARK:
+          /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
+              .showAddDialog(false, assert(state.selectedFolder));
+          break;
+        case Command.ADD_FOLDER:
+          /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
+              .showAddDialog(true, assert(state.selectedFolder));
+          break;
+        case Command.IMPORT:
+          chrome.bookmarks.import();
+          break;
+        case Command.EXPORT:
+          chrome.bookmarks.export();
+          break;
         default:
           assert(false);
       }
@@ -566,7 +602,23 @@
         case Command.OPEN_INCOGNITO:
           label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito';
           break;
+        case Command.SORT:
+          label = 'menuSort';
+          break;
+        case Command.ADD_BOOKMARK:
+          label = 'menuAddBookmark';
+          break;
+        case Command.ADD_FOLDER:
+          label = 'menuAddFolder';
+          break;
+        case Command.IMPORT:
+          label = 'menuImport';
+          break;
+        case Command.EXPORT:
+          label = 'menuExport';
+          break;
       }
+      assert(label);
 
       return loadTimeData.getString(assert(label));
     },
@@ -591,7 +643,38 @@
     },
 
     /** @private */
-    onMenuIdsChanged_: function() {
+    computeMenuCommands_: function() {
+      switch (this.menuSource_) {
+        case MenuSource.ITEM:
+        case MenuSource.TREE:
+          return [
+            Command.EDIT,
+            Command.COPY_URL,
+            Command.SHOW_IN_FOLDER,
+            Command.DELETE,
+            // <hr>
+            Command.OPEN_NEW_TAB,
+            Command.OPEN_NEW_WINDOW,
+            Command.OPEN_INCOGNITO,
+          ];
+        case MenuSource.TOOLBAR:
+          return [
+            Command.SORT,
+            // <hr>
+            Command.ADD_BOOKMARK,
+            Command.ADD_FOLDER,
+            // <hr>
+            Command.IMPORT,
+            Command.EXPORT,
+          ];
+        case MenuSource.NONE:
+          return [];
+      }
+      assert(false);
+    },
+
+    /** @private */
+    computeHasAnySublabel_: function() {
       if (!this.menuIds_)
         return;
 
@@ -605,8 +688,10 @@
      * @private
      */
     showDividerAfter_: function(command, itemIds) {
-      return command == Command.DELETE &&
-          (this.globalCanEdit_ || this.isSingleBookmark_(itemIds));
+      return ((command == Command.SORT || command == Command.ADD_FOLDER) &&
+              this.menuSource_ == MenuSource.TOOLBAR) ||
+          (command == Command.DELETE &&
+           (this.globalCanEdit_ || this.isSingleBookmark_(itemIds)));
     },
 
     /**
@@ -639,7 +724,7 @@
      * @param {Event} e
      * @private
      */
-    onOpenItemMenu_: function(e) {
+    onOpenCommandMenu_: function(e) {
       if (e.detail.targetElement) {
         this.openCommandMenuAtElement(e.detail.targetElement, e.detail.source);
       } else {
diff --git a/chrome/browser/resources/md_bookmarks/constants.js b/chrome/browser/resources/md_bookmarks/constants.js
index bbda71c..00bd2a0 100644
--- a/chrome/browser/resources/md_bookmarks/constants.js
+++ b/chrome/browser/resources/md_bookmarks/constants.js
@@ -39,8 +39,14 @@
   COPY: 12,
   CUT: 13,
   PASTE: 14,
+  SORT: 15,
+  ADD_BOOKMARK: 16,
+  ADD_FOLDER: 17,
+  IMPORT: 18,
+  EXPORT: 19,
+
   // Append new values to the end of the enum.
-  MAX_VALUE: 15,
+  MAX_VALUE: 20,
 };
 
 /**
@@ -49,8 +55,9 @@
  */
 const MenuSource = {
   NONE: 0,
-  LIST: 1,
+  ITEM: 1,
   TREE: 2,
+  TOOLBAR: 3,
 };
 
 /**
diff --git a/chrome/browser/resources/md_bookmarks/item.html b/chrome/browser/resources/md_bookmarks/item.html
index b39e781..d0f8fdc 100644
--- a/chrome/browser/resources/md_bookmarks/item.html
+++ b/chrome/browser/resources/md_bookmarks/item.html
@@ -32,7 +32,6 @@
         text-decoration: none;
       }
 
-      :host(:focus) #website-title,
       :host([is-selected-item_]) #website-title {
         flex: 0 auto;
       }
@@ -46,7 +45,6 @@
         min-width: 100px;
       }
 
-      :host(:focus) #website-url,
       :host([is-selected-item_]) #website-url {
         display: block;
       }
diff --git a/chrome/browser/resources/md_bookmarks/item.js b/chrome/browser/resources/md_bookmarks/item.js
index c3c12c3..d83ef18 100644
--- a/chrome/browser/resources/md_bookmarks/item.js
+++ b/chrome/browser/resources/md_bookmarks/item.js
@@ -71,14 +71,15 @@
    */
   onContextMenu_: function(e) {
     e.preventDefault();
+    e.stopPropagation();
     this.focus();
     if (!this.isSelectedItem_)
       this.selectThisItem_();
 
-    this.fire('open-item-menu', {
+    this.fire('open-command-menu', {
       x: e.clientX,
       y: e.clientY,
-      source: MenuSource.LIST,
+      source: MenuSource.ITEM,
     });
   },
 
@@ -90,9 +91,9 @@
     e.stopPropagation();
     e.preventDefault();
     this.selectThisItem_();
-    this.fire('open-item-menu', {
+    this.fire('open-command-menu', {
       targetElement: e.target,
-      source: MenuSource.LIST,
+      source: MenuSource.ITEM,
     });
   },
 
diff --git a/chrome/browser/resources/md_bookmarks/list.js b/chrome/browser/resources/md_bookmarks/list.js
index 3898fc0..bf84521a 100644
--- a/chrome/browser/resources/md_bookmarks/list.js
+++ b/chrome/browser/resources/md_bookmarks/list.js
@@ -46,7 +46,7 @@
 
   listeners: {
     'click': 'deselectItems_',
-    'open-item-menu': 'onOpenItemMenu_',
+    'open-command-menu': 'onOpenCommandMenu_',
   },
 
   attached: function() {
@@ -167,9 +167,10 @@
    * @param {Event} e
    * @private
    */
-  onOpenItemMenu_: function(e) {
+  onOpenCommandMenu_: function(e) {
     // If the item is not visible, scroll to it before rendering the menu.
-    this.scrollToId_(/** @type {BookmarksItemElement} */ (e.path[0]).itemId);
+    if (e.source == MenuSource.ITEM)
+      this.scrollToId_(/** @type {BookmarksItemElement} */ (e.path[0]).itemId);
   },
 
   /**
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.html b/chrome/browser/resources/md_bookmarks/toolbar.html
index 94a2776..219c383c 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.html
+++ b/chrome/browser/resources/md_bookmarks/toolbar.html
@@ -1,11 +1,8 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://bookmarks/edit_dialog.html">
 <link rel="import" href="chrome://bookmarks/shared_style.html">
 
 <dom-module id="bookmarks-toolbar">
@@ -62,42 +59,6 @@
         <div></div>
       </button>
     </cr-toolbar>
-    <template is="cr-lazy-render" id="dropdown">
-      <dialog is="cr-action-menu">
-        <button id="sortButton"
-            class="dropdown-item"
-            on-tap="onSortTap_"
-            disabled="[[!canSortFolder_]]">
-          $i18n{menuSort}
-        </button>
-        <hr aria-hidden="true">
-        <button id="addBookmarkButton"
-            class="dropdown-item"
-            on-tap="onAddBookmarkTap_"
-            disabled="[[!canChangeList_]]">
-          $i18n{menuAddBookmark}
-        </button>
-        <button class="dropdown-item"
-            on-tap="onAddFolderTap_"
-            disabled="[[!canChangeList_]]">
-          $i18n{menuAddFolder}
-        </button>
-        <hr aria-hidden="true">
-        <button id="importBookmarkButton"
-            class="dropdown-item"
-            on-tap="onImportTap_"
-            disabled="[[!globalCanEdit_]]">
-          $i18n{menuImport}
-        </button>
-        <button class="dropdown-item"
-            on-tap="onExportTap_">
-          $i18n{menuExport}
-        </button>
-      </dialog>
-    </template>
-    <template is="cr-lazy-render" id="addDialog">
-      <bookmarks-edit-dialog></bookmarks-edit-dialog>
-    </template>
     <template is="dom-if" if="[[showSelectionOverlay]]">
       <cr-toolbar-selection-overlay delete-label="$i18n{delete}"
           cancel-label="$i18n{cancel}"
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.js b/chrome/browser/resources/md_bookmarks/toolbar.js
index 26ef609..a3ed76c 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.js
+++ b/chrome/browser/resources/md_bookmarks/toolbar.js
@@ -10,12 +10,6 @@
   ],
 
   properties: {
-    /** @private */
-    searchTerm_: {
-      type: String,
-      observer: 'onSearchTermChanged_',
-    },
-
     sidebarWidth: {
       type: String,
       observer: 'onSidebarWidthChanged_',
@@ -34,31 +28,17 @@
       reflectToAttribute: true,
     },
 
+    /** @private */
+    searchTerm_: {
+      type: String,
+      observer: 'onSearchTermChanged_',
+    },
+
     /** @private {!Set<string>} */
     selectedItems_: Object,
 
     /** @private */
     globalCanEdit_: Boolean,
-
-    /** @private */
-    selectedFolder_: String,
-
-    /** @private */
-    selectedFolderChildren_: Number,
-
-    /** @private */
-    canSortFolder_: {
-      type: Boolean,
-      computed: `computeCanSortFolder_(
-          canChangeList_, selectedFolder_, selectedFolderChildren_)`,
-    },
-
-    /** @private */
-    canChangeList_: {
-      type: Boolean,
-      computed:
-          'computeCanChangeList_(selectedFolder_, searchTerm_, globalCanEdit_)',
-    }
   },
 
   attached: function() {
@@ -71,15 +51,6 @@
     this.watch('globalCanEdit_', function(state) {
       return state.prefs.canEdit;
     });
-    this.watch('selectedFolder_', function(state) {
-      return state.selectedFolder;
-    });
-    this.watch('selectedFolderChildren_', (state) => {
-      if (!state.selectedFolder)
-        return 0;
-
-      return state.nodes[state.selectedFolder].children.length;
-    });
     this.updateFromStore();
   },
 
@@ -94,44 +65,10 @@
    * @private
    */
   onMenuButtonOpenTap_: function(e) {
-    const menu = /** @type {!CrActionMenuElement} */ (this.$.dropdown.get());
-    menu.showAt(/** @type {!Element} */ (e.target));
-  },
-
-  /** @private */
-  onSortTap_: function() {
-    chrome.bookmarkManagerPrivate.sortChildren(assert(this.selectedFolder_));
-    bookmarks.ToastManager.getInstance().show(
-        loadTimeData.getString('toastFolderSorted'), true);
-    this.closeDropdownMenu_();
-  },
-
-  /** @private */
-  onAddBookmarkTap_: function() {
-    const dialog =
-        /** @type {BookmarksEditDialogElement} */ (this.$.addDialog.get());
-    dialog.showAddDialog(false, assert(this.selectedFolder_));
-    this.closeDropdownMenu_();
-  },
-
-  /** @private */
-  onAddFolderTap_: function() {
-    const dialog =
-        /** @type {BookmarksEditDialogElement} */ (this.$.addDialog.get());
-    dialog.showAddDialog(true, assert(this.selectedFolder_));
-    this.closeDropdownMenu_();
-  },
-
-  /** @private */
-  onImportTap_: function() {
-    chrome.bookmarks.import();
-    this.closeDropdownMenu_();
-  },
-
-  /** @private */
-  onExportTap_: function() {
-    chrome.bookmarks.export();
-    this.closeDropdownMenu_();
+    this.fire('open-command-menu', {
+      targetElement: e.target,
+      source: MenuSource.TOOLBAR,
+    });
   },
 
   /** @private */
@@ -147,12 +84,6 @@
     this.dispatch(bookmarks.actions.deselectItems());
   },
 
-  /** @private */
-  closeDropdownMenu_: function() {
-    const menu = /** @type {!CrActionMenuElement} */ (this.$.dropdown.get());
-    menu.close();
-  },
-
   /**
    * @param {Event} e
    * @private
@@ -177,24 +108,6 @@
    * @return {boolean}
    * @private
    */
-  computeCanSortFolder_: function() {
-    return this.canChangeList_ && this.selectedFolderChildren_ > 1;
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
-  computeCanChangeList_: function() {
-    return !this.searchTerm_ &&
-        bookmarks.util.canReorderChildren(
-            this.getState(), this.selectedFolder_);
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
   shouldShowSelectionOverlay_: function() {
     return this.selectedItems_.size > 1 && this.globalCanEdit_;
   },
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 279b6d3..ea33fc27 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -64,7 +64,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/insecure_content_renderer.mojom.h"
+#include "chrome/common/content_settings_renderer.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -144,7 +144,7 @@
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_test_util.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(USE_NSS_CERTS)
@@ -3386,8 +3386,8 @@
   void SetAllowRunningInsecureContent() {
     content::RenderFrameHost* render_frame_host =
         browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
-    chrome::mojom::InsecureContentRendererPtr renderer;
-    render_frame_host->GetRemoteInterfaces()->GetInterface(&renderer);
+    chrome::mojom::ContentSettingsRendererAssociatedPtr renderer;
+    render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&renderer);
     renderer->SetAllowRunningInsecureContent();
   }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index fb87e12..f0486c4 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -919,8 +919,6 @@
       "tabs/tab_strip_model.cc",
       "tabs/tab_strip_model.h",
       "tabs/tab_strip_model_delegate.h",
-      "tabs/tab_strip_model_impl.cc",
-      "tabs/tab_strip_model_impl.h",
       "tabs/tab_strip_model_observer.cc",
       "tabs/tab_strip_model_observer.h",
       "tabs/tab_strip_model_order_controller.cc",
@@ -3103,8 +3101,6 @@
         "views/tabs/tab_strip.cc",
         "views/tabs/tab_strip.h",
         "views/tabs/tab_strip_controller.h",
-        "views/tabs/tab_strip_impl.cc",
-        "views/tabs/tab_strip_impl.h",
         "views/tabs/tab_strip_layout.cc",
         "views/tabs/tab_strip_layout.h",
         "views/tabs/window_finder.cc",
diff --git a/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc b/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc
index 4773f792..7190115 100644
--- a/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc
@@ -37,6 +37,7 @@
   void SetClient(ash::mojom::AccessibilityControllerClientPtr client) override {
     was_client_set_ = true;
   }
+  void SetDarkenScreen(bool darken) override {}
 
   bool was_client_set() const { return was_client_set_; }
 
diff --git a/chrome/browser/ui/ash/tab_scrubber.cc b/chrome/browser/ui/ash/tab_scrubber.cc
index 0f12870..4584b85 100644
--- a/chrome/browser/ui/ash/tab_scrubber.cc
+++ b/chrome/browser/ui/ash/tab_scrubber.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "ui/aura/window.h"
@@ -44,7 +44,7 @@
 }
 
 // static
-gfx::Point TabScrubber::GetStartPoint(TabStripImpl* tab_strip,
+gfx::Point TabScrubber::GetStartPoint(TabStrip* tab_strip,
                                       int index,
                                       TabScrubber::Direction direction) {
   int initial_tab_offset = Tab::GetPinnedWidth() / 2;
@@ -109,11 +109,7 @@
 
   BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
       browser->window()->GetNativeWindow());
-  TabStripImpl* tab_strip = browser_view->tabstrip()->AsTabStripImpl();
-  if (!tab_strip) {
-    DLOG(WARNING) << "TabScrubber disabled for experimental tab strip.";
-    return;
-  }
+  TabStrip* tab_strip = browser_view->tabstrip();
 
   if (tab_strip->IsAnimating()) {
     FinishScrub(false);
@@ -237,12 +233,7 @@
   DCHECK(browser);
   DCHECK(browser_view);
 
-  tab_strip_ = browser_view->tabstrip()->AsTabStripImpl();
-  if (!tab_strip_) {
-    DLOG(WARNING) << "TabScrubber disabled for experimental tab strip.";
-    return;
-  }
-
+  tab_strip_ = browser_view->tabstrip();
   scrubbing_ = true;
   browser_ = browser;
 
@@ -265,18 +256,16 @@
   if (browser_ && browser_->window()) {
     BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
         browser_->window()->GetNativeWindow());
-    TabStripImpl* tab_strip = browser_view->tabstrip()->AsTabStripImpl();
-    if (tab_strip) {
-      if (activate && highlighted_tab_ != -1) {
-        Tab* tab = tab_strip->tab_at(highlighted_tab_);
-        tab->hover_controller()->HideImmediately();
-        int distance = std::abs(highlighted_tab_ -
-                                browser_->tab_strip_model()->active_index());
-        UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.ScrubDistance", distance, 1, 20, 21);
-        browser_->tab_strip_model()->ActivateTabAt(highlighted_tab_, true);
-      }
-      tab_strip->RemoveObserver(this);
+    TabStrip* tab_strip = browser_view->tabstrip();
+    if (activate && highlighted_tab_ != -1) {
+      Tab* tab = tab_strip->tab_at(highlighted_tab_);
+      tab->hover_controller()->HideImmediately();
+      int distance = std::abs(highlighted_tab_ -
+                              browser_->tab_strip_model()->active_index());
+      UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.ScrubDistance", distance, 1, 20, 21);
+      browser_->tab_strip_model()->ActivateTabAt(highlighted_tab_, true);
     }
+    tab_strip->RemoveObserver(this);
   }
 
   browser_ = nullptr;
diff --git a/chrome/browser/ui/ash/tab_scrubber.h b/chrome/browser/ui/ash/tab_scrubber.h
index aeb5d72..8a11342 100644
--- a/chrome/browser/ui/ash/tab_scrubber.h
+++ b/chrome/browser/ui/ash/tab_scrubber.h
@@ -17,7 +17,7 @@
 
 class Browser;
 class Tab;
-class TabStripImpl;
+class TabStrip;
 
 namespace gfx {
 class Point;
@@ -35,7 +35,7 @@
 
   // Returns the virtual position of a swipe starting in the tab at |index|,
   // base on the |direction|.
-  static gfx::Point GetStartPoint(TabStripImpl* tab_strip,
+  static gfx::Point GetStartPoint(TabStrip* tab_strip,
                                   int index,
                                   TabScrubber::Direction direction);
 
@@ -89,7 +89,7 @@
   // false and there is no pending work.
   Browser* browser_;
   // The TabStrip of the active browser we're scrubbing.
-  TabStripImpl* tab_strip_;
+  TabStrip* tab_strip_;
   // The current accumulated x and y positions of a swipe, in
   // the coordinates of the TabStrip of |browser_|
   float swipe_x_;
diff --git a/chrome/browser/ui/ash/tab_scrubber_browsertest.cc b/chrome/browser/ui/ash/tab_scrubber_browsertest.cc
index 628a562c..41d6cd8 100644
--- a/chrome/browser/ui/ash/tab_scrubber_browsertest.cc
+++ b/chrome/browser/ui/ash/tab_scrubber_browsertest.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chromeos/chromeos_switches.h"
@@ -98,15 +98,13 @@
     browser()->tab_strip_model()->RemoveObserver(this);
   }
 
-  TabStripImpl* GetTabStrip(Browser* browser) {
+  TabStrip* GetTabStrip(Browser* browser) {
     aura::Window* window = browser->window()->GetNativeWindow();
     // This test depends on TabStrip impl.
-    TabStripImpl* tab_strip_impl =
-        BrowserView::GetBrowserViewForNativeWindow(window)
-            ->tabstrip()
-            ->AsTabStripImpl();
-    DCHECK(tab_strip_impl);
-    return tab_strip_impl;
+    TabStrip* tab_strip =
+        BrowserView::GetBrowserViewForNativeWindow(window)->tabstrip();
+    DCHECK(tab_strip);
+    return tab_strip;
   }
 
   float GetStartX(Browser* browser,
@@ -230,7 +228,7 @@
   }
 
   void AddTabs(Browser* browser, int num_tabs) {
-    TabStripImpl* tab_strip = GetTabStrip(browser);
+    TabStrip* tab_strip = GetTabStrip(browser);
     for (int i = 0; i < num_tabs; ++i)
       AddBlankTabAndShow(browser);
     ASSERT_EQ(num_tabs + 1, browser->tab_strip_model()->count());
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index b964f9a..4ae6f2e 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -139,7 +139,7 @@
 #include "chrome/browser/ui/tab_helpers.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "chrome/browser/ui/tabs/tab_menu_model.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/unload_controller.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
@@ -369,8 +369,8 @@
       window_(NULL),
       tab_strip_model_delegate_(new chrome::BrowserTabStripModelDelegate(this)),
       tab_strip_model_(
-          std::make_unique<TabStripModelImpl>(tab_strip_model_delegate_.get(),
-                                              params.profile)),
+          std::make_unique<TabStripModel>(tab_strip_model_delegate_.get(),
+                                          params.profile)),
       app_name_(params.app_name),
       is_trusted_source_(params.trusted_source),
       cancel_download_confirmation_state_(NOT_PROMPTED),
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
index dc6af2e6..3cc24cd3d 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller_unittest.mm
@@ -110,7 +110,7 @@
   feature_list.InitAndEnableFeature(
       password_manager::features::kEnablePasswordSelection);
   SetUpSavePendingState();
-  GetModelAndCreateIfNull()->set_hide_eye_icon(false);
+  GetModelAndCreateIfNull()->allow_passwords_revealing();
   [controller() showWindow:nil];
   SavePendingPasswordViewController* saveController =
       base::mac::ObjCCastStrict<SavePendingPasswordViewController>(
diff --git a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
index f4707d4..23f40f4 100644
--- a/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/save_pending_password_view_controller.mm
@@ -47,13 +47,14 @@
 }
 
 void FillPasswordPopup(const autofill::PasswordForm& form,
-                       bool visible,
+                       bool are_passwords_revealed,
                        NSPopUpButton* button) {
   [button removeAllItems];
   for (const base::string16& possible_password : form.all_possible_passwords) {
     base::string16 text =
-        visible ? possible_password
-                : base::string16(possible_password.length(), kBulletChar);
+        are_passwords_revealed
+            ? possible_password
+            : base::string16(possible_password.length(), kBulletChar);
     base::scoped_nsobject<NSMenuItem> newItem([[NSMenuItem alloc]
         initWithTitle:base::SysUTF16ToNSString(text)
                action:NULL
@@ -131,18 +132,22 @@
 - (void)onEyeClicked:(id)sender {
   if (!self.model)
     return;  // The view will be destroyed soon.
-  bool visible = [passwordViewButton_ state] == NSOnState;
+  bool are_passwords_revealed = [passwordViewButton_ state] == NSOnState;
+  if (are_passwords_revealed && !self.model->RevealPasswords())
+    return;
   const autofill::PasswordForm& form = self.model->pending_password();
   if (passwordSelectionField_) {
     NSInteger index = [passwordSelectionField_ indexOfSelectedItem];
     self.model->OnCredentialEdited(form.username_value,
                                    form.all_possible_passwords[index]);
-    FillPasswordPopup(form, visible, passwordSelectionField_.get());
+    FillPasswordPopup(form, are_passwords_revealed,
+                      passwordSelectionField_.get());
   } else {
     DCHECK(passwordStaticField_);
     base::string16 text =
-        visible ? form.password_value
-                : base::string16(form.password_value.length(), kBulletChar);
+        are_passwords_revealed
+            ? form.password_value
+            : base::string16(form.password_value.length(), kBulletChar);
     [passwordStaticField_ setStringValue:base::SysUTF16ToNSString(text)];
   }
 }
@@ -198,11 +203,17 @@
       if (form.all_possible_passwords.size() > 1) {
         passwordSelectionField_.reset(
             [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]);
-        FillPasswordPopup(form, false, passwordSelectionField_.get());
+        FillPasswordPopup(
+            form, self.model->are_passwords_revealed_when_bubble_is_opened(),
+            passwordSelectionField_.get());
         [passwordSelectionField_ sizeToFit];
       } else {
-        passwordStaticField_.reset([Label(
-            base::string16(form.password_value.length(), kBulletChar)) retain]);
+        if (self.model->are_passwords_revealed_when_bubble_is_opened()) {
+          passwordStaticField_.reset([Label(form.password_value) retain]);
+        } else {
+          passwordStaticField_.reset([Label(base::string16(
+              form.password_value.length(), kBulletChar)) retain]);
+        }
         // Overwrite the height of the password field because it's higher in the
         // editable mode.
         [passwordStaticField_
@@ -212,11 +223,13 @@
                                       NSHeight([EditableField(
                                           form.password_value) frame])))];
       }
-      if (!self.model->hide_eye_icon()) {
-        passwordViewButton_.reset(
-            [EyeIcon(self, @selector(onEyeClicked:)) retain]);
-        [container addSubview:passwordViewButton_];
-      }
+      passwordViewButton_.reset(
+          [EyeIcon(self, @selector(onEyeClicked:)) retain]);
+      if (self.model->are_passwords_revealed_when_bubble_is_opened())
+        [passwordViewButton_ setState:NSOnState];
+      else
+        [passwordViewButton_ setState:NSOffState];
+      [container addSubview:passwordViewButton_];
     } else {
       passwordStaticField_.reset([PasswordLabel(form.password_value) retain]);
     }
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index f33d2d9..46c466b 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -38,7 +38,7 @@
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/insecure_content_renderer.mojom.h"
+#include "chrome/common/content_settings_renderer.mojom.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/grit/generated_resources.h"
@@ -62,7 +62,7 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/origin_util.h"
 #include "ppapi/features/features.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -94,8 +94,8 @@
 }
 
 void SetAllowRunningInsecureContent(content::RenderFrameHost* frame) {
-  chrome::mojom::InsecureContentRendererPtr renderer;
-  frame->GetRemoteInterfaces()->GetInterface(&renderer);
+  chrome::mojom::ContentSettingsRendererAssociatedPtr renderer;
+  frame->GetRemoteAssociatedInterfaces()->GetInterface(&renderer);
   renderer->SetAllowRunningInsecureContent();
 }
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
index a6f7b12..1d6f14d 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -291,9 +291,13 @@
         interaction_stats.dismissal_count = stats->dismissal_count;
       }
     }
-    hide_eye_icon_ = delegate_->BubbleIsManualFallbackForSaving()
-                         ? pending_password_.form_has_autofilled_value
-                         : display_reason == USER_ACTION;
+    are_passwords_revealed_when_bubble_is_opened_ =
+        delegate_->ArePasswordsRevealedWhenBubbleIsOpened();
+    password_revealing_requires_reauth_ =
+        !are_passwords_revealed_when_bubble_is_opened_ &&
+        (delegate_->BubbleIsManualFallbackForSaving()
+             ? pending_password_.form_has_autofilled_value
+             : display_reason == USER_ACTION);
     enable_editing_ = delegate_->GetCredentialSource() !=
                       password_manager::metrics_util::CredentialSourceType::
                           kCredentialManagementAPI;
@@ -560,6 +564,11 @@
   interaction_keeper_->SetClockForTesting(std::move(clock));
 }
 
+bool ManagePasswordsBubbleModel::RevealPasswords() {
+  return !password_revealing_requires_reauth_ ||
+         (delegate_ && delegate_->AuthenticateUser());
+}
+
 void ManagePasswordsBubbleModel::UpdatePendingStateTitle() {
   title_brand_link_range_ = gfx::Range();
   PasswordTitleType type =
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.h b/chrome/browser/ui/passwords/manage_passwords_bubble_model.h
index 20f40ca..b3d7aca 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.h
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.h
@@ -116,11 +116,19 @@
     return title_brand_link_range_;
   }
 
-#if defined(UNIT_TEST)
-  void set_hide_eye_icon(bool hide) { hide_eye_icon_ = hide; }
-#endif
+  bool are_passwords_revealed_when_bubble_is_opened() const {
+    return are_passwords_revealed_when_bubble_is_opened_;
+  }
 
-  bool hide_eye_icon() const { return hide_eye_icon_; }
+#if defined(UNIT_TEST)
+  void allow_passwords_revealing() {
+    password_revealing_requires_reauth_ = false;
+  }
+
+  bool password_revealing_requires_reauth() const {
+    return password_revealing_requires_reauth_;
+  }
+#endif
 
   bool enable_editing() const { return enable_editing_; }
 
@@ -138,6 +146,13 @@
 
   void SetClockForTesting(std::unique_ptr<base::Clock> clock);
 
+  // Returns true if passwords revealing is not locked or re-authentication is
+  // not available on the given platform. Otherwise, the method schedules
+  // re-authentication and bubble reopen (the current bubble will be destroyed),
+  // and returns false immediately. New bubble will reveal the passwords if the
+  // re-authentication is successful.
+  bool RevealPasswords();
+
  private:
   enum UserBehaviorOnUpdateBubble {
     UPDATE_CLICKED,
@@ -172,8 +187,11 @@
   // A bridge to ManagePasswordsUIController instance.
   base::WeakPtr<PasswordsModelDelegate> delegate_;
 
-  // True iff the eye icon should be hidden for privacy reasons.
-  bool hide_eye_icon_;
+  // True iff password revealing should require re-auth for privacy reasons.
+  bool password_revealing_requires_reauth_;
+
+  // True iff bubble should pop up with revealed password value.
+  bool are_passwords_revealed_when_bubble_is_opened_;
 
   // True iff username/password editing should be enabled.
   bool enable_editing_;
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
index 68f90f1..22d26489 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -154,7 +154,7 @@
   void PretendAutoSigningIn();
   void PretendManagingPasswords();
 
-  void DestroyModel();
+  void DestroyModelAndVerifyControllerExpectations();
   void DestroyModelExpectReason(
       password_manager::metrics_util::UIDismissalReason dismissal_reason);
 
@@ -220,7 +220,8 @@
                  ManagePasswordsBubbleModel::USER_ACTION);
 }
 
-void ManagePasswordsBubbleModelTest::DestroyModel() {
+void ManagePasswordsBubbleModelTest::
+    DestroyModelAndVerifyControllerExpectations() {
   EXPECT_CALL(*controller(), OnBubbleHidden());
   model_.reset();
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
@@ -229,7 +230,7 @@
 void ManagePasswordsBubbleModelTest::DestroyModelExpectReason(
     password_manager::metrics_util::UIDismissalReason dismissal_reason) {
   base::HistogramTester histogram_tester;
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
   histogram_tester.ExpectUniqueSample(kUIDismissalReasonMetric,
                                       dismissal_reason, 1);
 }
@@ -330,7 +331,7 @@
   autofill::PasswordForm form;
   EXPECT_CALL(*controller(), UpdatePassword(form));
   model()->OnUpdateClicked(form);
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
 }
 
 TEST_F(ManagePasswordsBubbleModelTest, EditCredential) {
@@ -347,7 +348,7 @@
               SavePassword(kExpectedUsername, kExpectedPassword));
   EXPECT_CALL(*controller(), NeverSavePassword()).Times(0);
   model()->OnSaveClicked();
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
 }
 
 TEST_F(ManagePasswordsBubbleModelTest, OnBrandLinkClicked) {
@@ -368,7 +369,7 @@
   model()->OnSaveClicked();
 
   EXPECT_FALSE(model()->ReplaceToShowPromotionIfNeeded());
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
   histogram_tester.ExpectTotalCount(kSignInPromoDismissalReasonMetric, 0);
   histogram_tester.ExpectTotalCount(kSignInPromoCountTilSignInMetric, 0);
   histogram_tester.ExpectTotalCount(kSignInPromoCountTilNoThanksMetric, 0);
@@ -386,7 +387,7 @@
   EXPECT_TRUE(model()->ReplaceToShowPromotionIfNeeded());
   EXPECT_CALL(*controller(), NavigateToChromeSignIn());
   model()->OnSignInToChromeClicked();
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
   histogram_tester.ExpectUniqueSample(
       kUIDismissalReasonMetric,
       password_manager::metrics_util::CLICKED_SAVE, 1);
@@ -410,7 +411,7 @@
 
   EXPECT_TRUE(model()->ReplaceToShowPromotionIfNeeded());
   model()->OnSkipSignInClicked();
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
   histogram_tester.ExpectUniqueSample(
       kUIDismissalReasonMetric,
       password_manager::metrics_util::CLICKED_SAVE, 1);
@@ -433,7 +434,7 @@
   model()->OnSaveClicked();
 
   EXPECT_TRUE(model()->ReplaceToShowPromotionIfNeeded());
-  DestroyModel();
+  DestroyModelAndVerifyControllerExpectations();
   histogram_tester.ExpectUniqueSample(
       kUIDismissalReasonMetric,
       password_manager::metrics_util::CLICKED_SAVE, 1);
@@ -588,7 +589,7 @@
           } else {
             NOTREACHED();
           }
-          DestroyModel();
+          DestroyModelAndVerifyControllerExpectations();
         }
 
         ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
@@ -626,7 +627,7 @@
   }
 }
 
-TEST_F(ManagePasswordsBubbleModelTest, EyeIcon) {
+TEST_F(ManagePasswordsBubbleModelTest, EyeIcon_ReauthForPasswordsRevealing) {
   for (bool is_manual_fallback_for_saving : {false, true}) {
     for (bool form_has_autofilled_value : {false, true}) {
       for (ManagePasswordsBubbleModel::DisplayReason display_reason :
@@ -655,25 +656,62 @@
         if (display_reason == ManagePasswordsBubbleModel::AUTOMATIC)
           EXPECT_CALL(*GetStore(), AddSiteStatsImpl(_));
 
+        EXPECT_CALL(*controller(), ArePasswordsRevealedWhenBubbleIsOpened())
+            .WillOnce(Return(false));
         EXPECT_CALL(*controller(), BubbleIsManualFallbackForSaving())
             .WillOnce(Return(is_manual_fallback_for_saving));
+
         SetUpWithState(password_manager::ui::PENDING_PASSWORD_STATE,
                        display_reason);
-        EXPECT_EQ(
+        bool reauth_expected =
             is_manual_fallback_for_saving
                 ? form_has_autofilled_value
-                : display_reason == ManagePasswordsBubbleModel::USER_ACTION,
-            model()->hide_eye_icon());
+                : display_reason == ManagePasswordsBubbleModel::USER_ACTION;
+        EXPECT_EQ(reauth_expected,
+                  model()->password_revealing_requires_reauth());
 
-        DestroyModel();
+        if (reauth_expected) {
+          EXPECT_CALL(*controller(), AuthenticateUser())
+              .WillOnce(Return(false));
+          EXPECT_FALSE(model()->RevealPasswords());
+          ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
+
+          EXPECT_CALL(*controller(), AuthenticateUser()).WillOnce(Return(true));
+          EXPECT_TRUE(model()->RevealPasswords());
+        } else {
+          EXPECT_TRUE(model()->RevealPasswords());
+        }
+
+        DestroyModelAndVerifyControllerExpectations();
         // Flush async calls on password store.
         base::RunLoop().RunUntilIdle();
-        testing::Mock::VerifyAndClearExpectations(GetStore());
+        ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(GetStore()));
       }
     }
   }
 }
 
+TEST_F(ManagePasswordsBubbleModelTest, EyeIcon_BubbleReopenedAfterAuth) {
+  // Checks re-authentication is not needed if the bubble is opened right after
+  // successful authentication.
+  autofill::PasswordForm form = GetPendingPassword();
+  form.form_has_autofilled_value = true;
+  EXPECT_CALL(*controller(), GetPendingPassword()).WillOnce(ReturnRef(form));
+  password_manager::InteractionsStats stats = GetTestStats();
+  EXPECT_CALL(*controller(), GetCurrentInteractionStats())
+      .WillOnce(Return(&stats));
+
+  // After successful authentication this value is set to true.
+  EXPECT_CALL(*controller(), ArePasswordsRevealedWhenBubbleIsOpened())
+      .WillOnce(Return(true));
+
+  SetUpWithState(password_manager::ui::PENDING_PASSWORD_STATE,
+                 ManagePasswordsBubbleModel::USER_ACTION);
+
+  EXPECT_FALSE(model()->password_revealing_requires_reauth());
+  EXPECT_TRUE(model()->RevealPasswords());
+}
+
 TEST_F(ManagePasswordsBubbleModelTest, DisableEditing) {
   autofill::PasswordForm form = GetPendingPassword();
   EXPECT_CALL(*controller(), GetPendingPassword()).WillOnce(ReturnRef(form));
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 6c70cac..7f5034f 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -7,8 +7,10 @@
 #include <utility>
 
 #include "base/auto_reset.h"
+#include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/timer/timer.h"
+#include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
@@ -33,6 +35,12 @@
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "content/public/browser/navigation_handle.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/password_manager/password_manager_util_win.h"
+#elif defined(OS_MACOSX)
+#include "chrome/browser/password_manager/password_manager_util_mac.h"
+#endif
+
 using password_manager::PasswordFormManager;
 
 int ManagePasswordsUIController::save_fallback_timeout_in_seconds_ = 90;
@@ -62,6 +70,7 @@
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       bubble_status_(NOT_SHOWN),
+      are_passwords_revealed_when_next_bubble_is_opened_(false),
       weak_ptr_factory_(this) {
   passwords_data_.set_client(
       ChromePasswordManagerClient::FromWebContents(web_contents));
@@ -325,6 +334,7 @@
 }
 
 void ManagePasswordsUIController::OnBubbleShown() {
+  are_passwords_revealed_when_next_bubble_is_opened_ = false;
   bubble_status_ = SHOWN;
 }
 
@@ -486,6 +496,24 @@
   }
 }
 
+bool ManagePasswordsUIController::AuthenticateUser() {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &ManagePasswordsUIController::RequestAuthenticationAndReopenBubble,
+          weak_ptr_factory_.GetWeakPtr()));
+  return false;
+#else
+  return true;
+#endif
+}
+
+bool ManagePasswordsUIController::ArePasswordsRevealedWhenBubbleIsOpened()
+    const {
+  return are_passwords_revealed_when_next_bubble_is_opened_;
+}
+
 void ManagePasswordsUIController::SavePasswordInternal() {
   password_manager::PasswordStore* password_store =
       GetPasswordStore(web_contents());
@@ -599,3 +627,36 @@
   if (tab_dialogs)
     tab_dialogs->HideManagePasswordsBubble();
 }
+
+void ManagePasswordsUIController::RequestAuthenticationAndReopenBubble() {
+  base::WeakPtr<ManagePasswordsUIController> weak_ptr =
+      weak_ptr_factory_.GetWeakPtr();
+  bool auth_is_successful = ShowAuthenticationDialog();
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ManagePasswordsUIController::ReopenBubbleAfterAuth,
+                     weak_ptr, auth_is_successful));
+}
+
+void ManagePasswordsUIController::ReopenBubbleAfterAuth(
+    bool auth_is_successful) {
+  if (GetState() != password_manager::ui::PENDING_PASSWORD_STATE &&
+      GetState() != password_manager::ui::PENDING_PASSWORD_UPDATE_STATE)
+    return;
+  if (auth_is_successful)
+    are_passwords_revealed_when_next_bubble_is_opened_ = true;
+  bubble_status_ = SHOULD_POP_UP;
+  UpdateBubbleAndIconVisibility();
+}
+
+bool ManagePasswordsUIController::ShowAuthenticationDialog() {
+#if defined(OS_WIN)
+  return password_manager_util_win::AuthenticateUser(
+      web_contents()->GetNativeView());
+#elif defined(OS_MACOSX)
+  return password_manager_util_mac::AuthenticateUser();
+#else
+  NOTREACHED();
+  return true;
+#endif
+}
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index a50f4ea..0c3fbf66 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -128,6 +128,8 @@
   void NavigateToPasswordManagerSettingsPage() override;
   void NavigateToChromeSignIn() override;
   void OnDialogHidden() override;
+  bool AuthenticateUser() override;
+  bool ArePasswordsRevealedWhenBubbleIsOpened() const override;
 
  protected:
   explicit ManagePasswordsUIController(
@@ -192,6 +194,17 @@
   // content::WebContentsObserver:
   void WebContentsDestroyed() override;
 
+  // Requests authentication and reopens the bubble if the controller still
+  // exists and is in a pending state.
+  void RequestAuthenticationAndReopenBubble();
+
+  // Re-opens the bubble. The password in the reopened bubble will be revealed
+  // if the authentication was successful.
+  void ReopenBubbleAfterAuth(bool auth_is_successful);
+
+  // Shows an authentication dialog and returns true if auth is successful.
+  virtual bool ShowAuthenticationDialog();
+
   // Timeout in seconds for the manual fallback for saving.
   static int save_fallback_timeout_in_seconds_;
 
@@ -209,6 +222,9 @@
   // fallback).
   base::OneShotTimer save_fallback_timer_;
 
+  // True iff bubble should pop up with revealed password value.
+  bool are_passwords_revealed_when_next_bubble_is_opened_;
+
   // The bubbles of different types can pop up unpredictably superseding each
   // other. However, closing the bubble may affect the state of
   // ManagePasswordsUIController internally. This is undesired if
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
index a9d24fe..e8d53dc 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
@@ -95,6 +95,9 @@
   ~TestManagePasswordsUIController() override;
 
   bool opened_bubble() const { return opened_bubble_; }
+  bool are_passwords_revealed_in_opened_bubble() const {
+    return are_passwords_revealed_in_opened_bubble_;
+  }
 
   MOCK_METHOD1(CreateAccountChooser,
                AccountChooserPrompt*(PasswordDialogController*));
@@ -110,8 +113,10 @@
   void UpdatePasswordInternal(
       const autofill::PasswordForm& password_form) override {}
   void NeverSavePasswordInternal() override;
+  bool ShowAuthenticationDialog() override { return true; }
 
   bool opened_bubble_;
+  bool are_passwords_revealed_in_opened_bubble_;
 };
 
 TestManagePasswordsUIController::TestManagePasswordsUIController(
@@ -133,8 +138,11 @@
   OnUpdateBubbleAndIconVisibility();
   TestManagePasswordsIconView view;
   UpdateIconAndBubbleState(&view);
-  if (opened_bubble_)
+  if (opened_bubble_) {
+    are_passwords_revealed_in_opened_bubble_ =
+        ArePasswordsRevealedWhenBubbleIsOpened();
     OnBubbleShown();
+  }
 }
 
 void TestManagePasswordsUIController::NeverSavePasswordInternal() {
@@ -1237,3 +1245,35 @@
   EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
   controller()->OnBubbleHidden();
 }
+
+TEST_F(ManagePasswordsUIControllerTest, AuthenticateUserToRevealPasswords) {
+  std::unique_ptr<password_manager::PasswordFormManager> test_form_manager(
+      CreateFormManager());
+  test_form_manager->ProvisionallySave(
+      test_local_form(),
+      password_manager::PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
+  controller()->OnPasswordSubmitted(std::move(test_form_manager));
+  EXPECT_EQ(password_manager::ui::PENDING_PASSWORD_STATE,
+            controller()->GetState());
+  EXPECT_TRUE(controller()->opened_bubble());
+  ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
+
+  // Simulate that re-auth is need to reveal passwords in the bubble.
+  bool success = controller()->AuthenticateUser();
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  EXPECT_FALSE(success);
+  // Let the task posted in AuthenticateUser re-open the bubble.
+  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
+  content::RunAllPendingInMessageLoop();
+  EXPECT_TRUE(controller()->opened_bubble());
+  EXPECT_TRUE(controller()->are_passwords_revealed_in_opened_bubble());
+  // Since the bubble is opened, this property is already cleared.
+  EXPECT_FALSE(controller()->ArePasswordsRevealedWhenBubbleIsOpened());
+
+  // Close the bubble.
+  controller()->OnBubbleHidden();
+#else
+  EXPECT_TRUE(success);
+#endif
+}
diff --git a/chrome/browser/ui/passwords/passwords_model_delegate.h b/chrome/browser/ui/passwords/passwords_model_delegate.h
index 54a156f4..54563cc 100644
--- a/chrome/browser/ui/passwords/passwords_model_delegate.h
+++ b/chrome/browser/ui/passwords/passwords_model_delegate.h
@@ -113,6 +113,18 @@
   // Called from the dialog controller when the dialog is hidden.
   virtual void OnDialogHidden() = 0;
 
+  // Called from the model when re-auth is needed to show passwords. Returns
+  // true immediately if user authentication is not available for the given
+  // platform. Otherwise, the method schedules a task to show an authentication
+  // dialog and reopens the bubble afterwards, then the method returns false.
+  // The password in the reopened bubble will be revealed if the authentication
+  // was successful.
+  virtual bool AuthenticateUser() = 0;
+
+  // Returns true if the password values should be revealed when the bubble is
+  // opened.
+  virtual bool ArePasswordsRevealedWhenBubbleIsOpened() const = 0;
+
  protected:
   virtual ~PasswordsModelDelegate() = default;
 };
diff --git a/chrome/browser/ui/passwords/passwords_model_delegate_mock.h b/chrome/browser/ui/passwords/passwords_model_delegate_mock.h
index e8045a61..badf78f 100644
--- a/chrome/browser/ui/passwords/passwords_model_delegate_mock.h
+++ b/chrome/browser/ui/passwords/passwords_model_delegate_mock.h
@@ -48,6 +48,8 @@
   MOCK_METHOD0(NavigateToPasswordManagerSettingsPage, void());
   MOCK_METHOD0(NavigateToChromeSignIn, void());
   MOCK_METHOD0(OnDialogHidden, void());
+  MOCK_METHOD0(AuthenticateUser, bool());
+  MOCK_CONST_METHOD0(ArePasswordsRevealedWhenBubbleIsOpened, bool());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PasswordsModelDelegateMock);
diff --git a/chrome/browser/ui/tabs/tab_activity_watcher_unittest.cc b/chrome/browser/ui/tabs/tab_activity_watcher_unittest.cc
index f21684d..240edfc 100644
--- a/chrome/browser/ui/tabs/tab_activity_watcher_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_activity_watcher_unittest.cc
@@ -15,14 +15,12 @@
 #include "chrome/browser/ui/tabs/tab_metrics_event.pb.h"
 #include "chrome/browser/ui/tabs/tab_metrics_logger_impl.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/browser/ui/tabs/tab_ukm_test_helper.h"
 #include "chrome/test/base/test_browser_window.h"
 #include "chrome/test/base/testing_profile.h"
-#include "components/ukm/test_ukm_recorder.h"
 #include "components/ukm/ukm_source.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/test/web_contents_tester.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/interfaces/ukm_interface.mojom.h"
@@ -64,22 +62,6 @@
     {TabManager_TabMetrics::kWasRecentlyAudibleName, 0},
 });
 
-// Helper class to respond to WebContents lifecycle events we can't
-// trigger/simulate.
-class TestWebContentsObserver : public content::WebContentsObserver {
- public:
-  explicit TestWebContentsObserver(content::WebContents* web_contents)
-      : content::WebContentsObserver(web_contents) {}
-
-  // content::WebContentsObserver:
-  void WebContentsDestroyed() override {
-    // Verify that a WebContents being destroyed does not trigger logging.
-    web_contents()->WasHidden();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
-};
 
 blink::WebMouseEvent CreateMouseEvent(WebInputEvent::Type event_type) {
   return blink::WebMouseEvent(event_type, WebInputEvent::kNoModifiers,
@@ -90,9 +72,7 @@
 
 // Tests UKM entries generated by TabMetricsLogger at the request of
 // TabActivityWatcher.
-// Inherits from ChromeRenderViewHostTestHarness to use TestWebContents and
-// Profile.
-class TabActivityWatcherTest : public ChromeRenderViewHostTestHarness {
+class TabActivityWatcherTest : public TabActivityTestBase {
  protected:
   TabActivityWatcherTest() {
     TabActivityWatcher::GetInstance()->DisableLogTimeoutForTesting();
@@ -100,100 +80,34 @@
   }
 
   void TearDown() override {
-    EXPECT_FALSE(WasNewEntryRecorded());
+    EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
     TabActivityWatcher::GetInstance()->ResetForTesting();
-    ChromeRenderViewHostTestHarness::TearDown();
+    TabActivityTestBase::TearDown();
   }
 
-  // Creates a new WebContents suitable for testing, adds it to the tab strip
-  // and commits a navigation to |initial_url|. The WebContents is owned by the
-  // TabStripModel, so its tab must be closed later, e.g. via CloseAllTabs().
-  content::WebContents* AddWebContentsAndNavigate(
-      TabStripModel* tab_strip_model,
-      const GURL& initial_url) {
-    content::WebContents::CreateParams params(profile(), nullptr);
-    // Create as a background tab if there are other tabs in the tab strip.
-    params.initially_hidden = tab_strip_model->count() > 0;
-    content::WebContents* test_contents =
-        WebContentsTester::CreateTestWebContents(params);
-
-    // Create the TestWebContentsObserver to observe |test_contents|. When the
-    // WebContents is destroyed, the observer will be reset automatically.
-    observers_.push_back(
-        std::make_unique<TestWebContentsObserver>(test_contents));
-
-    tab_strip_model->AppendWebContents(test_contents, false);
-    WebContentsTester::For(test_contents)->NavigateAndCommit(initial_url);
-    return test_contents;
-  }
-
-  // Sets |new_index| as the active tab in its tab strip, hiding the previously
-  // active tab.
-  void SwitchToTabAt(TabStripModel* tab_strip_model, int new_index) {
-    int active_index = tab_strip_model->active_index();
-    EXPECT_NE(new_index, active_index);
-
-    content::WebContents* active_contents =
-        tab_strip_model->GetWebContentsAt(active_index);
-    ASSERT_TRUE(active_contents);
-    content::WebContents* new_contents =
-        tab_strip_model->GetWebContentsAt(new_index);
-    ASSERT_TRUE(new_contents);
-
-    // Activate the tab. Normally this would hide the active tab's aura::Window,
-    // which is what actually triggers TabActivityWatcher to log the change. For
-    // a TestWebContents, we must manually call WasHidden(), and do the reverse
-    // for the newly activated tab.
-    tab_strip_model->ActivateTabAt(new_index, /*user_gesture=*/true);
-    active_contents->WasHidden();
-    new_contents->WasShown();
-  }
-
-  // Expects that exactly one new TabManager.TabMetrics entry has been recorded,
-  // and that it matches the values and the given URL.
   void ExpectNewEntry(const GURL& source_url,
                       const UkmMetricMap& expected_metrics) {
-    num_entries_++;  // There should only be 1 more entry than before.
-    std::vector<const ukm::mojom::UkmEntry*> entries =
-        ukm_recorder()->GetEntriesByName(kEntryName);
-    ASSERT_EQ(num_entries_, entries.size());
+    ukm_entry_checker_.ExpectNewEntry(kEntryName, source_url, expected_metrics);
 
-    // Verify the entry is associated with the correct URL.
-    const ukm::mojom::UkmEntry* entry = entries.back();
-    ukm_recorder()->ExpectEntrySourceHasUrl(entry, source_url);
-
-    // Verify the entry's SequenceId, which should increment for each event.
+    const size_t num_entries = ukm_entry_checker_.NumEntries(kEntryName);
+    const ukm::mojom::UkmEntry* last_entry =
+        ukm_entry_checker_.LastUkmEntry(kEntryName);
     ukm::TestUkmRecorder::ExpectEntryMetric(
-        entry, TabManager_TabMetrics::kSequenceIdName, num_entries_);
-
-    // Each expected metric should match a named value in the UKM entry.
-    for (const std::pair<const char*, uint64_t>& pair : expected_metrics)
-      ukm::TestUkmRecorder::ExpectEntryMetric(entry, pair.first, pair.second);
+        last_entry, TabManager_TabMetrics::kSequenceIdName, num_entries);
   }
 
-  bool WasNewEntryRecorded() {
-    return ukm_recorder()->GetEntriesByName(kEntryName).size() > num_entries_;
-  }
-
-  ukm::TestUkmRecorder* ukm_recorder() { return &ukm_recorder_; }
+ protected:
+  UkmEntryChecker ukm_entry_checker_;
 
  private:
-  ukm::TestAutoSetUkmRecorder ukm_recorder_;
   TabMetricsLoggerImpl tab_metrics_logger_;
-
-  // Tracks the expected number of entries to ensure we don't log duplicate or
-  // incorrect entries.
-  size_t num_entries_ = 0;
-
-  // Owns the observers we've created.
-  std::vector<std::unique_ptr<TestWebContentsObserver>> observers_;
-
   DISALLOW_COPY_AND_ASSIGN(TabActivityWatcherTest);
 };
 
 TEST_F(TabActivityWatcherTest, Basic) {
   Browser::CreateParams params(profile(), true);
-  auto browser = CreateBrowserWithTestWindowForParams(&params);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* fg_contents =
@@ -202,7 +116,7 @@
   WebContentsTester::For(fg_contents)->TestSetIsLoading(false);
 
   // Adding, loading and activating a foreground tab doesn't trigger logging.
-  EXPECT_FALSE(WasNewEntryRecorded());
+  EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
 
   // The second web contents is added as a background tab, so it logs an entry
   // when it stops loading.
@@ -233,7 +147,8 @@
 // Tests when tab events like pinning and navigating trigger logging.
 TEST_F(TabActivityWatcherTest, TabEvents) {
   Browser::CreateParams params(profile(), true);
-  auto browser = CreateBrowserWithTestWindowForParams(&params);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents_1 =
@@ -243,7 +158,7 @@
   // Opening the background tab triggers logging once the page finishes loading.
   content::WebContents* test_contents_2 =
       AddWebContentsAndNavigate(tab_strip_model, GURL(kTestUrls[1]));
-  EXPECT_FALSE(WasNewEntryRecorded());
+  EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
   WebContentsTester::For(test_contents_2)->TestSetIsLoading(false);
   {
     SCOPED_TRACE("");
@@ -253,11 +168,11 @@
   // Navigating the active tab doesn't trigger logging.
   WebContentsTester::For(test_contents_1)->NavigateAndCommit(kTestUrls[2]);
   WebContentsTester::For(test_contents_1)->TestSetIsLoading(false);
-  EXPECT_FALSE(WasNewEntryRecorded());
+  EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
 
   // Pinning the active tab doesn't trigger logging.
   tab_strip_model->SetTabPinned(0, true);
-  EXPECT_FALSE(WasNewEntryRecorded());
+  EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
 
   // Pinning and unpinning the background tab triggers logging.
   tab_strip_model->SetTabPinned(1, true);
@@ -277,7 +192,7 @@
   // Navigating the background tab triggers logging once the page finishes
   // loading.
   WebContentsTester::For(test_contents_2)->NavigateAndCommit(kTestUrls[0]);
-  EXPECT_FALSE(WasNewEntryRecorded());
+  EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
   WebContentsTester::For(test_contents_2)->TestSetIsLoading(false);
   {
     SCOPED_TRACE("");
@@ -290,7 +205,8 @@
 // Tests setting and changing tab metrics.
 TEST_F(TabActivityWatcherTest, TabMetrics) {
   Browser::CreateParams params(profile(), true);
-  auto browser = CreateBrowserWithTestWindowForParams(&params);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents_1 =
@@ -359,7 +275,8 @@
 // events.
 TEST_F(TabActivityWatcherTest, InputEvents) {
   Browser::CreateParams params(profile(), true);
-  auto browser = CreateBrowserWithTestWindowForParams(&params);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents_1 =
@@ -429,7 +346,8 @@
 // WebContents is still the active tab).
 TEST_F(TabActivityWatcherTest, HideWindow) {
   Browser::CreateParams params(profile(), true);
-  auto browser = CreateBrowserWithTestWindowForParams(&params);
+  std::unique_ptr<Browser> browser =
+      CreateBrowserWithTestWindowForParams(&params);
 
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   content::WebContents* test_contents =
@@ -445,7 +363,7 @@
 
   // Showing the window does not.
   test_contents->WasShown();
-  EXPECT_FALSE(WasNewEntryRecorded());
+  EXPECT_EQ(0, ukm_entry_checker_.NumNewEntriesRecorded(kEntryName));
 
   tab_strip_model->CloseAllTabs();
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 5b5ceb2..7cb8647 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -4,15 +4,169 @@
 
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
+#include <algorithm>
+#include <set>
+#include <string>
+#include <utility>
 
-TabStripModel::TabStripModel(TabStripModelDelegate* delegate)
-    : delegate_(delegate) {
-  DCHECK(delegate_);
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "build/build_config.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
+#include "chrome/browser/ui/tabs/tab_utils.h"
+#include "chrome/browser/ui/web_contents_sizer.h"
+#include "chrome/common/url_constants.h"
+#include "components/feature_engagement/features.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+#include "chrome/browser/feature_engagement/new_tab/new_tab_tracker.h"
+#include "chrome/browser/feature_engagement/new_tab/new_tab_tracker_factory.h"
+#endif
+
+using base::UserMetricsAction;
+using content::WebContents;
+
+namespace {
+
+// Returns true if the specified transition is one of the types that cause the
+// opener relationships for the tab in which the transition occurred to be
+// forgotten. This is generally any navigation that isn't a link click (i.e.
+// any navigation that can be considered to be the start of a new task distinct
+// from what had previously occurred in that tab).
+bool ShouldForgetOpenersForTransition(ui::PageTransition transition) {
+  return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) ||
+         ui::PageTransitionCoreTypeIs(transition,
+                                      ui::PAGE_TRANSITION_AUTO_BOOKMARK) ||
+         ui::PageTransitionCoreTypeIs(transition,
+                                      ui::PAGE_TRANSITION_GENERATED) ||
+         ui::PageTransitionCoreTypeIs(transition,
+                                      ui::PAGE_TRANSITION_KEYWORD) ||
+         ui::PageTransitionCoreTypeIs(transition,
+                                      ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
 }
 
-TabStripModel::~TabStripModel() = default;
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// WebContentsData
+
+// An object to hold a reference to a WebContents that is in a tabstrip, as
+// well as other various properties it has.
+class TabStripModel::WebContentsData : public content::WebContentsObserver {
+ public:
+  WebContentsData(TabStripModel* tab_strip_model, WebContents* a_contents);
+
+  // Changes the WebContents that this WebContentsData tracks.
+  void SetWebContents(WebContents* contents);
+  WebContents* web_contents() { return contents_; }
+
+  // Create a relationship between this WebContentsData and other
+  // WebContentses. Used to identify which WebContents to select next after
+  // one is closed.
+  WebContents* group() const { return group_; }
+  void set_group(WebContents* value) { group_ = value; }
+  WebContents* opener() const { return opener_; }
+  void set_opener(WebContents* value) { opener_ = value; }
+
+  // Alters the properties of the WebContents.
+  bool reset_group_on_select() const { return reset_group_on_select_; }
+  void set_reset_group_on_select(bool value) { reset_group_on_select_ = value; }
+  bool pinned() const { return pinned_; }
+  void set_pinned(bool value) { pinned_ = value; }
+  bool blocked() const { return blocked_; }
+  void set_blocked(bool value) { blocked_ = value; }
+
+ private:
+  // Make sure that if someone deletes this WebContents out from under us, it
+  // is properly removed from the tab strip.
+  void WebContentsDestroyed() override;
+
+  // The WebContents being tracked by this WebContentsData. The
+  // WebContentsObserver does keep a reference, but when the WebContents is
+  // deleted, the WebContentsObserver reference is NULLed and thus inaccessible.
+  WebContents* contents_;
+
+  // The TabStripModel containing this WebContents.
+  TabStripModel* tab_strip_model_;
+
+  // The group is used to model a set of tabs spawned from a single parent
+  // tab. This value is preserved for a given tab as long as the tab remains
+  // navigated to the link it was initially opened at or some navigation from
+  // that page (i.e. if the user types or visits a bookmark or some other
+  // navigation within that tab, the group relationship is lost). This
+  // property can safely be used to implement features that depend on a
+  // logical group of related tabs.
+  WebContents* group_ = nullptr;
+
+  // The owner models the same relationship as group, except it is more
+  // easily discarded, e.g. when the user switches to a tab not part of the
+  // same group. This property is used to determine what tab to select next
+  // when one is closed.
+  WebContents* opener_ = nullptr;
+
+  // True if our group should be reset the moment selection moves away from
+  // this tab. This is the case for tabs opened in the foreground at the end
+  // of the TabStrip while viewing another Tab. If these tabs are closed
+  // before selection moves elsewhere, their opener is selected. But if
+  // selection shifts to _any_ tab (including their opener), the group
+  // relationship is reset to avoid confusing close sequencing.
+  bool reset_group_on_select_ = false;
+
+  // Is the tab pinned?
+  bool pinned_ = false;
+
+  // Is the tab interaction blocked by a modal dialog?
+  bool blocked_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsData);
+};
+
+TabStripModel::WebContentsData::WebContentsData(TabStripModel* tab_strip_model,
+                                                WebContents* contents)
+    : content::WebContentsObserver(contents),
+      contents_(contents),
+      tab_strip_model_(tab_strip_model) {}
+
+void TabStripModel::WebContentsData::SetWebContents(WebContents* contents) {
+  contents_ = contents;
+  Observe(contents);
+}
+
+void TabStripModel::WebContentsData::WebContentsDestroyed() {
+  DCHECK_EQ(contents_, web_contents());
+
+  // Note that we only detach the contents here, not close it - it's
+  // already been closed. We just want to undo our bookkeeping.
+  int index = tab_strip_model_->GetIndexOfWebContents(web_contents());
+  DCHECK_NE(TabStripModel::kNoTab, index);
+  tab_strip_model_->DetachWebContentsAt(index);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TabStripModel, public:
+
+TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile)
+    : delegate_(delegate), profile_(profile), weak_factory_(this) {
+  DCHECK(delegate_);
+  order_controller_.reset(new TabStripModelOrderController(this));
+}
+
+TabStripModel::~TabStripModel() {
+  contents_data_.clear();
+  order_controller_.reset();
+}
 
 void TabStripModel::AddObserver(TabStripModelObserver* observer) {
   observers_.AddObserver(observer);
@@ -22,6 +176,795 @@
   observers_.RemoveObserver(observer);
 }
 
+bool TabStripModel::ContainsIndex(int index) const {
+  return index >= 0 && index < count();
+}
+
+void TabStripModel::AppendWebContents(WebContents* contents, bool foreground) {
+  InsertWebContentsAt(count(), contents,
+                      foreground ? (ADD_INHERIT_GROUP | ADD_ACTIVE) : ADD_NONE);
+}
+
+void TabStripModel::InsertWebContentsAt(int index,
+                                        WebContents* contents,
+                                        int add_types) {
+  delegate()->WillAddWebContents(contents);
+
+  bool active = (add_types & ADD_ACTIVE) != 0;
+  bool pin = (add_types & ADD_PINNED) != 0;
+  index = ConstrainInsertionIndex(index, pin);
+
+  // In tab dragging situations, if the last tab in the window was detached
+  // then the user aborted the drag, we will have the |closing_all_| member
+  // set (see DetachWebContentsAt) which will mess with our mojo here. We need
+  // to clear this bit.
+  closing_all_ = false;
+
+  // Have to get the active contents before we monkey with the contents
+  // otherwise we run into problems when we try to change the active contents
+  // since the old contents and the new contents will be the same...
+  WebContents* active_contents = GetActiveWebContents();
+  std::unique_ptr<WebContentsData> data =
+      base::MakeUnique<WebContentsData>(this, contents);
+  data->set_pinned(pin);
+  if ((add_types & ADD_INHERIT_GROUP) && active_contents) {
+    if (active) {
+      // Forget any existing relationships, we don't want to make things too
+      // confusing by having multiple groups active at the same time.
+      ForgetAllOpeners();
+    }
+    // Anything opened by a link we deem to have an opener.
+    data->set_group(active_contents);
+    data->set_opener(active_contents);
+  } else if ((add_types & ADD_INHERIT_OPENER) && active_contents) {
+    if (active) {
+      // Forget any existing relationships, we don't want to make things too
+      // confusing by having multiple groups active at the same time.
+      ForgetAllOpeners();
+    }
+    data->set_opener(active_contents);
+  }
+
+  // TODO(gbillock): Ask the modal dialog manager whether the WebContents should
+  // be blocked, or just let the modal dialog manager make the blocking call
+  // directly and not use this at all.
+  const web_modal::WebContentsModalDialogManager* manager =
+      web_modal::WebContentsModalDialogManager::FromWebContents(contents);
+  if (manager)
+    data->set_blocked(manager->IsDialogActive());
+
+  contents_data_.insert(contents_data_.begin() + index, std::move(data));
+
+  selection_model_.IncrementFrom(index);
+
+  for (auto& observer : observers_)
+    observer.TabInsertedAt(this, contents, index, active);
+
+  if (active) {
+    ui::ListSelectionModel new_model = selection_model_;
+    new_model.SetSelectedIndex(index);
+    SetSelection(std::move(new_model), Notify::kDefault);
+  }
+}
+
+WebContents* TabStripModel::ReplaceWebContentsAt(int index,
+                                                 WebContents* new_contents) {
+  delegate()->WillAddWebContents(new_contents);
+
+  DCHECK(ContainsIndex(index));
+  WebContents* old_contents = GetWebContentsAtImpl(index);
+
+  FixOpenersAndGroupsReferencing(index);
+
+  contents_data_[index]->SetWebContents(new_contents);
+
+  for (auto& observer : observers_)
+    observer.TabReplacedAt(this, old_contents, new_contents, index);
+
+  // When the active WebContents is replaced send out a selection notification
+  // too. We do this as nearly all observers need to treat a replacement of the
+  // selected contents as the selection changing.
+  if (active_index() == index) {
+    for (auto& observer : observers_) {
+      observer.ActiveTabChanged(old_contents, new_contents, active_index(),
+                                TabStripModelObserver::CHANGE_REASON_REPLACED);
+    }
+  }
+  return old_contents;
+}
+
+WebContents* TabStripModel::DetachWebContentsAt(int index) {
+  CHECK(!in_notify_);
+  if (contents_data_.empty())
+    return nullptr;
+  DCHECK(ContainsIndex(index));
+
+  FixOpenersAndGroupsReferencing(index);
+
+  WebContents* removed_contents = GetWebContentsAtImpl(index);
+  bool was_selected = IsTabSelected(index);
+  int next_selected_index = order_controller_->DetermineNewSelectedIndex(index);
+  contents_data_.erase(contents_data_.begin() + index);
+  if (empty())
+    closing_all_ = true;
+  for (auto& observer : observers_)
+    observer.TabDetachedAt(removed_contents, index);
+  if (empty()) {
+    selection_model_.Clear();
+    // TabDetachedAt() might unregister observers, so send |TabStripEmpty()| in
+    // a second pass.
+    for (auto& observer : observers_)
+      observer.TabStripEmpty();
+  } else {
+    int old_active = active_index();
+    selection_model_.DecrementFrom(index);
+    ui::ListSelectionModel old_model;
+    old_model = selection_model_;
+    if (index == old_active) {
+      NotifyIfTabDeactivated(removed_contents);
+      if (!selection_model_.empty()) {
+        // The active tab was removed, but there is still something selected.
+        // Move the active and anchor to the first selected index.
+        selection_model_.set_active(selection_model_.selected_indices()[0]);
+        selection_model_.set_anchor(selection_model_.active());
+      } else {
+        // The active tab was removed and nothing is selected. Reset the
+        // selection and send out notification.
+        selection_model_.SetSelectedIndex(next_selected_index);
+      }
+      NotifyIfActiveTabChanged(removed_contents, Notify::kDefault);
+    }
+
+    // Sending notification in case the detached tab was selected. Using
+    // NotifyIfActiveOrSelectionChanged() here would not guarantee that a
+    // notification is sent even though the tab selection has changed because
+    // |old_model| is stored after calling DecrementFrom().
+    if (was_selected) {
+      for (auto& observer : observers_)
+        observer.TabSelectionChanged(this, old_model);
+    }
+  }
+  return removed_contents;
+}
+
+void TabStripModel::ActivateTabAt(int index, bool user_gesture) {
+  DCHECK(ContainsIndex(index));
+  ui::ListSelectionModel new_model = selection_model_;
+  new_model.SetSelectedIndex(index);
+  SetSelection(std::move(new_model),
+               user_gesture ? Notify::kUserGesture : Notify::kDefault);
+}
+
+void TabStripModel::AddTabAtToSelection(int index) {
+  DCHECK(ContainsIndex(index));
+  ui::ListSelectionModel new_model = selection_model_;
+  new_model.AddIndexToSelection(index);
+  SetSelection(std::move(new_model), Notify::kDefault);
+}
+
+void TabStripModel::MoveWebContentsAt(int index,
+                                      int to_position,
+                                      bool select_after_move) {
+  DCHECK(ContainsIndex(index));
+
+  // Ensure pinned and non-pinned tabs do not mix.
+  const int first_non_pinned_tab = IndexOfFirstNonPinnedTab();
+  to_position = IsTabPinned(index)
+                    ? std::min(first_non_pinned_tab - 1, to_position)
+                    : std::max(first_non_pinned_tab, to_position);
+  if (index == to_position)
+    return;
+
+  MoveWebContentsAtImpl(index, to_position, select_after_move);
+}
+
+void TabStripModel::MoveSelectedTabsTo(int index) {
+  int total_pinned_count = IndexOfFirstNonPinnedTab();
+  int selected_pinned_count = 0;
+  int selected_count =
+      static_cast<int>(selection_model_.selected_indices().size());
+  for (int i = 0; i < selected_count &&
+                  IsTabPinned(selection_model_.selected_indices()[i]);
+       ++i) {
+    selected_pinned_count++;
+  }
+
+  // To maintain that all pinned tabs occur before non-pinned tabs we move them
+  // first.
+  if (selected_pinned_count > 0) {
+    MoveSelectedTabsToImpl(
+        std::min(total_pinned_count - selected_pinned_count, index), 0u,
+        selected_pinned_count);
+    if (index > total_pinned_count - selected_pinned_count) {
+      // We're being told to drag pinned tabs to an invalid location. Adjust the
+      // index such that non-pinned tabs end up at a location as though we could
+      // move the pinned tabs to index. See description in header for more
+      // details.
+      index += selected_pinned_count;
+    }
+  }
+  if (selected_pinned_count == selected_count)
+    return;
+
+  // Then move the non-pinned tabs.
+  MoveSelectedTabsToImpl(std::max(index, total_pinned_count),
+                         selected_pinned_count,
+                         selected_count - selected_pinned_count);
+}
+
+WebContents* TabStripModel::GetActiveWebContents() const {
+  return GetWebContentsAt(active_index());
+}
+
+WebContents* TabStripModel::GetWebContentsAt(int index) const {
+  if (ContainsIndex(index))
+    return GetWebContentsAtImpl(index);
+  return nullptr;
+}
+
+int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const {
+  for (size_t i = 0; i < contents_data_.size(); ++i) {
+    if (contents_data_[i]->web_contents() == contents)
+      return i;
+  }
+  return kNoTab;
+}
+
+void TabStripModel::UpdateWebContentsStateAt(int index,
+                                             TabChangeType change_type) {
+  DCHECK(ContainsIndex(index));
+
+  for (auto& observer : observers_)
+    observer.TabChangedAt(GetWebContentsAtImpl(index), index, change_type);
+}
+
+void TabStripModel::SetTabNeedsAttentionAt(int index, bool attention) {
+  DCHECK(ContainsIndex(index));
+
+  for (auto& observer : observers_)
+    observer.SetTabNeedsAttentionAt(index, attention);
+}
+
+void TabStripModel::CloseAllTabs() {
+  // Set state so that observers can adjust their behavior to suit this
+  // specific condition when CloseWebContentsAt causes a flurry of
+  // Close/Detach/Select notifications to be sent.
+  closing_all_ = true;
+  std::vector<content::WebContents*> closing_tabs;
+  closing_tabs.reserve(count());
+  for (int i = count() - 1; i >= 0; --i)
+    closing_tabs.push_back(GetWebContentsAt(i));
+  InternalCloseTabs(closing_tabs, CLOSE_CREATE_HISTORICAL_TAB);
+}
+
+bool TabStripModel::CloseWebContentsAt(int index, uint32_t close_types) {
+  DCHECK(ContainsIndex(index));
+  WebContents* contents = GetWebContentsAt(index);
+  return InternalCloseTabs(base::span<WebContents* const>(&contents, 1),
+                           close_types);
+}
+
+bool TabStripModel::TabsAreLoading() const {
+  for (const auto& data : contents_data_) {
+    if (data->web_contents()->IsLoading())
+      return true;
+  }
+
+  return false;
+}
+
+WebContents* TabStripModel::GetOpenerOfWebContentsAt(int index) {
+  DCHECK(ContainsIndex(index));
+  return contents_data_[index]->opener();
+}
+
+void TabStripModel::SetOpenerOfWebContentsAt(int index, WebContents* opener) {
+  DCHECK(ContainsIndex(index));
+  // The TabStripModel only maintains the references to openers that it itself
+  // owns; trying to set an opener to an external WebContents can result in
+  // the opener being used after its freed. See crbug.com/698681.
+  DCHECK(!opener || GetIndexOfWebContents(opener) != kNoTab)
+      << "Cannot set opener to a web contents not owned by this tab strip.";
+  contents_data_[index]->set_opener(opener);
+}
+
+int TabStripModel::GetIndexOfLastWebContentsOpenedBy(const WebContents* opener,
+                                                     int start_index) const {
+  DCHECK(opener);
+  DCHECK(ContainsIndex(start_index));
+
+  std::set<const WebContents*> opener_and_descendants;
+  opener_and_descendants.insert(opener);
+  int last_index = kNoTab;
+
+  for (int i = start_index + 1; i < count(); ++i) {
+    // Test opened by transitively, i.e. include tabs opened by tabs opened by
+    // opener, etc. Stop when we find the first non-descendant.
+    if (!opener_and_descendants.count(contents_data_[i]->opener())) {
+      // Skip over pinned tabs as new tabs are added after pinned tabs.
+      if (contents_data_[i]->pinned())
+        continue;
+      break;
+    }
+    opener_and_descendants.insert(contents_data_[i]->web_contents());
+    last_index = i;
+  }
+  return last_index;
+}
+
+void TabStripModel::TabNavigating(WebContents* contents,
+                                  ui::PageTransition transition) {
+  if (ShouldForgetOpenersForTransition(transition)) {
+    // Don't forget the openers if this tab is a New Tab page opened at the
+    // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one
+    // navigation of one of these transition types before resetting the
+    // opener relationships (this allows for the use case of opening a new
+    // tab to do a quick look-up of something while viewing a tab earlier in
+    // the strip). We can make this heuristic more permissive if need be.
+    if (!IsNewTabAtEndOfTabStrip(contents)) {
+      // If the user navigates the current tab to another page in any way
+      // other than by clicking a link, we want to pro-actively forget all
+      // TabStrip opener relationships since we assume they're beginning a
+      // different task by reusing the current tab.
+      ForgetAllOpeners();
+      // In this specific case we also want to reset the group relationship,
+      // since it is now technically invalid.
+      ForgetGroup(contents);
+    }
+  }
+}
+
+void TabStripModel::SetTabBlocked(int index, bool blocked) {
+  DCHECK(ContainsIndex(index));
+  if (contents_data_[index]->blocked() == blocked)
+    return;
+  contents_data_[index]->set_blocked(blocked);
+  for (auto& observer : observers_)
+    observer.TabBlockedStateChanged(contents_data_[index]->web_contents(),
+                                    index);
+}
+
+void TabStripModel::SetTabPinned(int index, bool pinned) {
+  DCHECK(ContainsIndex(index));
+  if (contents_data_[index]->pinned() == pinned)
+    return;
+
+  // The tab's position may have to change as the pinned tab state is changing.
+  int non_pinned_tab_index = IndexOfFirstNonPinnedTab();
+  contents_data_[index]->set_pinned(pinned);
+  if (pinned && index != non_pinned_tab_index) {
+    MoveWebContentsAtImpl(index, non_pinned_tab_index, false);
+    index = non_pinned_tab_index;
+  } else if (!pinned && index + 1 != non_pinned_tab_index) {
+    MoveWebContentsAtImpl(index, non_pinned_tab_index - 1, false);
+    index = non_pinned_tab_index - 1;
+  }
+
+  for (auto& observer : observers_)
+    observer.TabPinnedStateChanged(this, contents_data_[index]->web_contents(),
+                                   index);
+}
+
+bool TabStripModel::IsTabPinned(int index) const {
+  DCHECK(ContainsIndex(index));
+  return contents_data_[index]->pinned();
+}
+
+bool TabStripModel::IsTabBlocked(int index) const {
+  return contents_data_[index]->blocked();
+}
+
+int TabStripModel::IndexOfFirstNonPinnedTab() const {
+  for (size_t i = 0; i < contents_data_.size(); ++i) {
+    if (!IsTabPinned(static_cast<int>(i)))
+      return static_cast<int>(i);
+  }
+  // No pinned tabs.
+  return count();
+}
+
+void TabStripModel::ExtendSelectionTo(int index) {
+  DCHECK(ContainsIndex(index));
+  ui::ListSelectionModel new_model = selection_model_;
+  new_model.SetSelectionFromAnchorTo(index);
+  SetSelection(std::move(new_model), Notify::kDefault);
+}
+
+void TabStripModel::ToggleSelectionAt(int index) {
+  DCHECK(ContainsIndex(index));
+  ui::ListSelectionModel new_model = selection_model();
+  if (selection_model_.IsSelected(index)) {
+    if (selection_model_.size() == 1) {
+      // One tab must be selected and this tab is currently selected so we can't
+      // unselect it.
+      return;
+    }
+    new_model.RemoveIndexFromSelection(index);
+    new_model.set_anchor(index);
+    if (new_model.active() == index ||
+        new_model.active() == ui::ListSelectionModel::kUnselectedIndex)
+      new_model.set_active(new_model.selected_indices()[0]);
+  } else {
+    new_model.AddIndexToSelection(index);
+    new_model.set_anchor(index);
+    new_model.set_active(index);
+  }
+  SetSelection(std::move(new_model), Notify::kDefault);
+}
+
+void TabStripModel::AddSelectionFromAnchorTo(int index) {
+  ui::ListSelectionModel new_model = selection_model_;
+  new_model.AddSelectionFromAnchorTo(index);
+  SetSelection(std::move(new_model), Notify::kDefault);
+}
+
+bool TabStripModel::IsTabSelected(int index) const {
+  DCHECK(ContainsIndex(index));
+  return selection_model_.IsSelected(index);
+}
+
+void TabStripModel::SetSelectionFromModel(ui::ListSelectionModel source) {
+  DCHECK_NE(ui::ListSelectionModel::kUnselectedIndex, source.active());
+  SetSelection(std::move(source), Notify::kDefault);
+}
+
+const ui::ListSelectionModel& TabStripModel::selection_model() const {
+  return selection_model_;
+}
+
+void TabStripModel::AddWebContents(WebContents* contents,
+                                   int index,
+                                   ui::PageTransition transition,
+                                   int add_types) {
+  // If the newly-opened tab is part of the same task as the parent tab, we want
+  // to inherit the parent's "group" attribute, so that if this tab is then
+  // closed we'll jump back to the parent tab.
+  bool inherit_group = (add_types & ADD_INHERIT_GROUP) == ADD_INHERIT_GROUP;
+
+  if (ui::PageTransitionTypeIncludingQualifiersIs(transition,
+                                                  ui::PAGE_TRANSITION_LINK) &&
+      (add_types & ADD_FORCE_INDEX) == 0) {
+    // We assume tabs opened via link clicks are part of the same task as their
+    // parent.  Note that when |force_index| is true (e.g. when the user
+    // drag-and-drops a link to the tab strip), callers aren't really handling
+    // link clicks, they just want to score the navigation like a link click in
+    // the history backend, so we don't inherit the group in this case.
+    index = order_controller_->DetermineInsertionIndex(transition,
+                                                       add_types & ADD_ACTIVE);
+    inherit_group = true;
+  } else {
+    // For all other types, respect what was passed to us, normalizing -1s and
+    // values that are too large.
+    if (index < 0 || index > count())
+      index = count();
+  }
+
+  if (ui::PageTransitionTypeIncludingQualifiersIs(transition,
+                                                  ui::PAGE_TRANSITION_TYPED) &&
+      index == count()) {
+    // Also, any tab opened at the end of the TabStrip with a "TYPED"
+    // transition inherit group as well. This covers the cases where the user
+    // creates a New Tab (e.g. Ctrl+T, or clicks the New Tab button), or types
+    // in the address bar and presses Alt+Enter. This allows for opening a new
+    // Tab to quickly look up something. When this Tab is closed, the old one
+    // is re-selected, not the next-adjacent.
+    inherit_group = true;
+  }
+  InsertWebContentsAt(index, contents,
+                      add_types | (inherit_group ? ADD_INHERIT_GROUP : 0));
+  // Reset the index, just in case insert ended up moving it on us.
+  index = GetIndexOfWebContents(contents);
+
+  if (inherit_group && ui::PageTransitionTypeIncludingQualifiersIs(
+                           transition, ui::PAGE_TRANSITION_TYPED))
+    contents_data_[index]->set_reset_group_on_select(true);
+
+  // TODO(sky): figure out why this is here and not in InsertWebContentsAt. When
+  // here we seem to get failures in startup perf tests.
+  // Ensure that the new WebContentsView begins at the same size as the
+  // previous WebContentsView if it existed.  Otherwise, the initial WebKit
+  // layout will be performed based on a width of 0 pixels, causing a
+  // very long, narrow, inaccurate layout.  Because some scripts on pages (as
+  // well as WebKit's anchor link location calculation) are run on the
+  // initial layout and not recalculated later, we need to ensure the first
+  // layout is performed with sane view dimensions even when we're opening a
+  // new background tab.
+  if (WebContents* old_contents = GetActiveWebContents()) {
+    if ((add_types & ADD_ACTIVE) == 0) {
+      ResizeWebContents(contents,
+                        gfx::Rect(old_contents->GetContainerBounds().size()));
+    }
+  }
+}
+
+void TabStripModel::CloseSelectedTabs() {
+  InternalCloseTabs(
+      GetWebContentsesByIndices(selection_model_.selected_indices()),
+      CLOSE_CREATE_HISTORICAL_TAB | CLOSE_USER_GESTURE);
+}
+
+void TabStripModel::SelectNextTab() {
+  SelectRelativeTab(true);
+}
+
+void TabStripModel::SelectPreviousTab() {
+  SelectRelativeTab(false);
+}
+
+void TabStripModel::SelectLastTab() {
+  ActivateTabAt(count() - 1, true);
+}
+
+void TabStripModel::MoveTabNext() {
+  // TODO: this likely needs to be updated for multi-selection.
+  int new_index = std::min(active_index() + 1, count() - 1);
+  MoveWebContentsAt(active_index(), new_index, true);
+}
+
+void TabStripModel::MoveTabPrevious() {
+  // TODO: this likely needs to be updated for multi-selection.
+  int new_index = std::max(active_index() - 1, 0);
+  MoveWebContentsAt(active_index(), new_index, true);
+}
+
+// Context menu functions.
+bool TabStripModel::IsContextMenuCommandEnabled(
+    int context_index,
+    ContextMenuCommand command_id) const {
+  DCHECK(command_id > CommandFirst && command_id < CommandLast);
+  switch (command_id) {
+    case CommandNewTab:
+    case CommandCloseTab:
+      return true;
+
+    case CommandReload: {
+      std::vector<int> indices = GetIndicesForCommand(context_index);
+      for (size_t i = 0; i < indices.size(); ++i) {
+        WebContents* tab = GetWebContentsAt(indices[i]);
+        if (tab) {
+          CoreTabHelperDelegate* core_delegate =
+              CoreTabHelper::FromWebContents(tab)->delegate();
+          if (!core_delegate || core_delegate->CanReloadContents(tab))
+            return true;
+        }
+      }
+      return false;
+    }
+
+    case CommandCloseOtherTabs:
+    case CommandCloseTabsToRight:
+      return !GetIndicesClosedByCommand(context_index, command_id).empty();
+
+    case CommandDuplicate: {
+      std::vector<int> indices = GetIndicesForCommand(context_index);
+      for (size_t i = 0; i < indices.size(); ++i) {
+        if (delegate()->CanDuplicateContentsAt(indices[i]))
+          return true;
+      }
+      return false;
+    }
+
+    case CommandRestoreTab:
+      return delegate()->GetRestoreTabType() !=
+             TabStripModelDelegate::RESTORE_NONE;
+
+    case CommandToggleTabAudioMuted:
+    case CommandToggleSiteMuted: {
+      std::vector<int> indices = GetIndicesForCommand(context_index);
+      for (size_t i = 0; i < indices.size(); ++i) {
+        if (!chrome::CanToggleAudioMute(GetWebContentsAt(indices[i])))
+          return false;
+      }
+      return true;
+    }
+
+    case CommandBookmarkAllTabs:
+      return browser_defaults::bookmarks_enabled &&
+             delegate()->CanBookmarkAllTabs();
+
+    case CommandTogglePinned:
+    case CommandSelectByDomain:
+    case CommandSelectByOpener:
+      return true;
+
+    default:
+      NOTREACHED();
+  }
+  return false;
+}
+
+void TabStripModel::ExecuteContextMenuCommand(int context_index,
+                                              ContextMenuCommand command_id) {
+  DCHECK(command_id > CommandFirst && command_id < CommandLast);
+  switch (command_id) {
+    case CommandNewTab: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_NewTab"));
+      UMA_HISTOGRAM_ENUMERATION("Tab.NewTab",
+                                TabStripModel::NEW_TAB_CONTEXT_MENU,
+                                TabStripModel::NEW_TAB_ENUM_COUNT);
+      delegate()->AddTabAt(GURL(), context_index + 1, true);
+#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
+      auto* new_tab_tracker =
+          feature_engagement::NewTabTrackerFactory::GetInstance()
+              ->GetForProfile(profile_);
+      new_tab_tracker->OnNewTabOpened();
+      new_tab_tracker->CloseBubble();
+#endif
+      break;
+    }
+
+    case CommandReload: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_Reload"));
+      std::vector<int> indices = GetIndicesForCommand(context_index);
+      for (size_t i = 0; i < indices.size(); ++i) {
+        WebContents* tab = GetWebContentsAt(indices[i]);
+        if (tab) {
+          CoreTabHelperDelegate* core_delegate =
+              CoreTabHelper::FromWebContents(tab)->delegate();
+          if (!core_delegate || core_delegate->CanReloadContents(tab))
+            tab->GetController().Reload(content::ReloadType::NORMAL, true);
+        }
+      }
+      break;
+    }
+
+    case CommandDuplicate: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_Duplicate"));
+      std::vector<int> indices = GetIndicesForCommand(context_index);
+      // Copy the WebContents off as the indices will change as tabs are
+      // duplicated.
+      std::vector<WebContents*> tabs;
+      for (size_t i = 0; i < indices.size(); ++i)
+        tabs.push_back(GetWebContentsAt(indices[i]));
+      for (size_t i = 0; i < tabs.size(); ++i) {
+        int index = GetIndexOfWebContents(tabs[i]);
+        if (index != -1 && delegate()->CanDuplicateContentsAt(index))
+          delegate()->DuplicateContentsAt(index);
+      }
+      break;
+    }
+
+    case CommandCloseTab: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_CloseTab"));
+      InternalCloseTabs(
+          GetWebContentsesByIndices(GetIndicesForCommand(context_index)),
+          CLOSE_CREATE_HISTORICAL_TAB | CLOSE_USER_GESTURE);
+      break;
+    }
+
+    case CommandCloseOtherTabs: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_CloseOtherTabs"));
+      InternalCloseTabs(GetWebContentsesByIndices(GetIndicesClosedByCommand(
+                            context_index, command_id)),
+                        CLOSE_CREATE_HISTORICAL_TAB);
+      break;
+    }
+
+    case CommandCloseTabsToRight: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_CloseTabsToRight"));
+      InternalCloseTabs(GetWebContentsesByIndices(GetIndicesClosedByCommand(
+                            context_index, command_id)),
+                        CLOSE_CREATE_HISTORICAL_TAB);
+      break;
+    }
+
+    case CommandRestoreTab: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_RestoreTab"));
+      delegate()->RestoreTab();
+      break;
+    }
+
+    case CommandTogglePinned: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_TogglePinned"));
+      std::vector<int> indices = GetIndicesForCommand(context_index);
+      bool pin = WillContextMenuPin(context_index);
+      if (pin) {
+        for (size_t i = 0; i < indices.size(); ++i)
+          SetTabPinned(indices[i], true);
+      } else {
+        // Unpin from the back so that the order is maintained (unpinning can
+        // trigger moving a tab).
+        for (size_t i = indices.size(); i > 0; --i)
+          SetTabPinned(indices[i - 1], false);
+      }
+      break;
+    }
+
+    case CommandToggleTabAudioMuted: {
+      const std::vector<int>& indices = GetIndicesForCommand(context_index);
+      const bool mute = WillContextMenuMute(context_index);
+      if (mute)
+        base::RecordAction(UserMetricsAction("TabContextMenu_MuteTabs"));
+      else
+        base::RecordAction(UserMetricsAction("TabContextMenu_UnmuteTabs"));
+      for (std::vector<int>::const_iterator i = indices.begin();
+           i != indices.end(); ++i) {
+        chrome::SetTabAudioMuted(GetWebContentsAt(*i), mute,
+                                 TabMutedReason::CONTEXT_MENU, std::string());
+      }
+      break;
+    }
+
+    case CommandToggleSiteMuted: {
+      const std::vector<int>& indices = GetIndicesForCommand(context_index);
+      const bool mute = WillContextMenuMuteSites(context_index);
+      if (mute) {
+        base::RecordAction(
+            UserMetricsAction("SoundContentSetting.MuteBy.TabStrip"));
+      } else {
+        base::RecordAction(
+            UserMetricsAction("SoundContentSetting.UnmuteBy.TabStrip"));
+      }
+      chrome::SetSitesMuted(*this, indices, mute);
+      break;
+    }
+
+    case CommandBookmarkAllTabs: {
+      base::RecordAction(UserMetricsAction("TabContextMenu_BookmarkAllTabs"));
+
+      delegate()->BookmarkAllTabs();
+      break;
+    }
+
+    case CommandSelectByDomain:
+    case CommandSelectByOpener: {
+      std::vector<int> indices;
+      if (command_id == CommandSelectByDomain)
+        GetIndicesWithSameDomain(context_index, &indices);
+      else
+        GetIndicesWithSameOpener(context_index, &indices);
+      ui::ListSelectionModel selection_model;
+      selection_model.SetSelectedIndex(context_index);
+      for (size_t i = 0; i < indices.size(); ++i)
+        selection_model.AddIndexToSelection(indices[i]);
+      SetSelectionFromModel(std::move(selection_model));
+      break;
+    }
+
+    default:
+      NOTREACHED();
+  }
+}
+
+std::vector<int> TabStripModel::GetIndicesClosedByCommand(
+    int index,
+    ContextMenuCommand id) const {
+  DCHECK(ContainsIndex(index));
+  DCHECK(id == CommandCloseTabsToRight || id == CommandCloseOtherTabs);
+  bool is_selected = IsTabSelected(index);
+  int last_unclosed_tab = -1;
+  if (id == CommandCloseTabsToRight) {
+    last_unclosed_tab =
+        is_selected ? selection_model_.selected_indices().back() : index;
+  }
+
+  // NOTE: callers expect the vector to be sorted in descending order.
+  std::vector<int> indices;
+  for (int i = count() - 1; i > last_unclosed_tab; --i) {
+    if (i != index && !IsTabPinned(i) && (!is_selected || !IsTabSelected(i)))
+      indices.push_back(i);
+  }
+  return indices;
+}
+
+bool TabStripModel::WillContextMenuMute(int index) {
+  std::vector<int> indices = GetIndicesForCommand(index);
+  return !chrome::AreAllTabsMuted(*this, indices);
+}
+
+bool TabStripModel::WillContextMenuMuteSites(int index) {
+  return !chrome::AreAllSitesMuted(*this, GetIndicesForCommand(index));
+}
+
+bool TabStripModel::WillContextMenuPin(int index) {
+  std::vector<int> indices = GetIndicesForCommand(index);
+  // If all tabs are pinned, then we unpin, otherwise we pin.
+  bool all_pinned = true;
+  for (size_t i = 0; i < indices.size() && all_pinned; ++i)
+    all_pinned = IsTabPinned(indices[i]);
+  return !all_pinned;
+}
+
 // static
 bool TabStripModel::ContextMenuCommandToBrowserCommand(int cmd_id,
                                                        int* browser_cmd) {
@@ -52,6 +995,48 @@
   return true;
 }
 
+int TabStripModel::GetIndexOfNextWebContentsOpenedBy(const WebContents* opener,
+                                                     int start_index,
+                                                     bool use_group) const {
+  DCHECK(opener);
+  DCHECK(ContainsIndex(start_index));
+
+  // Check tabs after start_index first.
+  for (int i = start_index + 1; i < count(); ++i) {
+    if (OpenerMatches(contents_data_[i], opener, use_group))
+      return i;
+  }
+  // Then check tabs before start_index, iterating backwards.
+  for (int i = start_index - 1; i >= 0; --i) {
+    if (OpenerMatches(contents_data_[i], opener, use_group))
+      return i;
+  }
+  return kNoTab;
+}
+
+void TabStripModel::ForgetAllOpeners() {
+  // Forget all opener memories so we don't do anything weird with tab
+  // re-selection ordering.
+  for (const auto& data : contents_data_)
+    data->set_opener(nullptr);
+}
+
+void TabStripModel::ForgetGroup(WebContents* contents) {
+  int index = GetIndexOfWebContents(contents);
+  DCHECK(ContainsIndex(index));
+  contents_data_[index]->set_group(nullptr);
+  contents_data_[index]->set_opener(nullptr);
+}
+
+bool TabStripModel::ShouldResetGroupOnSelect(WebContents* contents) const {
+  int index = GetIndexOfWebContents(contents);
+  DCHECK(ContainsIndex(index));
+  return contents_data_[index]->reset_group_on_select();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TabStripModel, private:
+
 bool TabStripModel::ContainsWebContents(content::WebContents* contents) {
   return GetIndexOfWebContents(contents) != kNoTab;
 }
@@ -79,3 +1064,238 @@
     content::WebContents* contents) {
   return delegate_->ShouldRunUnloadListenerBeforeClosing(contents);
 }
+
+int TabStripModel::ConstrainInsertionIndex(int index, bool pinned_tab) {
+  return pinned_tab
+             ? std::min(std::max(0, index), IndexOfFirstNonPinnedTab())
+             : std::min(count(), std::max(index, IndexOfFirstNonPinnedTab()));
+}
+
+std::vector<WebContents*> TabStripModel::GetWebContentsFromIndices(
+    const std::vector<int>& indices) const {
+  std::vector<WebContents*> contents;
+  for (size_t i = 0; i < indices.size(); ++i)
+    contents.push_back(GetWebContentsAtImpl(indices[i]));
+  return contents;
+}
+
+void TabStripModel::GetIndicesWithSameDomain(int index,
+                                             std::vector<int>* indices) {
+  std::string domain = GetWebContentsAt(index)->GetURL().host();
+  if (domain.empty())
+    return;
+  for (int i = 0; i < count(); ++i) {
+    if (i == index)
+      continue;
+    if (GetWebContentsAt(i)->GetURL().host_piece() == domain)
+      indices->push_back(i);
+  }
+}
+
+void TabStripModel::GetIndicesWithSameOpener(int index,
+                                             std::vector<int>* indices) {
+  WebContents* opener = contents_data_[index]->group();
+  if (!opener) {
+    // If there is no group, find all tabs with the selected tab as the opener.
+    opener = GetWebContentsAt(index);
+    if (!opener)
+      return;
+  }
+  for (int i = 0; i < count(); ++i) {
+    if (i == index)
+      continue;
+    if (contents_data_[i]->group() == opener ||
+        GetWebContentsAtImpl(i) == opener) {
+      indices->push_back(i);
+    }
+  }
+}
+
+std::vector<int> TabStripModel::GetIndicesForCommand(int index) const {
+  if (!IsTabSelected(index)) {
+    std::vector<int> indices;
+    indices.push_back(index);
+    return indices;
+  }
+  return selection_model_.selected_indices();
+}
+
+bool TabStripModel::IsNewTabAtEndOfTabStrip(WebContents* contents) const {
+  const GURL& url = contents->GetURL();
+  return url.SchemeIs(content::kChromeUIScheme) &&
+         url.host_piece() == chrome::kChromeUINewTabHost &&
+         contents == GetWebContentsAtImpl(count() - 1) &&
+         contents->GetController().GetEntryCount() == 1;
+}
+
+std::vector<content::WebContents*> TabStripModel::GetWebContentsesByIndices(
+    const std::vector<int>& indices) {
+  std::vector<content::WebContents*> items;
+  items.reserve(indices.size());
+  for (int index : indices)
+    items.push_back(GetWebContentsAtImpl(index));
+  return items;
+}
+
+bool TabStripModel::InternalCloseTabs(
+    base::span<content::WebContents* const> items,
+    uint32_t close_types) {
+  if (items.empty())
+    return true;
+
+  const bool closing_all = static_cast<int>(items.size()) == count();
+  base::WeakPtr<TabStripModel> ref = weak_factory_.GetWeakPtr();
+  if (closing_all) {
+    for (auto& observer : observers_)
+      observer.WillCloseAllTabs();
+  }
+  const bool closed_all = CloseWebContentses(this, items, close_types);
+  if (!ref)
+    return closed_all;
+  if (closing_all && !closed_all) {
+    for (auto& observer : observers_)
+      observer.CloseAllTabsCanceled();
+  }
+  return closed_all;
+}
+
+WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
+  CHECK(ContainsIndex(index))
+      << "Failed to find: " << index << " in: " << count() << " entries.";
+  return contents_data_[index]->web_contents();
+}
+
+void TabStripModel::NotifyIfTabDeactivated(WebContents* contents) {
+  if (contents) {
+    for (auto& observer : observers_)
+      observer.TabDeactivated(contents);
+  }
+}
+
+void TabStripModel::NotifyIfActiveTabChanged(WebContents* old_contents,
+                                             Notify notify_types) {
+  WebContents* new_contents = GetWebContentsAtImpl(active_index());
+  if (old_contents == new_contents)
+    return;
+
+  int reason = notify_types == Notify::kUserGesture
+                   ? TabStripModelObserver::CHANGE_REASON_USER_GESTURE
+                   : TabStripModelObserver::CHANGE_REASON_NONE;
+  CHECK(!in_notify_);
+  in_notify_ = true;
+  for (auto& observer : observers_) {
+    observer.ActiveTabChanged(old_contents, new_contents, active_index(),
+                              reason);
+  }
+  in_notify_ = false;
+}
+
+void TabStripModel::NotifyIfActiveOrSelectionChanged(
+    WebContents* old_contents,
+    Notify notify_types,
+    const ui::ListSelectionModel& old_model) {
+  NotifyIfActiveTabChanged(old_contents, notify_types);
+
+  if (selection_model() != old_model) {
+    for (auto& observer : observers_)
+      observer.TabSelectionChanged(this, old_model);
+  }
+}
+
+void TabStripModel::SetSelection(ui::ListSelectionModel new_model,
+                                 Notify notify_types) {
+  WebContents* old_contents = GetActiveWebContents();
+  ui::ListSelectionModel old_model;
+  old_model = selection_model_;
+  if (new_model.active() != selection_model_.active())
+    NotifyIfTabDeactivated(old_contents);
+  selection_model_ = new_model;
+  NotifyIfActiveOrSelectionChanged(old_contents, notify_types, old_model);
+}
+
+void TabStripModel::SelectRelativeTab(bool next) {
+  // This may happen during automated testing or if a user somehow buffers
+  // many key accelerators.
+  if (contents_data_.empty())
+    return;
+
+  int index = active_index();
+  int delta = next ? 1 : -1;
+  index = (index + count() + delta) % count();
+  ActivateTabAt(index, true);
+}
+
+void TabStripModel::MoveWebContentsAtImpl(int index,
+                                          int to_position,
+                                          bool select_after_move) {
+  FixOpenersAndGroupsReferencing(index);
+
+  std::unique_ptr<WebContentsData> moved_data =
+      std::move(contents_data_[index]);
+  WebContents* web_contents = moved_data->web_contents();
+  contents_data_.erase(contents_data_.begin() + index);
+  contents_data_.insert(contents_data_.begin() + to_position,
+                        std::move(moved_data));
+
+  selection_model_.Move(index, to_position, 1);
+  if (!selection_model_.IsSelected(to_position) && select_after_move) {
+    // TODO(sky): why doesn't this code notify observers?
+    selection_model_.SetSelectedIndex(to_position);
+  }
+
+  for (auto& observer : observers_)
+    observer.TabMoved(web_contents, index, to_position);
+}
+
+void TabStripModel::MoveSelectedTabsToImpl(int index,
+                                           size_t start,
+                                           size_t length) {
+  DCHECK(start < selection_model_.selected_indices().size() &&
+         start + length <= selection_model_.selected_indices().size());
+  size_t end = start + length;
+  int count_before_index = 0;
+  for (size_t i = start; i < end && selection_model_.selected_indices()[i] <
+                                        index + count_before_index;
+       ++i) {
+    count_before_index++;
+  }
+
+  // First move those before index. Any tabs before index end up moving in the
+  // selection model so we use start each time through.
+  int target_index = index + count_before_index;
+  size_t tab_index = start;
+  while (tab_index < end &&
+         selection_model_.selected_indices()[start] < index) {
+    MoveWebContentsAt(selection_model_.selected_indices()[start],
+                      target_index - 1, false);
+    tab_index++;
+  }
+
+  // Then move those after the index. These don't result in reordering the
+  // selection.
+  while (tab_index < end) {
+    if (selection_model_.selected_indices()[tab_index] != target_index) {
+      MoveWebContentsAt(selection_model_.selected_indices()[tab_index],
+                        target_index, false);
+    }
+    tab_index++;
+    target_index++;
+  }
+}
+
+// static
+bool TabStripModel::OpenerMatches(const std::unique_ptr<WebContentsData>& data,
+                                  const WebContents* opener,
+                                  bool use_group) {
+  return data->opener() == opener || (use_group && data->group() == opener);
+}
+
+void TabStripModel::FixOpenersAndGroupsReferencing(int index) {
+  WebContents* old_contents = GetWebContentsAtImpl(index);
+  for (auto& data : contents_data_) {
+    if (data->group() == old_contents)
+      data->set_group(contents_data_[index]->group());
+    if (data->opener() == old_contents)
+      data->set_opener(contents_data_[index]->opener());
+  }
+}
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 3d7e56be..d99b48d 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -11,16 +11,18 @@
 #include <memory>
 #include <vector>
 
+#include "base/containers/span.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
 #include "chrome/browser/ui/tabs/web_contents_closer.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/base/page_transition_types.h"
 
 class Profile;
 class TabStripModelDelegate;
-class TabStripModelExperimental;
 
 namespace content {
 class WebContents;
@@ -117,12 +119,11 @@
 
   static const int kNoTab = -1;
 
-  explicit TabStripModel(TabStripModelDelegate* delegate);
+  // Construct a TabStripModel with a delegate to help it do certain things
+  // (see the TabStripModelDelegate documentation). |delegate| cannot be NULL.
+  explicit TabStripModel(TabStripModelDelegate* delegate, Profile* profile);
   ~TabStripModel() override;
 
-  // Returns the experimental implementation if there is one, nullptr otherwise.
-  virtual TabStripModelExperimental* AsTabStripModelExperimental() = 0;
-
   // Retrieves the TabStripModelDelegate associated with this TabStripModel.
   TabStripModelDelegate* delegate() const { return delegate_; }
 
@@ -131,32 +132,31 @@
   void RemoveObserver(TabStripModelObserver* observer);
 
   // Retrieve the number of WebContentses/emptiness of the TabStripModel.
-  virtual int count() const = 0;
-  virtual bool empty() const = 0;
+  int count() const { return static_cast<int>(contents_data_.size()); }
+  bool empty() const { return contents_data_.empty(); }
 
   // Retrieve the Profile associated with this TabStripModel.
-  virtual Profile* profile() const = 0;
+  Profile* profile() const { return profile_; }
 
   // Retrieve the index of the currently active WebContents. This will be
   // ui::ListSelectionModel::kUnselectedIndex if no tab is currently selected
   // (this happens while the tab strip is being initialized or is empty).
-  virtual int active_index() const = 0;
+  int active_index() const { return selection_model_.active(); }
 
   // Returns true if the tabstrip is currently closing all open tabs (via a
   // call to CloseAllTabs). As tabs close, the selection in the tabstrip
   // changes which notifies observers, which can use this as an optimization to
   // avoid doing meaningless or unhelpful work.
-  virtual bool closing_all() const = 0;
+  bool closing_all() const { return closing_all_; }
 
   // Basic API /////////////////////////////////////////////////////////////////
 
   // Determines if the specified index is contained within the TabStripModel.
-  virtual bool ContainsIndex(int index) const = 0;
+  bool ContainsIndex(int index) const;
 
   // Adds the specified WebContents in the default location. Tabs opened
   // in the foreground inherit the group of the previously active tab.
-  virtual void AppendWebContents(content::WebContents* contents,
-                                 bool foreground) = 0;
+  void AppendWebContents(content::WebContents* contents, bool foreground);
 
   // Adds the specified WebContents at the specified location.
   // |add_types| is a bitmask of AddTabTypes; see it for details.
@@ -168,9 +168,9 @@
   // the |index| is changed is if using the index would result in breaking the
   // constraint that all pinned tabs occur before non-pinned tabs.
   // See also AddWebContents.
-  virtual void InsertWebContentsAt(int index,
-                                   content::WebContents* contents,
-                                   int add_types) = 0;
+  void InsertWebContentsAt(int index,
+                           content::WebContents* contents,
+                           int add_types);
 
   // Closes the WebContents at the specified index. This causes the
   // WebContents to be destroyed, but it may not happen immediately.
@@ -178,30 +178,30 @@
   // WebContents was closed immediately, false if it was not closed (we
   // may be waiting for a response from an onunload handler, or waiting for the
   // user to confirm closure).
-  virtual bool CloseWebContentsAt(int index, uint32_t close_types) = 0;
+  bool CloseWebContentsAt(int index, uint32_t close_types);
 
   // Replaces the WebContents at |index| with |new_contents|. The
   // WebContents that was at |index| is returned and its ownership returns
   // to the caller.
-  virtual content::WebContents* ReplaceWebContentsAt(
+  content::WebContents* ReplaceWebContentsAt(
       int index,
-      content::WebContents* new_contents) = 0;
+      content::WebContents* new_contents);
 
   // Detaches the WebContents at the specified index from this strip. The
   // WebContents is not destroyed, just removed from display. The caller
   // is responsible for doing something with it (e.g. stuffing it into another
   // strip). Returns the detached WebContents.
-  virtual content::WebContents* DetachWebContentsAt(int index) = 0;
+  content::WebContents* DetachWebContentsAt(int index);
 
   // Makes the tab at the specified index the active tab. |user_gesture| is true
   // if the user actually clicked on the tab or navigated to it using a keyboard
   // command, false if the tab was activated as a by-product of some other
   // action.
-  virtual void ActivateTabAt(int index, bool user_gesture) = 0;
+  void ActivateTabAt(int index, bool user_gesture);
 
   // Adds tab at |index| to the currently selected tabs, without changing the
   // active tab index.
-  virtual void AddTabAtToSelection(int index) = 0;
+  void AddTabAtToSelection(int index);
 
   // Move the WebContents at the specified index to another index. This
   // method does NOT send Detached/Attached notifications, rather it moves the
@@ -209,9 +209,7 @@
   // If |select_after_move| is false, whatever tab was selected before the move
   // will still be selected, but its index may have incremented or decremented
   // one slot.
-  virtual void MoveWebContentsAt(int index,
-                                 int to_position,
-                                 bool select_after_move) = 0;
+  void MoveWebContentsAt(int index, int to_position, bool select_after_move);
 
   // Moves the selected tabs to |index|. |index| is treated as if the tab strip
   // did not contain any of the selected tabs. For example, if the tabstrip
@@ -229,96 +227,92 @@
   // index were 3, then the result would be [b c A f D F]. A, being pinned, can
   // move no further than index 2. The non-pinned tabs are moved to the target
   // index + selected-pinned tab-count (3 + 1).
-  virtual void MoveSelectedTabsTo(int index) = 0;
+  void MoveSelectedTabsTo(int index);
 
   // Returns the currently active WebContents, or NULL if there is none.
-  virtual content::WebContents* GetActiveWebContents() const = 0;
+  content::WebContents* GetActiveWebContents() const;
 
   // Returns the WebContents at the specified index, or NULL if there is
   // none.
-  virtual content::WebContents* GetWebContentsAt(int index) const = 0;
+  content::WebContents* GetWebContentsAt(int index) const;
 
   // Returns the index of the specified WebContents, or TabStripModel::kNoTab
   // if the WebContents is not in this TabStripModel.
-  virtual int GetIndexOfWebContents(
-      const content::WebContents* contents) const = 0;
+  int GetIndexOfWebContents(const content::WebContents* contents) const;
 
   // Notify any observers that the WebContents at the specified index has
   // changed in some way. See TabChangeType for details of |change_type|.
-  virtual void UpdateWebContentsStateAt(int index,
-                                        TabChangeType change_type) = 0;
+  void UpdateWebContentsStateAt(int index, TabChangeType change_type);
 
   // Cause a tab to display a UI indication to the user that it needs their
   // attention.
-  virtual void SetTabNeedsAttentionAt(int index, bool attention) = 0;
+  void SetTabNeedsAttentionAt(int index, bool attention);
 
   // Close all tabs at once. Code can use closing_all() above to defer
   // operations that might otherwise by invoked by the flurry of detach/select
   // notifications this method causes.
-  virtual void CloseAllTabs() = 0;
+  void CloseAllTabs();
 
   // Returns true if there are any WebContentses that are currently loading.
-  virtual bool TabsAreLoading() const = 0;
+  bool TabsAreLoading() const;
 
   // Returns the WebContents that opened the WebContents at |index|, or NULL if
   // there is no opener on record.
-  virtual content::WebContents* GetOpenerOfWebContentsAt(int index) = 0;
+  content::WebContents* GetOpenerOfWebContentsAt(int index);
 
   // Changes the |opener| of the WebContents at |index|.
   // Note: |opener| must be in this tab strip.
-  virtual void SetOpenerOfWebContentsAt(int index,
-                                        content::WebContents* opener) = 0;
+  void SetOpenerOfWebContentsAt(int index, content::WebContents* opener);
 
   // Returns the index of the last WebContents in the model opened by the
   // specified opener, starting at |start_index|.
-  virtual int GetIndexOfLastWebContentsOpenedBy(
-      const content::WebContents* opener,
-      int start_index) const = 0;
+  int GetIndexOfLastWebContentsOpenedBy(const content::WebContents* opener,
+                                        int start_index) const;
 
   // To be called when a navigation is about to occur in the specified
   // WebContents. Depending on the tab, and the transition type of the
   // navigation, the TabStripModel may adjust its selection and grouping
   // behavior.
-  virtual void TabNavigating(content::WebContents* contents,
-                             ui::PageTransition transition) = 0;
+  void TabNavigating(content::WebContents* contents,
+                     ui::PageTransition transition);
 
   // Changes the blocked state of the tab at |index|.
-  virtual void SetTabBlocked(int index, bool blocked) = 0;
+  void SetTabBlocked(int index, bool blocked);
 
   // Changes the pinned state of the tab at |index|. See description above
   // class for details on this.
-  virtual void SetTabPinned(int index, bool pinned) = 0;
+  void SetTabPinned(int index, bool pinned);
 
   // Returns true if the tab at |index| is pinned.
   // See description above class for details on pinned tabs.
-  virtual bool IsTabPinned(int index) const = 0;
+  bool IsTabPinned(int index) const;
 
   // Returns true if the tab at |index| is blocked by a tab modal dialog.
-  virtual bool IsTabBlocked(int index) const = 0;
+  bool IsTabBlocked(int index) const;
 
   // Returns the index of the first tab that is not a pinned tab. This returns
   // |count()| if all of the tabs are pinned tabs, and 0 if none of the tabs are
   // pinned tabs.
-  virtual int IndexOfFirstNonPinnedTab() const = 0;
+  int IndexOfFirstNonPinnedTab() const;
 
   // Extends the selection from the anchor to |index|.
-  virtual void ExtendSelectionTo(int index) = 0;
+  void ExtendSelectionTo(int index);
 
   // Toggles the selection at |index|. This does nothing if |index| is selected
   // and there are no other selected tabs.
-  virtual void ToggleSelectionAt(int index) = 0;
+  void ToggleSelectionAt(int index);
 
   // Makes sure the tabs from the anchor to |index| are selected. This only
   // adds to the selection.
-  virtual void AddSelectionFromAnchorTo(int index) = 0;
+  void AddSelectionFromAnchorTo(int index);
 
   // Returns true if the tab at |index| is selected.
-  virtual bool IsTabSelected(int index) const = 0;
+  bool IsTabSelected(int index) const;
 
   // Sets the selection to match that of |source|.
-  virtual void SetSelectionFromModel(ui::ListSelectionModel source) = 0;
+  void SetSelectionFromModel(ui::ListSelectionModel source);
 
-  virtual const ui::ListSelectionModel& selection_model() const = 0;
+  const ui::ListSelectionModel& selection_model() const;
 
   // Command level API /////////////////////////////////////////////////////////
 
@@ -327,30 +321,30 @@
   // AddTabTypes; see it for details. This method ends up calling into
   // InsertWebContentsAt to do the actual insertion. Pass kNoTab for |index| to
   // append the contents to the end of the tab strip.
-  virtual void AddWebContents(content::WebContents* contents,
-                              int index,
-                              ui::PageTransition transition,
-                              int add_types) = 0;
+  void AddWebContents(content::WebContents* contents,
+                      int index,
+                      ui::PageTransition transition,
+                      int add_types);
 
   // Closes the selected tabs.
-  virtual void CloseSelectedTabs() = 0;
+  void CloseSelectedTabs();
 
   // Select adjacent tabs
-  virtual void SelectNextTab() = 0;
-  virtual void SelectPreviousTab() = 0;
+  void SelectNextTab();
+  void SelectPreviousTab();
 
   // Selects the last tab in the tab strip.
-  virtual void SelectLastTab() = 0;
+  void SelectLastTab();
 
   // Swap adjacent tabs.
-  virtual void MoveTabNext() = 0;
-  virtual void MoveTabPrevious() = 0;
+  void MoveTabNext();
+  void MoveTabPrevious();
 
   // View API //////////////////////////////////////////////////////////////////
 
   // Context menu functions.
   enum ContextMenuCommand {
-    CommandFirst = 0,
+    CommandFirst,
     CommandNewTab,
     CommandReload,
     CommandDuplicate,
@@ -369,41 +363,79 @@
 
   // Returns true if the specified command is enabled. If |context_index| is
   // selected the response applies to all selected tabs.
-  virtual bool IsContextMenuCommandEnabled(
-      int context_index,
-      ContextMenuCommand command_id) const = 0;
+  bool IsContextMenuCommandEnabled(int context_index,
+                                   ContextMenuCommand command_id) const;
 
   // Performs the action associated with the specified command for the given
   // TabStripModel index |context_index|.  If |context_index| is selected the
   // command applies to all selected tabs.
-  virtual void ExecuteContextMenuCommand(int context_index,
-                                         ContextMenuCommand command_id) = 0;
+  void ExecuteContextMenuCommand(int context_index,
+                                 ContextMenuCommand command_id);
 
   // Returns a vector of indices of the tabs that will close when executing the
   // command |id| for the tab at |index|. The returned indices are sorted in
   // descending order.
-  virtual std::vector<int> GetIndicesClosedByCommand(
-      int index,
-      ContextMenuCommand id) const = 0;
+  std::vector<int> GetIndicesClosedByCommand(int index,
+                                             ContextMenuCommand id) const;
 
   // Returns true if 'CommandToggleTabAudioMuted' will mute. |index| is the
   // index supplied to |ExecuteContextMenuCommand|.
-  virtual bool WillContextMenuMute(int index) = 0;
+  bool WillContextMenuMute(int index);
 
   // Returns true if 'CommandToggleSiteMuted' will mute. |index| is the
   // index supplied to |ExecuteContextMenuCommand|.
-  virtual bool WillContextMenuMuteSites(int index) = 0;
+  bool WillContextMenuMuteSites(int index);
 
   // Returns true if 'CommandTogglePinned' will pin. |index| is the index
   // supplied to |ExecuteContextMenuCommand|.
-  virtual bool WillContextMenuPin(int index) = 0;
+  bool WillContextMenuPin(int index);
 
   // Convert a ContextMenuCommand into a browser command. Returns true if a
   // corresponding browser command exists, false otherwise.
   static bool ContextMenuCommandToBrowserCommand(int cmd_id, int* browser_cmd);
 
- protected:
-  base::ObserverList<TabStripModelObserver>& observers() { return observers_; }
+  // Access the order controller. Exposed only for unit tests.
+  TabStripModelOrderController* order_controller() const {
+    return order_controller_.get();
+  }
+
+  // Returns the index of the next WebContents in the sequence of WebContentses
+  // spawned by the specified WebContents after |start_index|. If |use_group| is
+  // true, the group property of the tab is used instead of the opener to find
+  // the next tab. Under some circumstances the group relationship may exist but
+  // the opener may not.
+  int GetIndexOfNextWebContentsOpenedBy(const content::WebContents* opener,
+                                        int start_index,
+                                        bool use_group) const;
+
+  // Forget all Opener relationships that are stored (but _not_ group
+  // relationships!) This is to reduce unpredictable tab switching behavior
+  // in complex session states. The exact circumstances under which this method
+  // is called are left up to the implementation of the selected
+  // TabStripModelOrderController.
+  void ForgetAllOpeners();
+
+  // Forgets the group affiliation of the specified WebContents. This
+  // should be called when a WebContents that is part of a logical group
+  // of tabs is moved to a new logical context by the user (e.g. by typing a new
+  // URL or selecting a bookmark). This also forgets the opener, which is
+  // considered a weaker relationship than group.
+  void ForgetGroup(content::WebContents* contents);
+
+  // Returns true if the group/opener relationships present for |contents|
+  // should be reset when _any_ selection change occurs in the model.
+  bool ShouldResetGroupOnSelect(content::WebContents* contents) const;
+
+ private:
+  class WebContentsData;
+
+  // Used when making selection notifications.
+  enum class Notify {
+    kDefault,
+
+    // The selection is changing from a user gesture.
+    kUserGesture,
+  };
 
   // WebContentsCloseDelegate:
   bool ContainsWebContents(content::WebContents* contents) override;
@@ -413,9 +445,122 @@
   bool ShouldRunUnloadListenerBeforeClosing(
       content::WebContents* contents) override;
 
- private:
+  int ConstrainInsertionIndex(int index, bool pinned_tab);
+
+  // Convenience for converting a vector of indices into a vector of
+  // WebContents.
+  std::vector<content::WebContents*> GetWebContentsFromIndices(
+      const std::vector<int>& indices) const;
+
+  // Gets the set of tab indices whose domain matches the tab at |index|.
+  void GetIndicesWithSameDomain(int index, std::vector<int>* indices);
+
+  // Gets the set of tab indices that have the same opener as the tab at
+  // |index|.
+  void GetIndicesWithSameOpener(int index, std::vector<int>* indices);
+
+  // If |index| is selected all the selected indices are returned, otherwise a
+  // vector with |index| is returned. This is used when executing commands to
+  // determine which indices the command applies to.
+  std::vector<int> GetIndicesForCommand(int index) const;
+
+  // Returns true if the specified WebContents is a New Tab at the end of
+  // the tabstrip. We check for this because opener relationships are _not_
+  // forgotten for the New Tab page opened as a result of a New Tab gesture
+  // (e.g. Ctrl+T, etc) since the user may open a tab transiently to look up
+  // something related to their current activity.
+  bool IsNewTabAtEndOfTabStrip(content::WebContents* contents) const;
+
+  // Closes the WebContentses at the specified indices. This causes the
+  // WebContentses to be destroyed, but it may not happen immediately. If
+  // the page in question has an unload event the WebContents will not be
+  // destroyed until after the event has completed, which will then call back
+  // into this method.
+  //
+  // Returns true if the WebContentses were closed immediately, false if we
+  // are waiting for the result of an onunload handler.
+  bool InternalCloseTabs(base::span<content::WebContents* const> items,
+                         uint32_t close_types);
+
+  // Gets the WebContents at an index. Does no bounds checking.
+  content::WebContents* GetWebContentsAtImpl(int index) const;
+
+  // Returns the WebContentses at the specified indices. This does no checking
+  // of the indices, it is assumed they are valid.
+  std::vector<content::WebContents*> GetWebContentsesByIndices(
+      const std::vector<int>& indices);
+
+  // Notifies the observers if the active tab is being deactivated.
+  void NotifyIfTabDeactivated(content::WebContents* contents);
+
+  // Notifies the observers if the active tab has changed.
+  void NotifyIfActiveTabChanged(content::WebContents* old_contents,
+                                Notify notify_types);
+
+  // Notifies the observers if the active tab or the tab selection has changed.
+  // |old_model| is a snapshot of |selection_model_| before the change.
+  // Note: This function might end up sending 0 to 2 notifications in the
+  // following order: ActiveTabChanged, TabSelectionChanged.
+  void NotifyIfActiveOrSelectionChanged(
+      content::WebContents* old_contents,
+      Notify notify_types,
+      const ui::ListSelectionModel& old_model);
+
+  // Sets the selection to |new_model| and notifies any observers.
+  // Note: This function might end up sending 0 to 3 notifications in the
+  // following order: TabDeactivated, ActiveTabChanged, TabSelectionChanged.
+  void SetSelection(ui::ListSelectionModel new_model, Notify notify_types);
+
+  // Selects either the next tab (|forward| is true), or the previous tab
+  // (|forward| is false).
+  void SelectRelativeTab(bool forward);
+
+  // Does the work of MoveWebContentsAt. This has no checks to make sure the
+  // position is valid, those are done in MoveWebContentsAt.
+  void MoveWebContentsAtImpl(int index,
+                             int to_position,
+                             bool select_after_move);
+
+  // Implementation of MoveSelectedTabsTo. Moves |length| of the selected tabs
+  // starting at |start| to |index|. See MoveSelectedTabsTo for more details.
+  void MoveSelectedTabsToImpl(int index, size_t start, size_t length);
+
+  // Returns true if the tab represented by the specified data has an opener
+  // that matches the specified one. If |use_group| is true, then this will
+  // fall back to check the group relationship as well.
+  static bool OpenerMatches(const std::unique_ptr<WebContentsData>& data,
+                            const content::WebContents* opener,
+                            bool use_group);
+
+  // Sets the group/opener of any tabs that reference the tab at |index| to that
+  // tab's group/opener respectively.
+  void FixOpenersAndGroupsReferencing(int index);
+
+  // The WebContents data currently hosted within this TabStripModel.
+  std::vector<std::unique_ptr<WebContentsData>> contents_data_;
+
   TabStripModelDelegate* delegate_;
   base::ObserverList<TabStripModelObserver> observers_;
+
+  // A profile associated with this TabStripModel.
+  Profile* profile_;
+
+  // True if all tabs are currently being closed via CloseAllTabs.
+  bool closing_all_ = false;
+
+  // An object that determines where new Tabs should be inserted and where
+  // selection should move when a Tab is closed.
+  std::unique_ptr<TabStripModelOrderController> order_controller_;
+
+  ui::ListSelectionModel selection_model_;
+
+  // Indicates if observers are currently being notified to catch reentrancy
+  // bugs. See for example http://crbug.com/529407
+  bool in_notify_ = false;
+
+  base::WeakPtrFactory<TabStripModel> weak_factory_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModel);
 };
 
 #endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_model_impl.cc b/chrome/browser/ui/tabs/tab_strip_model_impl.cc
deleted file mode 100644
index 2aa183ed..0000000
--- a/chrome/browser/ui/tabs/tab_strip_model_impl.cc
+++ /dev/null
@@ -1,1268 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
-
-#include <algorithm>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "build/build_config.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
-#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
-#include "chrome/browser/ui/tabs/tab_utils.h"
-#include "chrome/browser/ui/web_contents_sizer.h"
-#include "chrome/common/url_constants.h"
-#include "components/feature_engagement/features.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-
-#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-#include "chrome/browser/feature_engagement/new_tab/new_tab_tracker.h"
-#include "chrome/browser/feature_engagement/new_tab/new_tab_tracker_factory.h"
-#endif
-
-using base::UserMetricsAction;
-using content::WebContents;
-
-namespace {
-
-// Returns true if the specified transition is one of the types that cause the
-// opener relationships for the tab in which the transition occurred to be
-// forgotten. This is generally any navigation that isn't a link click (i.e.
-// any navigation that can be considered to be the start of a new task distinct
-// from what had previously occurred in that tab).
-bool ShouldForgetOpenersForTransition(ui::PageTransition transition) {
-  return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) ||
-         ui::PageTransitionCoreTypeIs(transition,
-                                      ui::PAGE_TRANSITION_AUTO_BOOKMARK) ||
-         ui::PageTransitionCoreTypeIs(transition,
-                                      ui::PAGE_TRANSITION_GENERATED) ||
-         ui::PageTransitionCoreTypeIs(transition,
-                                      ui::PAGE_TRANSITION_KEYWORD) ||
-         ui::PageTransitionCoreTypeIs(transition,
-                                      ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
-}
-
-}  // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// WebContentsData
-
-// An object to hold a reference to a WebContents that is in a tabstrip, as
-// well as other various properties it has.
-class TabStripModelImpl::WebContentsData : public content::WebContentsObserver {
- public:
-  WebContentsData(TabStripModel* tab_strip_model, WebContents* a_contents);
-
-  // Changes the WebContents that this WebContentsData tracks.
-  void SetWebContents(WebContents* contents);
-  WebContents* web_contents() { return contents_; }
-
-  // Create a relationship between this WebContentsData and other
-  // WebContentses. Used to identify which WebContents to select next after
-  // one is closed.
-  WebContents* group() const { return group_; }
-  void set_group(WebContents* value) { group_ = value; }
-  WebContents* opener() const { return opener_; }
-  void set_opener(WebContents* value) { opener_ = value; }
-
-  // Alters the properties of the WebContents.
-  bool reset_group_on_select() const { return reset_group_on_select_; }
-  void set_reset_group_on_select(bool value) { reset_group_on_select_ = value; }
-  bool pinned() const { return pinned_; }
-  void set_pinned(bool value) { pinned_ = value; }
-  bool blocked() const { return blocked_; }
-  void set_blocked(bool value) { blocked_ = value; }
-
- private:
-  // Make sure that if someone deletes this WebContents out from under us, it
-  // is properly removed from the tab strip.
-  void WebContentsDestroyed() override;
-
-  // The WebContents being tracked by this WebContentsData. The
-  // WebContentsObserver does keep a reference, but when the WebContents is
-  // deleted, the WebContentsObserver reference is NULLed and thus inaccessible.
-  WebContents* contents_;
-
-  // The TabStripModel containing this WebContents.
-  TabStripModel* tab_strip_model_;
-
-  // The group is used to model a set of tabs spawned from a single parent
-  // tab. This value is preserved for a given tab as long as the tab remains
-  // navigated to the link it was initially opened at or some navigation from
-  // that page (i.e. if the user types or visits a bookmark or some other
-  // navigation within that tab, the group relationship is lost). This
-  // property can safely be used to implement features that depend on a
-  // logical group of related tabs.
-  WebContents* group_ = nullptr;
-
-  // The owner models the same relationship as group, except it is more
-  // easily discarded, e.g. when the user switches to a tab not part of the
-  // same group. This property is used to determine what tab to select next
-  // when one is closed.
-  WebContents* opener_ = nullptr;
-
-  // True if our group should be reset the moment selection moves away from
-  // this tab. This is the case for tabs opened in the foreground at the end
-  // of the TabStrip while viewing another Tab. If these tabs are closed
-  // before selection moves elsewhere, their opener is selected. But if
-  // selection shifts to _any_ tab (including their opener), the group
-  // relationship is reset to avoid confusing close sequencing.
-  bool reset_group_on_select_ = false;
-
-  // Is the tab pinned?
-  bool pinned_ = false;
-
-  // Is the tab interaction blocked by a modal dialog?
-  bool blocked_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(WebContentsData);
-};
-
-TabStripModelImpl::WebContentsData::WebContentsData(
-    TabStripModel* tab_strip_model,
-    WebContents* contents)
-    : content::WebContentsObserver(contents),
-      contents_(contents),
-      tab_strip_model_(tab_strip_model) {}
-
-void TabStripModelImpl::WebContentsData::SetWebContents(WebContents* contents) {
-  contents_ = contents;
-  Observe(contents);
-}
-
-void TabStripModelImpl::WebContentsData::WebContentsDestroyed() {
-  DCHECK_EQ(contents_, web_contents());
-
-  // Note that we only detach the contents here, not close it - it's
-  // already been closed. We just want to undo our bookkeeping.
-  int index = tab_strip_model_->GetIndexOfWebContents(web_contents());
-  DCHECK_NE(TabStripModelImpl::kNoTab, index);
-  tab_strip_model_->DetachWebContentsAt(index);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// TabStripModel, public:
-
-TabStripModelImpl::TabStripModelImpl(TabStripModelDelegate* delegate,
-                                     Profile* profile)
-    : TabStripModel(delegate), profile_(profile), weak_factory_(this) {
-  order_controller_.reset(new TabStripModelOrderController(this));
-}
-
-TabStripModelImpl::~TabStripModelImpl() {
-  contents_data_.clear();
-  order_controller_.reset();
-}
-
-TabStripModelExperimental* TabStripModelImpl::AsTabStripModelExperimental() {
-  return nullptr;
-}
-
-int TabStripModelImpl::count() const {
-  return static_cast<int>(contents_data_.size());
-}
-
-bool TabStripModelImpl::empty() const {
-  return contents_data_.empty();
-}
-
-Profile* TabStripModelImpl::profile() const {
-  return profile_;
-}
-
-int TabStripModelImpl::active_index() const {
-  return selection_model_.active();
-}
-
-bool TabStripModelImpl::closing_all() const {
-  return closing_all_;
-}
-
-bool TabStripModelImpl::ContainsIndex(int index) const {
-  return index >= 0 && index < count();
-}
-
-void TabStripModelImpl::AppendWebContents(WebContents* contents,
-                                          bool foreground) {
-  InsertWebContentsAt(count(), contents,
-                      foreground ? (ADD_INHERIT_GROUP | ADD_ACTIVE) : ADD_NONE);
-}
-
-void TabStripModelImpl::InsertWebContentsAt(int index,
-                                            WebContents* contents,
-                                            int add_types) {
-  delegate()->WillAddWebContents(contents);
-
-  bool active = (add_types & ADD_ACTIVE) != 0;
-  bool pin = (add_types & ADD_PINNED) != 0;
-  index = ConstrainInsertionIndex(index, pin);
-
-  // In tab dragging situations, if the last tab in the window was detached
-  // then the user aborted the drag, we will have the |closing_all_| member
-  // set (see DetachWebContentsAt) which will mess with our mojo here. We need
-  // to clear this bit.
-  closing_all_ = false;
-
-  // Have to get the active contents before we monkey with the contents
-  // otherwise we run into problems when we try to change the active contents
-  // since the old contents and the new contents will be the same...
-  WebContents* active_contents = GetActiveWebContents();
-  std::unique_ptr<WebContentsData> data =
-      base::MakeUnique<WebContentsData>(this, contents);
-  data->set_pinned(pin);
-  if ((add_types & ADD_INHERIT_GROUP) && active_contents) {
-    if (active) {
-      // Forget any existing relationships, we don't want to make things too
-      // confusing by having multiple groups active at the same time.
-      ForgetAllOpeners();
-    }
-    // Anything opened by a link we deem to have an opener.
-    data->set_group(active_contents);
-    data->set_opener(active_contents);
-  } else if ((add_types & ADD_INHERIT_OPENER) && active_contents) {
-    if (active) {
-      // Forget any existing relationships, we don't want to make things too
-      // confusing by having multiple groups active at the same time.
-      ForgetAllOpeners();
-    }
-    data->set_opener(active_contents);
-  }
-
-  // TODO(gbillock): Ask the modal dialog manager whether the WebContents should
-  // be blocked, or just let the modal dialog manager make the blocking call
-  // directly and not use this at all.
-  const web_modal::WebContentsModalDialogManager* manager =
-      web_modal::WebContentsModalDialogManager::FromWebContents(contents);
-  if (manager)
-    data->set_blocked(manager->IsDialogActive());
-
-  contents_data_.insert(contents_data_.begin() + index, std::move(data));
-
-  selection_model_.IncrementFrom(index);
-
-  for (auto& observer : observers())
-    observer.TabInsertedAt(this, contents, index, active);
-
-  if (active) {
-    ui::ListSelectionModel new_model = selection_model_;
-    new_model.SetSelectedIndex(index);
-    SetSelection(std::move(new_model), Notify::kDefault);
-  }
-}
-
-WebContents* TabStripModelImpl::ReplaceWebContentsAt(
-    int index,
-    WebContents* new_contents) {
-  delegate()->WillAddWebContents(new_contents);
-
-  DCHECK(ContainsIndex(index));
-  WebContents* old_contents = GetWebContentsAtImpl(index);
-
-  FixOpenersAndGroupsReferencing(index);
-
-  contents_data_[index]->SetWebContents(new_contents);
-
-  for (auto& observer : observers())
-    observer.TabReplacedAt(this, old_contents, new_contents, index);
-
-  // When the active WebContents is replaced send out a selection notification
-  // too. We do this as nearly all observers need to treat a replacement of the
-  // selected contents as the selection changing.
-  if (active_index() == index) {
-    for (auto& observer : observers()) {
-      observer.ActiveTabChanged(old_contents, new_contents, active_index(),
-                                TabStripModelObserver::CHANGE_REASON_REPLACED);
-    }
-  }
-  return old_contents;
-}
-
-WebContents* TabStripModelImpl::DetachWebContentsAt(int index) {
-  CHECK(!in_notify_);
-  if (contents_data_.empty())
-    return nullptr;
-  DCHECK(ContainsIndex(index));
-
-  FixOpenersAndGroupsReferencing(index);
-
-  WebContents* removed_contents = GetWebContentsAtImpl(index);
-  bool was_selected = IsTabSelected(index);
-  int next_selected_index = order_controller_->DetermineNewSelectedIndex(index);
-  contents_data_.erase(contents_data_.begin() + index);
-  if (empty())
-    closing_all_ = true;
-  for (auto& observer : observers())
-    observer.TabDetachedAt(removed_contents, index);
-  if (empty()) {
-    selection_model_.Clear();
-    // TabDetachedAt() might unregister observers, so send |TabStripEmpty()| in
-    // a second pass.
-    for (auto& observer : observers())
-      observer.TabStripEmpty();
-  } else {
-    int old_active = active_index();
-    selection_model_.DecrementFrom(index);
-    ui::ListSelectionModel old_model;
-    old_model = selection_model_;
-    if (index == old_active) {
-      NotifyIfTabDeactivated(removed_contents);
-      if (!selection_model_.empty()) {
-        // The active tab was removed, but there is still something selected.
-        // Move the active and anchor to the first selected index.
-        selection_model_.set_active(selection_model_.selected_indices()[0]);
-        selection_model_.set_anchor(selection_model_.active());
-      } else {
-        // The active tab was removed and nothing is selected. Reset the
-        // selection and send out notification.
-        selection_model_.SetSelectedIndex(next_selected_index);
-      }
-      NotifyIfActiveTabChanged(removed_contents, Notify::kDefault);
-    }
-
-    // Sending notification in case the detached tab was selected. Using
-    // NotifyIfActiveOrSelectionChanged() here would not guarantee that a
-    // notification is sent even though the tab selection has changed because
-    // |old_model| is stored after calling DecrementFrom().
-    if (was_selected) {
-      for (auto& observer : observers())
-        observer.TabSelectionChanged(this, old_model);
-    }
-  }
-  return removed_contents;
-}
-
-void TabStripModelImpl::ActivateTabAt(int index, bool user_gesture) {
-  DCHECK(ContainsIndex(index));
-  ui::ListSelectionModel new_model = selection_model_;
-  new_model.SetSelectedIndex(index);
-  SetSelection(std::move(new_model),
-               user_gesture ? Notify::kUserGesture : Notify::kDefault);
-}
-
-void TabStripModelImpl::AddTabAtToSelection(int index) {
-  DCHECK(ContainsIndex(index));
-  ui::ListSelectionModel new_model = selection_model_;
-  new_model.AddIndexToSelection(index);
-  SetSelection(std::move(new_model), Notify::kDefault);
-}
-
-void TabStripModelImpl::MoveWebContentsAt(int index,
-                                          int to_position,
-                                          bool select_after_move) {
-  DCHECK(ContainsIndex(index));
-
-  // Ensure pinned and non-pinned tabs do not mix.
-  const int first_non_pinned_tab = IndexOfFirstNonPinnedTab();
-  to_position = IsTabPinned(index)
-                    ? std::min(first_non_pinned_tab - 1, to_position)
-                    : std::max(first_non_pinned_tab, to_position);
-  if (index == to_position)
-    return;
-
-  MoveWebContentsAtImpl(index, to_position, select_after_move);
-}
-
-void TabStripModelImpl::MoveSelectedTabsTo(int index) {
-  int total_pinned_count = IndexOfFirstNonPinnedTab();
-  int selected_pinned_count = 0;
-  int selected_count =
-      static_cast<int>(selection_model_.selected_indices().size());
-  for (int i = 0; i < selected_count &&
-                  IsTabPinned(selection_model_.selected_indices()[i]);
-       ++i) {
-    selected_pinned_count++;
-  }
-
-  // To maintain that all pinned tabs occur before non-pinned tabs we move them
-  // first.
-  if (selected_pinned_count > 0) {
-    MoveSelectedTabsToImpl(
-        std::min(total_pinned_count - selected_pinned_count, index), 0u,
-        selected_pinned_count);
-    if (index > total_pinned_count - selected_pinned_count) {
-      // We're being told to drag pinned tabs to an invalid location. Adjust the
-      // index such that non-pinned tabs end up at a location as though we could
-      // move the pinned tabs to index. See description in header for more
-      // details.
-      index += selected_pinned_count;
-    }
-  }
-  if (selected_pinned_count == selected_count)
-    return;
-
-  // Then move the non-pinned tabs.
-  MoveSelectedTabsToImpl(std::max(index, total_pinned_count),
-                         selected_pinned_count,
-                         selected_count - selected_pinned_count);
-}
-
-WebContents* TabStripModelImpl::GetActiveWebContents() const {
-  return GetWebContentsAt(active_index());
-}
-
-WebContents* TabStripModelImpl::GetWebContentsAt(int index) const {
-  if (ContainsIndex(index))
-    return GetWebContentsAtImpl(index);
-  return nullptr;
-}
-
-int TabStripModelImpl::GetIndexOfWebContents(
-    const WebContents* contents) const {
-  for (size_t i = 0; i < contents_data_.size(); ++i) {
-    if (contents_data_[i]->web_contents() == contents)
-      return i;
-  }
-  return kNoTab;
-}
-
-void TabStripModelImpl::UpdateWebContentsStateAt(int index,
-                                                 TabChangeType change_type) {
-  DCHECK(ContainsIndex(index));
-
-  for (auto& observer : observers())
-    observer.TabChangedAt(GetWebContentsAtImpl(index), index, change_type);
-}
-
-void TabStripModelImpl::SetTabNeedsAttentionAt(int index, bool attention) {
-  DCHECK(ContainsIndex(index));
-
-  for (auto& observer : observers())
-    observer.SetTabNeedsAttentionAt(index, attention);
-}
-
-void TabStripModelImpl::CloseAllTabs() {
-  // Set state so that observers can adjust their behavior to suit this
-  // specific condition when CloseWebContentsAt causes a flurry of
-  // Close/Detach/Select notifications to be sent.
-  closing_all_ = true;
-  std::vector<content::WebContents*> closing_tabs;
-  closing_tabs.reserve(count());
-  for (int i = count() - 1; i >= 0; --i)
-    closing_tabs.push_back(GetWebContentsAt(i));
-  InternalCloseTabs(closing_tabs, CLOSE_CREATE_HISTORICAL_TAB);
-}
-
-bool TabStripModelImpl::CloseWebContentsAt(int index, uint32_t close_types) {
-  DCHECK(ContainsIndex(index));
-  WebContents* contents = GetWebContentsAt(index);
-  return InternalCloseTabs(base::span<WebContents* const>(&contents, 1),
-                           close_types);
-}
-
-bool TabStripModelImpl::TabsAreLoading() const {
-  for (const auto& data : contents_data_) {
-    if (data->web_contents()->IsLoading())
-      return true;
-  }
-
-  return false;
-}
-
-WebContents* TabStripModelImpl::GetOpenerOfWebContentsAt(int index) {
-  DCHECK(ContainsIndex(index));
-  return contents_data_[index]->opener();
-}
-
-void TabStripModelImpl::SetOpenerOfWebContentsAt(int index,
-                                                 WebContents* opener) {
-  DCHECK(ContainsIndex(index));
-  // The TabStripModel only maintains the references to openers that it itself
-  // owns; trying to set an opener to an external WebContents can result in
-  // the opener being used after its freed. See crbug.com/698681.
-  DCHECK(!opener || GetIndexOfWebContents(opener) != kNoTab)
-      << "Cannot set opener to a web contents not owned by this tab strip.";
-  contents_data_[index]->set_opener(opener);
-}
-
-int TabStripModelImpl::GetIndexOfLastWebContentsOpenedBy(
-    const WebContents* opener,
-    int start_index) const {
-  DCHECK(opener);
-  DCHECK(ContainsIndex(start_index));
-
-  std::set<const WebContents*> opener_and_descendants;
-  opener_and_descendants.insert(opener);
-  int last_index = kNoTab;
-
-  for (int i = start_index + 1; i < count(); ++i) {
-    // Test opened by transitively, i.e. include tabs opened by tabs opened by
-    // opener, etc. Stop when we find the first non-descendant.
-    if (!opener_and_descendants.count(contents_data_[i]->opener())) {
-      // Skip over pinned tabs as new tabs are added after pinned tabs.
-      if (contents_data_[i]->pinned())
-        continue;
-      break;
-    }
-    opener_and_descendants.insert(contents_data_[i]->web_contents());
-    last_index = i;
-  }
-  return last_index;
-}
-
-void TabStripModelImpl::TabNavigating(WebContents* contents,
-                                      ui::PageTransition transition) {
-  if (ShouldForgetOpenersForTransition(transition)) {
-    // Don't forget the openers if this tab is a New Tab page opened at the
-    // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one
-    // navigation of one of these transition types before resetting the
-    // opener relationships (this allows for the use case of opening a new
-    // tab to do a quick look-up of something while viewing a tab earlier in
-    // the strip). We can make this heuristic more permissive if need be.
-    if (!IsNewTabAtEndOfTabStrip(contents)) {
-      // If the user navigates the current tab to another page in any way
-      // other than by clicking a link, we want to pro-actively forget all
-      // TabStrip opener relationships since we assume they're beginning a
-      // different task by reusing the current tab.
-      ForgetAllOpeners();
-      // In this specific case we also want to reset the group relationship,
-      // since it is now technically invalid.
-      ForgetGroup(contents);
-    }
-  }
-}
-
-void TabStripModelImpl::SetTabBlocked(int index, bool blocked) {
-  DCHECK(ContainsIndex(index));
-  if (contents_data_[index]->blocked() == blocked)
-    return;
-  contents_data_[index]->set_blocked(blocked);
-  for (auto& observer : observers())
-    observer.TabBlockedStateChanged(contents_data_[index]->web_contents(),
-                                    index);
-}
-
-void TabStripModelImpl::SetTabPinned(int index, bool pinned) {
-  DCHECK(ContainsIndex(index));
-  if (contents_data_[index]->pinned() == pinned)
-    return;
-
-  // The tab's position may have to change as the pinned tab state is changing.
-  int non_pinned_tab_index = IndexOfFirstNonPinnedTab();
-  contents_data_[index]->set_pinned(pinned);
-  if (pinned && index != non_pinned_tab_index) {
-    MoveWebContentsAtImpl(index, non_pinned_tab_index, false);
-    index = non_pinned_tab_index;
-  } else if (!pinned && index + 1 != non_pinned_tab_index) {
-    MoveWebContentsAtImpl(index, non_pinned_tab_index - 1, false);
-    index = non_pinned_tab_index - 1;
-  }
-
-  for (auto& observer : observers())
-    observer.TabPinnedStateChanged(this, contents_data_[index]->web_contents(),
-                                   index);
-}
-
-bool TabStripModelImpl::IsTabPinned(int index) const {
-  DCHECK(ContainsIndex(index));
-  return contents_data_[index]->pinned();
-}
-
-bool TabStripModelImpl::IsTabBlocked(int index) const {
-  return contents_data_[index]->blocked();
-}
-
-int TabStripModelImpl::IndexOfFirstNonPinnedTab() const {
-  for (size_t i = 0; i < contents_data_.size(); ++i) {
-    if (!IsTabPinned(static_cast<int>(i)))
-      return static_cast<int>(i);
-  }
-  // No pinned tabs.
-  return count();
-}
-
-void TabStripModelImpl::ExtendSelectionTo(int index) {
-  DCHECK(ContainsIndex(index));
-  ui::ListSelectionModel new_model = selection_model_;
-  new_model.SetSelectionFromAnchorTo(index);
-  SetSelection(std::move(new_model), Notify::kDefault);
-}
-
-void TabStripModelImpl::ToggleSelectionAt(int index) {
-  DCHECK(ContainsIndex(index));
-  ui::ListSelectionModel new_model = selection_model();
-  if (selection_model_.IsSelected(index)) {
-    if (selection_model_.size() == 1) {
-      // One tab must be selected and this tab is currently selected so we can't
-      // unselect it.
-      return;
-    }
-    new_model.RemoveIndexFromSelection(index);
-    new_model.set_anchor(index);
-    if (new_model.active() == index ||
-        new_model.active() == ui::ListSelectionModel::kUnselectedIndex)
-      new_model.set_active(new_model.selected_indices()[0]);
-  } else {
-    new_model.AddIndexToSelection(index);
-    new_model.set_anchor(index);
-    new_model.set_active(index);
-  }
-  SetSelection(std::move(new_model), Notify::kDefault);
-}
-
-void TabStripModelImpl::AddSelectionFromAnchorTo(int index) {
-  ui::ListSelectionModel new_model = selection_model_;
-  new_model.AddSelectionFromAnchorTo(index);
-  SetSelection(std::move(new_model), Notify::kDefault);
-}
-
-bool TabStripModelImpl::IsTabSelected(int index) const {
-  DCHECK(ContainsIndex(index));
-  return selection_model_.IsSelected(index);
-}
-
-void TabStripModelImpl::SetSelectionFromModel(ui::ListSelectionModel source) {
-  DCHECK_NE(ui::ListSelectionModel::kUnselectedIndex, source.active());
-  SetSelection(std::move(source), Notify::kDefault);
-}
-
-const ui::ListSelectionModel& TabStripModelImpl::selection_model() const {
-  return selection_model_;
-}
-
-void TabStripModelImpl::AddWebContents(WebContents* contents,
-                                       int index,
-                                       ui::PageTransition transition,
-                                       int add_types) {
-  // If the newly-opened tab is part of the same task as the parent tab, we want
-  // to inherit the parent's "group" attribute, so that if this tab is then
-  // closed we'll jump back to the parent tab.
-  bool inherit_group = (add_types & ADD_INHERIT_GROUP) == ADD_INHERIT_GROUP;
-
-  if (ui::PageTransitionTypeIncludingQualifiersIs(transition,
-                                                  ui::PAGE_TRANSITION_LINK) &&
-      (add_types & ADD_FORCE_INDEX) == 0) {
-    // We assume tabs opened via link clicks are part of the same task as their
-    // parent.  Note that when |force_index| is true (e.g. when the user
-    // drag-and-drops a link to the tab strip), callers aren't really handling
-    // link clicks, they just want to score the navigation like a link click in
-    // the history backend, so we don't inherit the group in this case.
-    index = order_controller_->DetermineInsertionIndex(transition,
-                                                       add_types & ADD_ACTIVE);
-    inherit_group = true;
-  } else {
-    // For all other types, respect what was passed to us, normalizing -1s and
-    // values that are too large.
-    if (index < 0 || index > count())
-      index = count();
-  }
-
-  if (ui::PageTransitionTypeIncludingQualifiersIs(transition,
-                                                  ui::PAGE_TRANSITION_TYPED) &&
-      index == count()) {
-    // Also, any tab opened at the end of the TabStrip with a "TYPED"
-    // transition inherit group as well. This covers the cases where the user
-    // creates a New Tab (e.g. Ctrl+T, or clicks the New Tab button), or types
-    // in the address bar and presses Alt+Enter. This allows for opening a new
-    // Tab to quickly look up something. When this Tab is closed, the old one
-    // is re-selected, not the next-adjacent.
-    inherit_group = true;
-  }
-  InsertWebContentsAt(index, contents,
-                      add_types | (inherit_group ? ADD_INHERIT_GROUP : 0));
-  // Reset the index, just in case insert ended up moving it on us.
-  index = GetIndexOfWebContents(contents);
-
-  if (inherit_group && ui::PageTransitionTypeIncludingQualifiersIs(
-                           transition, ui::PAGE_TRANSITION_TYPED))
-    contents_data_[index]->set_reset_group_on_select(true);
-
-  // TODO(sky): figure out why this is here and not in InsertWebContentsAt. When
-  // here we seem to get failures in startup perf tests.
-  // Ensure that the new WebContentsView begins at the same size as the
-  // previous WebContentsView if it existed.  Otherwise, the initial WebKit
-  // layout will be performed based on a width of 0 pixels, causing a
-  // very long, narrow, inaccurate layout.  Because some scripts on pages (as
-  // well as WebKit's anchor link location calculation) are run on the
-  // initial layout and not recalculated later, we need to ensure the first
-  // layout is performed with sane view dimensions even when we're opening a
-  // new background tab.
-  if (WebContents* old_contents = GetActiveWebContents()) {
-    if ((add_types & ADD_ACTIVE) == 0) {
-      ResizeWebContents(contents,
-                        gfx::Rect(old_contents->GetContainerBounds().size()));
-    }
-  }
-}
-
-void TabStripModelImpl::CloseSelectedTabs() {
-  InternalCloseTabs(
-      GetWebContentsesByIndices(selection_model_.selected_indices()),
-      CLOSE_CREATE_HISTORICAL_TAB | CLOSE_USER_GESTURE);
-}
-
-void TabStripModelImpl::SelectNextTab() {
-  SelectRelativeTab(true);
-}
-
-void TabStripModelImpl::SelectPreviousTab() {
-  SelectRelativeTab(false);
-}
-
-void TabStripModelImpl::SelectLastTab() {
-  ActivateTabAt(count() - 1, true);
-}
-
-void TabStripModelImpl::MoveTabNext() {
-  // TODO: this likely needs to be updated for multi-selection.
-  int new_index = std::min(active_index() + 1, count() - 1);
-  MoveWebContentsAt(active_index(), new_index, true);
-}
-
-void TabStripModelImpl::MoveTabPrevious() {
-  // TODO: this likely needs to be updated for multi-selection.
-  int new_index = std::max(active_index() - 1, 0);
-  MoveWebContentsAt(active_index(), new_index, true);
-}
-
-// Context menu functions.
-bool TabStripModelImpl::IsContextMenuCommandEnabled(
-    int context_index,
-    ContextMenuCommand command_id) const {
-  DCHECK(command_id > CommandFirst && command_id < CommandLast);
-  switch (command_id) {
-    case CommandNewTab:
-    case CommandCloseTab:
-      return true;
-
-    case CommandReload: {
-      std::vector<int> indices = GetIndicesForCommand(context_index);
-      for (size_t i = 0; i < indices.size(); ++i) {
-        WebContents* tab = GetWebContentsAt(indices[i]);
-        if (tab) {
-          CoreTabHelperDelegate* core_delegate =
-              CoreTabHelper::FromWebContents(tab)->delegate();
-          if (!core_delegate || core_delegate->CanReloadContents(tab))
-            return true;
-        }
-      }
-      return false;
-    }
-
-    case CommandCloseOtherTabs:
-    case CommandCloseTabsToRight:
-      return !GetIndicesClosedByCommand(context_index, command_id).empty();
-
-    case CommandDuplicate: {
-      std::vector<int> indices = GetIndicesForCommand(context_index);
-      for (size_t i = 0; i < indices.size(); ++i) {
-        if (delegate()->CanDuplicateContentsAt(indices[i]))
-          return true;
-      }
-      return false;
-    }
-
-    case CommandRestoreTab:
-      return delegate()->GetRestoreTabType() !=
-             TabStripModelDelegate::RESTORE_NONE;
-
-    case CommandToggleTabAudioMuted:
-    case CommandToggleSiteMuted: {
-      std::vector<int> indices = GetIndicesForCommand(context_index);
-      for (size_t i = 0; i < indices.size(); ++i) {
-        if (!chrome::CanToggleAudioMute(GetWebContentsAt(indices[i])))
-          return false;
-      }
-      return true;
-    }
-
-    case CommandBookmarkAllTabs:
-      return browser_defaults::bookmarks_enabled &&
-             delegate()->CanBookmarkAllTabs();
-
-    case CommandTogglePinned:
-    case CommandSelectByDomain:
-    case CommandSelectByOpener:
-      return true;
-
-    default:
-      NOTREACHED();
-  }
-  return false;
-}
-
-void TabStripModelImpl::ExecuteContextMenuCommand(
-    int context_index,
-    ContextMenuCommand command_id) {
-  DCHECK(command_id > CommandFirst && command_id < CommandLast);
-  switch (command_id) {
-    case CommandNewTab: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_NewTab"));
-      UMA_HISTOGRAM_ENUMERATION("Tab.NewTab",
-                                TabStripModelImpl::NEW_TAB_CONTEXT_MENU,
-                                TabStripModelImpl::NEW_TAB_ENUM_COUNT);
-      delegate()->AddTabAt(GURL(), context_index + 1, true);
-#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-      auto* new_tab_tracker =
-          feature_engagement::NewTabTrackerFactory::GetInstance()
-              ->GetForProfile(profile_);
-      new_tab_tracker->OnNewTabOpened();
-      new_tab_tracker->CloseBubble();
-#endif
-      break;
-    }
-
-    case CommandReload: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_Reload"));
-      std::vector<int> indices = GetIndicesForCommand(context_index);
-      for (size_t i = 0; i < indices.size(); ++i) {
-        WebContents* tab = GetWebContentsAt(indices[i]);
-        if (tab) {
-          CoreTabHelperDelegate* core_delegate =
-              CoreTabHelper::FromWebContents(tab)->delegate();
-          if (!core_delegate || core_delegate->CanReloadContents(tab))
-            tab->GetController().Reload(content::ReloadType::NORMAL, true);
-        }
-      }
-      break;
-    }
-
-    case CommandDuplicate: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_Duplicate"));
-      std::vector<int> indices = GetIndicesForCommand(context_index);
-      // Copy the WebContents off as the indices will change as tabs are
-      // duplicated.
-      std::vector<WebContents*> tabs;
-      for (size_t i = 0; i < indices.size(); ++i)
-        tabs.push_back(GetWebContentsAt(indices[i]));
-      for (size_t i = 0; i < tabs.size(); ++i) {
-        int index = GetIndexOfWebContents(tabs[i]);
-        if (index != -1 && delegate()->CanDuplicateContentsAt(index))
-          delegate()->DuplicateContentsAt(index);
-      }
-      break;
-    }
-
-    case CommandCloseTab: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_CloseTab"));
-      InternalCloseTabs(
-          GetWebContentsesByIndices(GetIndicesForCommand(context_index)),
-          CLOSE_CREATE_HISTORICAL_TAB | CLOSE_USER_GESTURE);
-      break;
-    }
-
-    case CommandCloseOtherTabs: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_CloseOtherTabs"));
-      InternalCloseTabs(GetWebContentsesByIndices(GetIndicesClosedByCommand(
-                            context_index, command_id)),
-                        CLOSE_CREATE_HISTORICAL_TAB);
-      break;
-    }
-
-    case CommandCloseTabsToRight: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_CloseTabsToRight"));
-      InternalCloseTabs(GetWebContentsesByIndices(GetIndicesClosedByCommand(
-                            context_index, command_id)),
-                        CLOSE_CREATE_HISTORICAL_TAB);
-      break;
-    }
-
-    case CommandRestoreTab: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_RestoreTab"));
-      delegate()->RestoreTab();
-      break;
-    }
-
-    case CommandTogglePinned: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_TogglePinned"));
-      std::vector<int> indices = GetIndicesForCommand(context_index);
-      bool pin = WillContextMenuPin(context_index);
-      if (pin) {
-        for (size_t i = 0; i < indices.size(); ++i)
-          SetTabPinned(indices[i], true);
-      } else {
-        // Unpin from the back so that the order is maintained (unpinning can
-        // trigger moving a tab).
-        for (size_t i = indices.size(); i > 0; --i)
-          SetTabPinned(indices[i - 1], false);
-      }
-      break;
-    }
-
-    case CommandToggleTabAudioMuted: {
-      const std::vector<int>& indices = GetIndicesForCommand(context_index);
-      const bool mute = WillContextMenuMute(context_index);
-      if (mute)
-        base::RecordAction(UserMetricsAction("TabContextMenu_MuteTabs"));
-      else
-        base::RecordAction(UserMetricsAction("TabContextMenu_UnmuteTabs"));
-      for (std::vector<int>::const_iterator i = indices.begin();
-           i != indices.end(); ++i) {
-        chrome::SetTabAudioMuted(GetWebContentsAt(*i), mute,
-                                 TabMutedReason::CONTEXT_MENU, std::string());
-      }
-      break;
-    }
-
-    case CommandToggleSiteMuted: {
-      const std::vector<int>& indices = GetIndicesForCommand(context_index);
-      const bool mute = WillContextMenuMuteSites(context_index);
-      if (mute) {
-        base::RecordAction(
-            UserMetricsAction("SoundContentSetting.MuteBy.TabStrip"));
-      } else {
-        base::RecordAction(
-            UserMetricsAction("SoundContentSetting.UnmuteBy.TabStrip"));
-      }
-      chrome::SetSitesMuted(*this, indices, mute);
-      break;
-    }
-
-    case CommandBookmarkAllTabs: {
-      base::RecordAction(UserMetricsAction("TabContextMenu_BookmarkAllTabs"));
-
-      delegate()->BookmarkAllTabs();
-      break;
-    }
-
-    case CommandSelectByDomain:
-    case CommandSelectByOpener: {
-      std::vector<int> indices;
-      if (command_id == CommandSelectByDomain)
-        GetIndicesWithSameDomain(context_index, &indices);
-      else
-        GetIndicesWithSameOpener(context_index, &indices);
-      ui::ListSelectionModel selection_model;
-      selection_model.SetSelectedIndex(context_index);
-      for (size_t i = 0; i < indices.size(); ++i)
-        selection_model.AddIndexToSelection(indices[i]);
-      SetSelectionFromModel(std::move(selection_model));
-      break;
-    }
-
-    default:
-      NOTREACHED();
-  }
-}
-
-std::vector<int> TabStripModelImpl::GetIndicesClosedByCommand(
-    int index,
-    ContextMenuCommand id) const {
-  DCHECK(ContainsIndex(index));
-  DCHECK(id == CommandCloseTabsToRight || id == CommandCloseOtherTabs);
-  bool is_selected = IsTabSelected(index);
-  int last_unclosed_tab = -1;
-  if (id == CommandCloseTabsToRight) {
-    last_unclosed_tab =
-        is_selected ? selection_model_.selected_indices().back() : index;
-  }
-
-  // NOTE: callers expect the vector to be sorted in descending order.
-  std::vector<int> indices;
-  for (int i = count() - 1; i > last_unclosed_tab; --i) {
-    if (i != index && !IsTabPinned(i) && (!is_selected || !IsTabSelected(i)))
-      indices.push_back(i);
-  }
-  return indices;
-}
-
-bool TabStripModelImpl::WillContextMenuMute(int index) {
-  std::vector<int> indices = GetIndicesForCommand(index);
-  return !chrome::AreAllTabsMuted(*this, indices);
-}
-
-bool TabStripModelImpl::WillContextMenuMuteSites(int index) {
-  return !chrome::AreAllSitesMuted(*this, GetIndicesForCommand(index));
-}
-
-bool TabStripModelImpl::WillContextMenuPin(int index) {
-  std::vector<int> indices = GetIndicesForCommand(index);
-  // If all tabs are pinned, then we unpin, otherwise we pin.
-  bool all_pinned = true;
-  for (size_t i = 0; i < indices.size() && all_pinned; ++i)
-    all_pinned = IsTabPinned(indices[i]);
-  return !all_pinned;
-}
-
-int TabStripModelImpl::GetIndexOfNextWebContentsOpenedBy(
-    const WebContents* opener,
-    int start_index,
-    bool use_group) const {
-  DCHECK(opener);
-  DCHECK(ContainsIndex(start_index));
-
-  // Check tabs after start_index first.
-  for (int i = start_index + 1; i < count(); ++i) {
-    if (OpenerMatches(contents_data_[i], opener, use_group))
-      return i;
-  }
-  // Then check tabs before start_index, iterating backwards.
-  for (int i = start_index - 1; i >= 0; --i) {
-    if (OpenerMatches(contents_data_[i], opener, use_group))
-      return i;
-  }
-  return kNoTab;
-}
-
-void TabStripModelImpl::ForgetAllOpeners() {
-  // Forget all opener memories so we don't do anything weird with tab
-  // re-selection ordering.
-  for (const auto& data : contents_data_)
-    data->set_opener(nullptr);
-}
-
-void TabStripModelImpl::ForgetGroup(WebContents* contents) {
-  int index = GetIndexOfWebContents(contents);
-  DCHECK(ContainsIndex(index));
-  contents_data_[index]->set_group(nullptr);
-  contents_data_[index]->set_opener(nullptr);
-}
-
-bool TabStripModelImpl::ShouldResetGroupOnSelect(WebContents* contents) const {
-  int index = GetIndexOfWebContents(contents);
-  DCHECK(ContainsIndex(index));
-  return contents_data_[index]->reset_group_on_select();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// TabStripModel, private:
-
-int TabStripModelImpl::ConstrainInsertionIndex(int index, bool pinned_tab) {
-  return pinned_tab
-             ? std::min(std::max(0, index), IndexOfFirstNonPinnedTab())
-             : std::min(count(), std::max(index, IndexOfFirstNonPinnedTab()));
-}
-
-std::vector<WebContents*> TabStripModelImpl::GetWebContentsFromIndices(
-    const std::vector<int>& indices) const {
-  std::vector<WebContents*> contents;
-  for (size_t i = 0; i < indices.size(); ++i)
-    contents.push_back(GetWebContentsAtImpl(indices[i]));
-  return contents;
-}
-
-void TabStripModelImpl::GetIndicesWithSameDomain(int index,
-                                                 std::vector<int>* indices) {
-  std::string domain = GetWebContentsAt(index)->GetURL().host();
-  if (domain.empty())
-    return;
-  for (int i = 0; i < count(); ++i) {
-    if (i == index)
-      continue;
-    if (GetWebContentsAt(i)->GetURL().host_piece() == domain)
-      indices->push_back(i);
-  }
-}
-
-void TabStripModelImpl::GetIndicesWithSameOpener(int index,
-                                                 std::vector<int>* indices) {
-  WebContents* opener = contents_data_[index]->group();
-  if (!opener) {
-    // If there is no group, find all tabs with the selected tab as the opener.
-    opener = GetWebContentsAt(index);
-    if (!opener)
-      return;
-  }
-  for (int i = 0; i < count(); ++i) {
-    if (i == index)
-      continue;
-    if (contents_data_[i]->group() == opener ||
-        GetWebContentsAtImpl(i) == opener) {
-      indices->push_back(i);
-    }
-  }
-}
-
-std::vector<int> TabStripModelImpl::GetIndicesForCommand(int index) const {
-  if (!IsTabSelected(index)) {
-    std::vector<int> indices;
-    indices.push_back(index);
-    return indices;
-  }
-  return selection_model_.selected_indices();
-}
-
-bool TabStripModelImpl::IsNewTabAtEndOfTabStrip(WebContents* contents) const {
-  const GURL& url = contents->GetURL();
-  return url.SchemeIs(content::kChromeUIScheme) &&
-         url.host_piece() == chrome::kChromeUINewTabHost &&
-         contents == GetWebContentsAtImpl(count() - 1) &&
-         contents->GetController().GetEntryCount() == 1;
-}
-
-std::vector<content::WebContents*> TabStripModelImpl::GetWebContentsesByIndices(
-    const std::vector<int>& indices) {
-  std::vector<content::WebContents*> items;
-  items.reserve(indices.size());
-  for (int index : indices)
-    items.push_back(GetWebContentsAtImpl(index));
-  return items;
-}
-
-bool TabStripModelImpl::InternalCloseTabs(
-    base::span<content::WebContents* const> items,
-    uint32_t close_types) {
-  if (items.empty())
-    return true;
-
-  const bool closing_all = static_cast<int>(items.size()) == count();
-  base::WeakPtr<TabStripModelImpl> ref = weak_factory_.GetWeakPtr();
-  if (closing_all) {
-    for (auto& observer : observers())
-      observer.WillCloseAllTabs();
-  }
-  const bool closed_all = CloseWebContentses(this, items, close_types);
-  if (!ref)
-    return closed_all;
-  if (closing_all && !closed_all) {
-    for (auto& observer : observers())
-      observer.CloseAllTabsCanceled();
-  }
-  return closed_all;
-}
-
-WebContents* TabStripModelImpl::GetWebContentsAtImpl(int index) const {
-  CHECK(ContainsIndex(index))
-      << "Failed to find: " << index << " in: " << count() << " entries.";
-  return contents_data_[index]->web_contents();
-}
-
-void TabStripModelImpl::NotifyIfTabDeactivated(WebContents* contents) {
-  if (contents) {
-    for (auto& observer : observers())
-      observer.TabDeactivated(contents);
-  }
-}
-
-void TabStripModelImpl::NotifyIfActiveTabChanged(WebContents* old_contents,
-                                                 Notify notify_types) {
-  WebContents* new_contents = GetWebContentsAtImpl(active_index());
-  if (old_contents == new_contents)
-    return;
-
-  int reason = notify_types == Notify::kUserGesture
-                   ? TabStripModelObserver::CHANGE_REASON_USER_GESTURE
-                   : TabStripModelObserver::CHANGE_REASON_NONE;
-  CHECK(!in_notify_);
-  in_notify_ = true;
-  for (auto& observer : observers()) {
-    observer.ActiveTabChanged(old_contents, new_contents, active_index(),
-                              reason);
-  }
-  in_notify_ = false;
-}
-
-void TabStripModelImpl::NotifyIfActiveOrSelectionChanged(
-    WebContents* old_contents,
-    Notify notify_types,
-    const ui::ListSelectionModel& old_model) {
-  NotifyIfActiveTabChanged(old_contents, notify_types);
-
-  if (selection_model() != old_model) {
-    for (auto& observer : observers())
-      observer.TabSelectionChanged(this, old_model);
-  }
-}
-
-void TabStripModelImpl::SetSelection(ui::ListSelectionModel new_model,
-                                     Notify notify_types) {
-  WebContents* old_contents = GetActiveWebContents();
-  ui::ListSelectionModel old_model;
-  old_model = selection_model_;
-  if (new_model.active() != selection_model_.active())
-    NotifyIfTabDeactivated(old_contents);
-  selection_model_ = new_model;
-  NotifyIfActiveOrSelectionChanged(old_contents, notify_types, old_model);
-}
-
-void TabStripModelImpl::SelectRelativeTab(bool next) {
-  // This may happen during automated testing or if a user somehow buffers
-  // many key accelerators.
-  if (contents_data_.empty())
-    return;
-
-  int index = active_index();
-  int delta = next ? 1 : -1;
-  index = (index + count() + delta) % count();
-  ActivateTabAt(index, true);
-}
-
-void TabStripModelImpl::MoveWebContentsAtImpl(int index,
-                                              int to_position,
-                                              bool select_after_move) {
-  FixOpenersAndGroupsReferencing(index);
-
-  std::unique_ptr<WebContentsData> moved_data =
-      std::move(contents_data_[index]);
-  WebContents* web_contents = moved_data->web_contents();
-  contents_data_.erase(contents_data_.begin() + index);
-  contents_data_.insert(contents_data_.begin() + to_position,
-                        std::move(moved_data));
-
-  selection_model_.Move(index, to_position, 1);
-  if (!selection_model_.IsSelected(to_position) && select_after_move) {
-    // TODO(sky): why doesn't this code notify observers?
-    selection_model_.SetSelectedIndex(to_position);
-  }
-
-  for (auto& observer : observers())
-    observer.TabMoved(web_contents, index, to_position);
-}
-
-void TabStripModelImpl::MoveSelectedTabsToImpl(int index,
-                                               size_t start,
-                                               size_t length) {
-  DCHECK(start < selection_model_.selected_indices().size() &&
-         start + length <= selection_model_.selected_indices().size());
-  size_t end = start + length;
-  int count_before_index = 0;
-  for (size_t i = start; i < end && selection_model_.selected_indices()[i] <
-                                        index + count_before_index;
-       ++i) {
-    count_before_index++;
-  }
-
-  // First move those before index. Any tabs before index end up moving in the
-  // selection model so we use start each time through.
-  int target_index = index + count_before_index;
-  size_t tab_index = start;
-  while (tab_index < end &&
-         selection_model_.selected_indices()[start] < index) {
-    MoveWebContentsAt(selection_model_.selected_indices()[start],
-                      target_index - 1, false);
-    tab_index++;
-  }
-
-  // Then move those after the index. These don't result in reordering the
-  // selection.
-  while (tab_index < end) {
-    if (selection_model_.selected_indices()[tab_index] != target_index) {
-      MoveWebContentsAt(selection_model_.selected_indices()[tab_index],
-                        target_index, false);
-    }
-    tab_index++;
-    target_index++;
-  }
-}
-
-// static
-bool TabStripModelImpl::OpenerMatches(
-    const std::unique_ptr<WebContentsData>& data,
-    const WebContents* opener,
-    bool use_group) {
-  return data->opener() == opener || (use_group && data->group() == opener);
-}
-
-void TabStripModelImpl::FixOpenersAndGroupsReferencing(int index) {
-  WebContents* old_contents = GetWebContentsAtImpl(index);
-  for (auto& data : contents_data_) {
-    if (data->group() == old_contents)
-      data->set_group(contents_data_[index]->group());
-    if (data->opener() == old_contents)
-      data->set_opener(contents_data_[index]->opener());
-  }
-}
diff --git a/chrome/browser/ui/tabs/tab_strip_model_impl.h b/chrome/browser/ui/tabs/tab_strip_model_impl.h
deleted file mode 100644
index eb2ccec..0000000
--- a/chrome/browser/ui/tabs/tab_strip_model_impl.h
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_IMPL_H_
-#define CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_IMPL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/containers/span.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "ui/base/models/list_selection_model.h"
-#include "ui/base/page_transition_types.h"
-
-class Profile;
-class TabStripModelDelegate;
-class TabStripModelOrderController;
-
-namespace content {
-class WebContents;
-}
-
-// Normal implementation of the TabStripModel interface.
-class TabStripModelImpl : public TabStripModel {
- public:
-  // Construct a TabStripModel with a delegate to help it do certain things
-  // (see the TabStripModelDelegate documentation). |delegate| cannot be NULL.
-  TabStripModelImpl(TabStripModelDelegate* delegate, Profile* profile);
-  ~TabStripModelImpl() override;
-
-  // TabStripModel implementation.
-  TabStripModelExperimental* AsTabStripModelExperimental() override;
-  int count() const override;
-  bool empty() const override;
-  Profile* profile() const override;
-  int active_index() const override;
-  bool closing_all() const override;
-  bool ContainsIndex(int index) const override;
-  void AppendWebContents(content::WebContents* contents,
-                         bool foreground) override;
-  void InsertWebContentsAt(int index,
-                           content::WebContents* contents,
-                           int add_types) override;
-  bool CloseWebContentsAt(int index, uint32_t close_types) override;
-  content::WebContents* ReplaceWebContentsAt(
-      int index,
-      content::WebContents* new_contents) override;
-  content::WebContents* DetachWebContentsAt(int index) override;
-  void ActivateTabAt(int index, bool user_gesture) override;
-  void AddTabAtToSelection(int index) override;
-  void MoveWebContentsAt(int index,
-                         int to_position,
-                         bool select_after_move) override;
-  void MoveSelectedTabsTo(int index) override;
-  content::WebContents* GetActiveWebContents() const override;
-  content::WebContents* GetWebContentsAt(int index) const override;
-  int GetIndexOfWebContents(
-      const content::WebContents* contents) const override;
-  void UpdateWebContentsStateAt(int index, TabChangeType change_type) override;
-  void SetTabNeedsAttentionAt(int index, bool attention) override;
-  void CloseAllTabs() override;
-  bool TabsAreLoading() const override;
-  content::WebContents* GetOpenerOfWebContentsAt(int index) override;
-  void SetOpenerOfWebContentsAt(int index,
-                                content::WebContents* opener) override;
-  int GetIndexOfLastWebContentsOpenedBy(const content::WebContents* opener,
-                                        int start_index) const override;
-  void TabNavigating(content::WebContents* contents,
-                     ui::PageTransition transition) override;
-  void SetTabBlocked(int index, bool blocked) override;
-  void SetTabPinned(int index, bool pinned) override;
-  bool IsTabPinned(int index) const override;
-  bool IsTabBlocked(int index) const override;
-  int IndexOfFirstNonPinnedTab() const override;
-  void ExtendSelectionTo(int index) override;
-  void ToggleSelectionAt(int index) override;
-  void AddSelectionFromAnchorTo(int index) override;
-  bool IsTabSelected(int index) const override;
-  void SetSelectionFromModel(ui::ListSelectionModel source) override;
-  const ui::ListSelectionModel& selection_model() const override;
-  void AddWebContents(content::WebContents* contents,
-                      int index,
-                      ui::PageTransition transition,
-                      int add_types) override;
-  void CloseSelectedTabs() override;
-  void SelectNextTab() override;
-  void SelectPreviousTab() override;
-  void SelectLastTab() override;
-  void MoveTabNext() override;
-  void MoveTabPrevious() override;
-  bool IsContextMenuCommandEnabled(
-      int context_index,
-      ContextMenuCommand command_id) const override;
-  void ExecuteContextMenuCommand(int context_index,
-                                 ContextMenuCommand command_id) override;
-  std::vector<int> GetIndicesClosedByCommand(int index, ContextMenuCommand id)
-      const override;
-  bool WillContextMenuMute(int index) override;
-  bool WillContextMenuMuteSites(int index) override;
-  bool WillContextMenuPin(int index) override;
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Ordering API
-  //
-  // These functions are used only by the TabStripModelOrderController which
-  // goes with this class (not the abstract base-class) so these do not need
-  // to be exposed in the general TabStripModel interface.
-
-  // Access the order controller. Exposed only for unit tests.
-  TabStripModelOrderController* order_controller() const {
-    return order_controller_.get();
-  }
-
-  // Returns the index of the next WebContents in the sequence of WebContentses
-  // spawned by the specified WebContents after |start_index|. If |use_group| is
-  // true, the group property of the tab is used instead of the opener to find
-  // the next tab. Under some circumstances the group relationship may exist but
-  // the opener may not.
-  int GetIndexOfNextWebContentsOpenedBy(const content::WebContents* opener,
-                                        int start_index,
-                                        bool use_group) const;
-
-  // Forget all Opener relationships that are stored (but _not_ group
-  // relationships!) This is to reduce unpredictable tab switching behavior
-  // in complex session states. The exact circumstances under which this method
-  // is called are left up to the implementation of the selected
-  // TabStripModelOrderController.
-  void ForgetAllOpeners();
-
-  // Forgets the group affiliation of the specified WebContents. This
-  // should be called when a WebContents that is part of a logical group
-  // of tabs is moved to a new logical context by the user (e.g. by typing a new
-  // URL or selecting a bookmark). This also forgets the opener, which is
-  // considered a weaker relationship than group.
-  void ForgetGroup(content::WebContents* contents);
-
-  // Returns true if the group/opener relationships present for |contents|
-  // should be reset when _any_ selection change occurs in the model.
-  bool ShouldResetGroupOnSelect(content::WebContents* contents) const;
-
- private:
-  class WebContentsData;
-
-  // Used when making selection notifications.
-  enum class Notify {
-    kDefault,
-
-    // The selection is changing from a user gesture.
-    kUserGesture,
-  };
-
-  int ConstrainInsertionIndex(int index, bool pinned_tab);
-
-  // Convenience for converting a vector of indices into a vector of
-  // WebContents.
-  std::vector<content::WebContents*> GetWebContentsFromIndices(
-      const std::vector<int>& indices) const;
-
-  // Gets the set of tab indices whose domain matches the tab at |index|.
-  void GetIndicesWithSameDomain(int index, std::vector<int>* indices);
-
-  // Gets the set of tab indices that have the same opener as the tab at
-  // |index|.
-  void GetIndicesWithSameOpener(int index, std::vector<int>* indices);
-
-  // If |index| is selected all the selected indices are returned, otherwise a
-  // vector with |index| is returned. This is used when executing commands to
-  // determine which indices the command applies to.
-  std::vector<int> GetIndicesForCommand(int index) const;
-
-  // Returns true if the specified WebContents is a New Tab at the end of
-  // the tabstrip. We check for this because opener relationships are _not_
-  // forgotten for the New Tab page opened as a result of a New Tab gesture
-  // (e.g. Ctrl+T, etc) since the user may open a tab transiently to look up
-  // something related to their current activity.
-  bool IsNewTabAtEndOfTabStrip(content::WebContents* contents) const;
-
-  // Closes the WebContentses at the specified indices. This causes the
-  // WebContentses to be destroyed, but it may not happen immediately. If
-  // the page in question has an unload event the WebContents will not be
-  // destroyed until after the event has completed, which will then call back
-  // into this method.
-  //
-  // Returns true if the WebContentses were closed immediately, false if we
-  // are waiting for the result of an onunload handler.
-  bool InternalCloseTabs(base::span<content::WebContents* const> items,
-                         uint32_t close_types);
-
-  // Gets the WebContents at an index. Does no bounds checking.
-  content::WebContents* GetWebContentsAtImpl(int index) const;
-
-  // Returns the WebContentses at the specified indices. This does no checking
-  // of the indices, it is assumed they are valid.
-  std::vector<content::WebContents*> GetWebContentsesByIndices(
-      const std::vector<int>& indices);
-
-  // Notifies the observers if the active tab is being deactivated.
-  void NotifyIfTabDeactivated(content::WebContents* contents);
-
-  // Notifies the observers if the active tab has changed.
-  void NotifyIfActiveTabChanged(content::WebContents* old_contents,
-                                Notify notify_types);
-
-  // Notifies the observers if the active tab or the tab selection has changed.
-  // |old_model| is a snapshot of |selection_model_| before the change.
-  // Note: This function might end up sending 0 to 2 notifications in the
-  // following order: ActiveTabChanged, TabSelectionChanged.
-  void NotifyIfActiveOrSelectionChanged(
-      content::WebContents* old_contents,
-      Notify notify_types,
-      const ui::ListSelectionModel& old_model);
-
-  // Sets the selection to |new_model| and notifies any observers.
-  // Note: This function might end up sending 0 to 3 notifications in the
-  // following order: TabDeactivated, ActiveTabChanged, TabSelectionChanged.
-  void SetSelection(ui::ListSelectionModel new_model, Notify notify_types);
-
-  // Selects either the next tab (|forward| is true), or the previous tab
-  // (|forward| is false).
-  void SelectRelativeTab(bool forward);
-
-  // Does the work of MoveWebContentsAt. This has no checks to make sure the
-  // position is valid, those are done in MoveWebContentsAt.
-  void MoveWebContentsAtImpl(int index,
-                             int to_position,
-                             bool select_after_move);
-
-  // Implementation of MoveSelectedTabsTo. Moves |length| of the selected tabs
-  // starting at |start| to |index|. See MoveSelectedTabsTo for more details.
-  void MoveSelectedTabsToImpl(int index, size_t start, size_t length);
-
-  // Returns true if the tab represented by the specified data has an opener
-  // that matches the specified one. If |use_group| is true, then this will
-  // fall back to check the group relationship as well.
-  static bool OpenerMatches(const std::unique_ptr<WebContentsData>& data,
-                            const content::WebContents* opener,
-                            bool use_group);
-
-  // Sets the group/opener of any tabs that reference the tab at |index| to that
-  // tab's group/opener respectively.
-  void FixOpenersAndGroupsReferencing(int index);
-
-  // The WebContents data currently hosted within this TabStripModel.
-  std::vector<std::unique_ptr<WebContentsData>> contents_data_;
-
-  // A profile associated with this TabStripModel.
-  Profile* profile_;
-
-  // True if all tabs are currently being closed via CloseAllTabs.
-  bool closing_all_ = false;
-
-  // An object that determines where new Tabs should be inserted and where
-  // selection should move when a Tab is closed.
-  std::unique_ptr<TabStripModelOrderController> order_controller_;
-
-  ui::ListSelectionModel selection_model_;
-
-  // Indicates if observers are currently being notified to catch reentrancy
-  // bugs. See for example http://crbug.com/529407
-  bool in_notify_ = false;
-
-  base::WeakPtrFactory<TabStripModelImpl> weak_factory_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(TabStripModelImpl);
-};
-
-#endif  // CHROME_BROWSER_UI_TABS_TAB_STRIP_MODEL_IMPL_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_model_order_controller.cc b/chrome/browser/ui/tabs/tab_strip_model_order_controller.cc
index 2017f9a..1da2ade1 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_order_controller.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_order_controller.cc
@@ -4,14 +4,14 @@
 
 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
 
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/web_contents.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 // TabStripModelOrderController, public:
 
 TabStripModelOrderController::TabStripModelOrderController(
-    TabStripModelImpl* tabstrip)
+    TabStripModel* tabstrip)
     : tabstrip_(tabstrip) {
   tabstrip_->AddObserver(this);
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model_order_controller.h b/chrome/browser/ui/tabs/tab_strip_model_order_controller.h
index de59ee08..11a355b 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_order_controller.h
+++ b/chrome/browser/ui/tabs/tab_strip_model_order_controller.h
@@ -9,7 +9,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "ui/base/page_transition_types.h"
 
-class TabStripModelImpl;
+class TabStripModel;
 
 ///////////////////////////////////////////////////////////////////////////////
 // TabStripModelOrderController
@@ -19,7 +19,7 @@
 //
 class TabStripModelOrderController : public TabStripModelObserver {
  public:
-  explicit TabStripModelOrderController(TabStripModelImpl* tabstrip);
+  explicit TabStripModelOrderController(TabStripModel* tabstrip);
   ~TabStripModelOrderController() override;
 
   // Determine where to place a newly opened tab by using the supplied
@@ -42,7 +42,7 @@
   // reflect the fact that |removing_index| is going away.
   int GetValidIndex(int index, int removing_index) const;
 
-  TabStripModelImpl* tabstrip_;
+  TabStripModel* tabstrip_;
 
   DISALLOW_COPY_AND_ASSIGN(TabStripModelOrderController);
 };
diff --git a/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc
index 0e88f1a8b..7af822c7 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/macros.h"
 #include "base/test/histogram_tester.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -36,7 +36,7 @@
 
 TEST_F(TabStripModelStatsRecorderTest, BasicTabLifecycle) {
   NoUnloadListenerTabStripModelDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
 
   TabStripModelStatsRecorder recorder;
   tabstrip.AddObserver(&recorder);
@@ -94,8 +94,8 @@
 
 TEST_F(TabStripModelStatsRecorderTest, ObserveMultipleTabStrips) {
   NoUnloadListenerTabStripModelDelegate delegate;
-  TabStripModelImpl tabstrip1(&delegate, profile());
-  TabStripModelImpl tabstrip2(&delegate, profile());
+  TabStripModel tabstrip1(&delegate, profile());
+  TabStripModel tabstrip2(&delegate, profile());
 
   TabStripModelStatsRecorder recorder;
   tabstrip1.AddObserver(&recorder);
@@ -163,7 +163,7 @@
 TEST_F(TabStripModelStatsRecorderTest,
        NumberOfOtherTabsActivatedBeforeMadeActive) {
   NoUnloadListenerTabStripModelDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
 
   TabStripModelStatsRecorder recorder;
   tabstrip.AddObserver(&recorder);
@@ -193,7 +193,7 @@
 TEST_F(TabStripModelStatsRecorderTest,
        NumberOfOtherTabsActivatedBeforeMadeActive_CycleTabs) {
   NoUnloadListenerTabStripModelDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
 
   TabStripModelStatsRecorder recorder;
   tabstrip.AddObserver(&recorder);
diff --git a/chrome/browser/ui/tabs/tab_strip_model_impl_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
similarity index 97%
rename from chrome/browser/ui/tabs/tab_strip_model_impl_unittest.cc
rename to chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 6d0b66a..26e16e0b 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_impl_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.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/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 
 #include <stddef.h>
 
@@ -425,7 +425,7 @@
 
 TEST_F(TabStripModelTest, TestBasicAPI) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   MockTabStripModelObserver observer(&tabstrip);
   tabstrip.AddObserver(&observer);
 
@@ -661,7 +661,7 @@
 
 TEST_F(TabStripModelTest, TestBasicOpenerAPI) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // This is a basic test of opener functionality. opener is created
@@ -734,12 +734,12 @@
   EXPECT_TRUE(tabstrip.empty());
 }
 
-static int GetInsertionIndex(TabStripModelImpl* tabstrip) {
+static int GetInsertionIndex(TabStripModel* tabstrip) {
   return tabstrip->order_controller()->DetermineInsertionIndex(
       ui::PAGE_TRANSITION_LINK, false);
 }
 
-static void InsertWebContentses(TabStripModelImpl* tabstrip,
+static void InsertWebContentses(TabStripModel* tabstrip,
                                 WebContents* contents1,
                                 WebContents* contents2,
                                 WebContents* contents3) {
@@ -754,7 +754,7 @@
 // Tests opening background tabs.
 TEST_F(TabStripModelTest, TestLTRInsertionOptions) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   WebContents* opener = CreateWebContents();
@@ -782,7 +782,7 @@
 // end of the strip, not bundled to any existing context.
 TEST_F(TabStripModelTest, TestInsertionIndexDetermination) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   WebContents* opener = CreateWebContents();
@@ -854,7 +854,7 @@
 // to position tabs.
 TEST_F(TabStripModelTest, TestInsertionIndexDeterminationAfterDragged) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Start with three tabs, of which the first is active.
@@ -905,7 +905,7 @@
 // tab when deciding where to position tabs.
 TEST_F(TabStripModelTest, TestInsertionIndexDeterminationNestedOpener) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Start with two tabs, of which the first is active:
@@ -981,7 +981,7 @@
 //
 TEST_F(TabStripModelTest, TestSelectOnClose) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   WebContents* opener = CreateWebContents();
@@ -1056,7 +1056,7 @@
 // CommandCloseTab.
 TEST_F(TabStripModelTest, CommandCloseTab) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Make sure can_close is honored.
@@ -1107,7 +1107,7 @@
 // CommandCloseTabs.
 TEST_F(TabStripModelTest, CommandCloseOtherTabs) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Create three tabs, select two tabs, CommandCloseOtherTabs should be enabled
@@ -1169,7 +1169,7 @@
 // CommandCloseTabsToRight.
 TEST_F(TabStripModelTest, CommandCloseTabsToRight) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Create three tabs, select last two tabs, CommandCloseTabsToRight should
@@ -1192,7 +1192,7 @@
 // CommandTogglePinned.
 TEST_F(TabStripModelTest, CommandTogglePinned) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Create three tabs with one pinned, pin the first two.
@@ -1225,7 +1225,7 @@
 //  - Close Tabs To Right
 TEST_F(TabStripModelTest, TestContextMenuCloseCommands) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   WebContents* opener = CreateWebContents();
@@ -1270,7 +1270,7 @@
 // Tests GetIndicesClosedByCommand.
 TEST_F(TabStripModelTest, GetIndicesClosedByCommand) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   WebContents* contents1 = CreateWebContents();
@@ -1320,7 +1320,7 @@
 // of links on the home page.
 TEST_F(TabStripModelTest, AddWebContents_MiddleClickLinksAndClose) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Open the Home Page.
@@ -1386,7 +1386,7 @@
 // it.
 TEST_F(TabStripModelTest, AddWebContents_LeftClickPopup) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Open the Home Page.
@@ -1435,7 +1435,7 @@
 // in the middle.
 TEST_F(TabStripModelTest, AddWebContents_CreateNewBlankTab) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Open the Home Page.
@@ -1488,7 +1488,7 @@
 // context.
 TEST_F(TabStripModelTest, AddWebContents_ForgetOpeners) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Open the Home Page
@@ -1549,7 +1549,7 @@
 // Added for http://b/issue?id=958960
 TEST_F(TabStripModelTest, AppendContentsReselectionTest) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   EXPECT_TRUE(tabstrip.empty());
 
   // Open the Home Page.
@@ -1581,7 +1581,7 @@
 // Added for http://b/issue?id=1027661
 TEST_F(TabStripModelTest, ReselectionConsidersChildrenTest) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   // Open page A
   WebContents* page_a_contents = CreateWebContents();
@@ -1631,7 +1631,7 @@
 
 TEST_F(TabStripModelTest, AddWebContents_NewTabAtEndOfStripInheritsGroup) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   // Open page A
   WebContents* page_a_contents = CreateWebContents();
@@ -1707,7 +1707,7 @@
 // not preserved.
 TEST_F(TabStripModelTest, NavigationForgetsOpeners) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   // Open page A
   WebContents* page_a_contents = CreateWebContents();
@@ -1755,7 +1755,7 @@
 // selected (Test 2 below).
 TEST_F(TabStripModelTest, NavigationForgettingDoesntAffectNewTab) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   // Open a tab and several tabs from it, then select one of the tabs that was
   // opened.
@@ -1821,7 +1821,7 @@
 // Tests that fast shutdown is attempted appropriately.
 TEST_F(TabStripModelTest, MAYBE_FastShutdown) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   MockTabStripModelObserver observer(&tabstrip);
   tabstrip.AddObserver(&observer);
 
@@ -1879,7 +1879,7 @@
 // Tests various permutations of pinning tabs.
 TEST_F(TabStripModelTest, Pinning) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl tabstrip(&delegate, profile());
+  TabStripModel tabstrip(&delegate, profile());
   MockTabStripModelObserver observer(&tabstrip);
   tabstrip.AddObserver(&observer);
 
@@ -2041,7 +2041,7 @@
   typedef MockTabStripModelObserver::State State;
 
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   WebContents* first_contents = CreateWebContents();
   strip.AddWebContents(first_contents, -1, ui::PAGE_TRANSITION_TYPED,
@@ -2091,7 +2091,7 @@
 // another tab.
 TEST_F(TabStripModelTest, DeleteFromDestroy) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
   WebContents* contents1 = CreateWebContents();
   WebContents* contents2 = CreateWebContents();
   MockTabStripModelObserver tab_strip_model_observer(&strip);
@@ -2116,7 +2116,7 @@
 // TabStrip while removing another tab.
 TEST_F(TabStripModelTest, DeleteTabStripFromDestroy) {
   TabStripDummyDelegate delegate;
-  TabStripModel* strip = new TabStripModelImpl(&delegate, profile());
+  TabStripModel* strip = new TabStripModel(&delegate, profile());
   MockTabStripModelObserver tab_strip_model_observer(strip);
   strip->AddObserver(&tab_strip_model_observer);
   WebContents* contents1 = CreateWebContents();
@@ -2134,7 +2134,7 @@
 // MoveWebContentsAt.
 TEST_F(TabStripModelTest, MoveWebContentsAtWithPinned) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
   ASSERT_NO_FATAL_FAILURE(PrepareTabstripForSelectionTest(&strip, 6, 3, "0"));
   EXPECT_EQ("0p 1p 2p 3 4 5", GetTabStripStateString(strip));
 
@@ -2211,7 +2211,7 @@
 
   for (size_t i = 0; i < arraysize(test_data); ++i) {
     TabStripDummyDelegate delegate;
-    TabStripModelImpl strip(&delegate, profile());
+    TabStripModel strip(&delegate, profile());
     ASSERT_NO_FATAL_FAILURE(PrepareTabstripForSelectionTest(
         &strip, test_data[i].tab_count, test_data[i].pinned_count,
         test_data[i].selected_tabs));
@@ -2225,7 +2225,7 @@
 // Tests that moving a tab forgets all groups referencing it.
 TEST_F(TabStripModelTest, MoveSelectedTabsTo_ForgetGroups) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   // Open page A as a new tab and then A1 in the background from A.
   WebContents* page_a_contents = CreateWebContents();
@@ -2281,7 +2281,7 @@
 
 TEST_F(TabStripModelTest, CloseSelectedTabs) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
   WebContents* contents1 = CreateWebContents();
   WebContents* contents2 = CreateWebContents();
   WebContents* contents3 = CreateWebContents();
@@ -2299,7 +2299,7 @@
   typedef MockTabStripModelObserver::State State;
 
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
   MockTabStripModelObserver observer(&strip);
   WebContents* contents0 = CreateWebContents();
   WebContents* contents1 = CreateWebContents();
@@ -2399,7 +2399,7 @@
   typedef MockTabStripModelObserver::State State;
 
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
   WebContents* contents1 = CreateWebContents();
   WebContents* contents2 = CreateWebContents();
   strip.AppendWebContents(contents1, false);
@@ -2427,7 +2427,7 @@
 TEST_F(TabStripModelTest, TabBlockedState) {
   // Start with a source tab strip.
   TabStripDummyDelegate dummy_tab_strip_delegate;
-  TabStripModelImpl strip_src(&dummy_tab_strip_delegate, profile());
+  TabStripModel strip_src(&dummy_tab_strip_delegate, profile());
   TabBlockedStateTestBrowser browser_src(&strip_src);
 
   // Add a tab.
@@ -2441,7 +2441,7 @@
   strip_src.AppendWebContents(contents2, false);
 
   // Create a destination tab strip.
-  TabStripModelImpl strip_dst(&dummy_tab_strip_delegate, profile());
+  TabStripModel strip_dst(&dummy_tab_strip_delegate, profile());
   TabBlockedStateTestBrowser browser_dst(&strip_dst);
 
   // Setup a SingleWebContentsDialogManager for tab |contents2|.
@@ -2476,7 +2476,7 @@
 // subsequent pinned tab.
 TEST_F(TabStripModelTest, LinkClicksWithPinnedTabOrdering) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
 
   // Open two pages, pinned.
   WebContents* page_a_contents = CreateWebContents();
@@ -2508,7 +2508,7 @@
 // select_after_move (as an int) was selected rather than |to_position|.
 TEST_F(TabStripModelTest, MoveWebContentsAt) {
   TabStripDummyDelegate delegate;
-  TabStripModelImpl strip(&delegate, profile());
+  TabStripModel strip(&delegate, profile());
   MockTabStripModelObserver observer(&strip);
   strip.AppendWebContents(CreateWebContents(), false);
   strip.AppendWebContents(CreateWebContents(), false);
diff --git a/chrome/browser/ui/tabs/tab_ukm_test_helper.cc b/chrome/browser/ui/tabs/tab_ukm_test_helper.cc
new file mode 100644
index 0000000..6eb9648
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_ukm_test_helper.cc
@@ -0,0 +1,163 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/tabs/tab_ukm_test_helper.h"
+
+#include "chrome/test/base/testing_profile.h"
+#include "components/ukm/ukm_source.h"
+#include "content/public/test/web_contents_tester.h"
+#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+
+using content::WebContentsTester;
+
+// Helper class to respond to WebContents lifecycle events we can't
+// trigger/simulate.
+class TestWebContentsObserver : public content::WebContentsObserver {
+ public:
+  explicit TestWebContentsObserver(content::WebContents* web_contents);
+
+  // content::WebContentsObserver:
+  void WebContentsDestroyed() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
+};
+
+TestWebContentsObserver::TestWebContentsObserver(
+    content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents) {}
+
+void TestWebContentsObserver::WebContentsDestroyed() {
+  // Simulate the WebContents hiding during destruction. This lets tests
+  // validate what is logged when a tab is destroyed.
+  web_contents()->WasHidden();
+}
+
+TabActivityTestBase::TabActivityTestBase() = default;
+TabActivityTestBase::~TabActivityTestBase() = default;
+
+content::WebContents* TabActivityTestBase::AddWebContentsAndNavigate(
+    TabStripModel* tab_strip_model,
+    const GURL& initial_url) {
+  content::WebContents::CreateParams params(profile(), nullptr);
+  // Create as a background tab if there are other tabs in the tab strip.
+  params.initially_hidden = tab_strip_model->count() > 0;
+  content::WebContents* test_contents =
+      WebContentsTester::CreateTestWebContents(params);
+
+  // Create the TestWebContentsObserver to observe |test_contents|. When the
+  // WebContents is destroyed, the observer will be reset automatically.
+  observers_.push_back(
+      std::make_unique<TestWebContentsObserver>(test_contents));
+
+  tab_strip_model->AppendWebContents(test_contents, false);
+  WebContentsTester::For(test_contents)->NavigateAndCommit(initial_url);
+  return test_contents;
+}
+
+void TabActivityTestBase::SwitchToTabAt(TabStripModel* tab_strip_model,
+                                        int new_index) {
+  int active_index = tab_strip_model->active_index();
+  EXPECT_NE(new_index, active_index);
+
+  content::WebContents* active_contents =
+      tab_strip_model->GetWebContentsAt(active_index);
+  ASSERT_TRUE(active_contents);
+  content::WebContents* new_contents =
+      tab_strip_model->GetWebContentsAt(new_index);
+  ASSERT_TRUE(new_contents);
+
+  // Activate the tab. Normally this would hide the active tab's aura::Window,
+  // which is what actually triggers TabActivityWatcher to log the change. For
+  // a TestWebContents, we must manually call WasHidden(), and do the reverse
+  // for the newly activated tab.
+  tab_strip_model->ActivateTabAt(new_index, true /* user_gesture */);
+  active_contents->WasHidden();
+  new_contents->WasShown();
+}
+
+UkmEntryChecker::UkmEntryChecker() = default;
+UkmEntryChecker::~UkmEntryChecker() = default;
+
+void UkmEntryChecker::ExpectNewEntry(const std::string& entry_name,
+                                     const GURL& source_url,
+                                     const UkmMetricMap& expected_metrics) {
+  num_entries_[entry_name]++;  // There should only be 1 more entry than before.
+  std::vector<const ukm::mojom::UkmEntry*> entries =
+      ukm_recorder_.GetEntriesByName(entry_name);
+  EXPECT_EQ(NumEntries(entry_name), entries.size());
+
+  // Verify the entry is associated with the correct URL.
+  const ukm::mojom::UkmEntry* entry = entries.back();
+  if (!source_url.is_empty())
+    ukm_recorder_.ExpectEntrySourceHasUrl(entry, source_url);
+
+  // Each expected metric should match a named value in the UKM entry.
+  for (const std::pair<const char*, uint64_t>& pair : expected_metrics)
+    ukm::TestUkmRecorder::ExpectEntryMetric(entry, pair.first, pair.second);
+}
+
+void UkmEntryChecker::ExpectNewEntries(
+    const std::string& entry_name,
+    const SourceUkmMetricMap& expected_data) {
+  std::vector<const ukm::mojom::UkmEntry*> entries =
+      ukm_recorder_.GetEntriesByName(entry_name);
+
+  const size_t num_new_entries = expected_data.size();
+  const size_t num_entries = entries.size();
+  num_entries_[entry_name] += num_new_entries;
+
+  EXPECT_EQ(NumEntries(entry_name), entries.size());
+  std::set<ukm::SourceId> found_source_ids;
+
+  for (size_t i = 0; i < num_new_entries; ++i) {
+    const ukm::mojom::UkmEntry* entry =
+        entries[num_entries - num_new_entries + i];
+    const ukm::SourceId& source_id = entry->source_id;
+    const auto& expected_data_for_id = expected_data.find(source_id);
+    EXPECT_TRUE(expected_data_for_id != expected_data.end());
+    EXPECT_EQ(0u, found_source_ids.count(source_id));
+
+    found_source_ids.insert(source_id);
+    const std::pair<GURL, UkmMetricMap>& expected_url_metrics =
+        expected_data_for_id->second;
+
+    const GURL& source_url = expected_url_metrics.first;
+    const UkmMetricMap& expected_metrics = expected_url_metrics.second;
+    if (!source_url.is_empty())
+      ukm_recorder_.ExpectEntrySourceHasUrl(entry, source_url);
+
+    // Each expected metric should match a named value in the UKM entry.
+    for (const std::pair<const char*, uint64_t>& pair : expected_metrics)
+      ukm::TestUkmRecorder::ExpectEntryMetric(entry, pair.first, pair.second);
+  }
+}
+
+int UkmEntryChecker::NumNewEntriesRecorded(
+    const std::string& entry_name) const {
+  const size_t current_ukm_entries =
+      ukm_recorder_.GetEntriesByName(entry_name).size();
+  const size_t previous_num_entries = NumEntries(entry_name);
+  CHECK(current_ukm_entries >= previous_num_entries);
+  return current_ukm_entries - previous_num_entries;
+}
+
+size_t UkmEntryChecker::NumEntries(const std::string& entry_name) const {
+  const auto it = num_entries_.find(entry_name);
+  return it != num_entries_.end() ? it->second : 0;
+}
+
+const ukm::mojom::UkmEntry* UkmEntryChecker::LastUkmEntry(
+    const std::string& entry_name) const {
+  std::vector<const ukm::mojom::UkmEntry*> entries =
+      ukm_recorder_.GetEntriesByName(entry_name);
+  CHECK(!entries.empty());
+  return entries.back();
+}
+
+ukm::SourceId UkmEntryChecker::GetSourceIdForUrl(const GURL& source_url) const {
+  const ukm::UkmSource* source = ukm_recorder_.GetSourceForUrl(source_url);
+  CHECK(source);
+  return source->id();
+}
diff --git a/chrome/browser/ui/tabs/tab_ukm_test_helper.h b/chrome/browser/ui/tabs/tab_ukm_test_helper.h
new file mode 100644
index 0000000..ddf08ec9
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_ukm_test_helper.h
@@ -0,0 +1,102 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TABS_TAB_UKM_TEST_HELPER_H_
+#define CHROME_BROWSER_UI_TABS_TAB_UKM_TEST_HELPER_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "content/public/browser/web_contents.h"
+
+using UkmMetricMap = std::map<const char*, int64_t>;
+using SourceUkmMetricMap =
+    std::map<ukm::SourceId, std::pair<GURL, UkmMetricMap>>;
+
+class TestWebContentsObserver;
+
+// Base class for tests that rely on logging tab activity. Inherits from
+// ChromeRenderViewHostTestHarness to use TestWebContents and Profile.
+class TabActivityTestBase : public ChromeRenderViewHostTestHarness {
+ public:
+  TabActivityTestBase();
+  ~TabActivityTestBase() override;
+
+  // Creates a new WebContents suitable for testing, adds it to the tab strip
+  // and commits a navigation to |initial_url|. The WebContents is owned by the
+  // TabStripModel, so its tab must be closed later, e.g. via CloseAllTabs().
+  content::WebContents* AddWebContentsAndNavigate(
+      TabStripModel* tab_strip_model,
+      const GURL& initial_url);
+
+  // Sets |new_index| as the active tab in its tab strip, hiding the previously
+  // active tab.
+  void SwitchToTabAt(TabStripModel* tab_strip_model, int new_index);
+
+ private:
+  // Owns the observers we've created.
+  std::vector<std::unique_ptr<TestWebContentsObserver>> observers_;
+  DISALLOW_COPY_AND_ASSIGN(TabActivityTestBase);
+};
+
+// Helper class to check entries have been logged as expected into UKM.
+class UkmEntryChecker {
+ public:
+  UkmEntryChecker();
+  ~UkmEntryChecker();
+
+  // Expects that exactly one entry has been recorded for |entry_name|, and that
+  // it matches the values and the given URL if |source_url| is none empty.
+  // Use this function when there's exactly one entry logged when some event
+  // happens.
+  // This function increments |num_entries_[entry_name]| by 1 and checks
+  // the new value of |num_entries_[entry_name]| is the same as number of
+  // entries in ukm.
+  void ExpectNewEntry(const std::string& entry_name,
+                      const GURL& source_url,
+                      const UkmMetricMap& expected_metrics);
+
+  // Expects that |expected_data.size()| number of entries have been recorded
+  // for |entry_name|. For each recorded entry (as identified by its source id),
+  // checks the values and the given URL if url is none empty.
+  // Use this function when there're multiple entries logged when an event
+  // happens. We use source ids to identify multiple entries.
+  // This function increments |num_entries_[entry_name]| by the size of
+  // |expected_data| and checks the new value of |num_entries_[entry_name]| is
+  // the same as number of entries in ukm.
+  void ExpectNewEntries(const std::string& entry_name,
+                        const SourceUkmMetricMap& expected_data);
+
+  // Returns number of new entries that have been recorded for |entry_name|.
+  // It is the difference between number of entries in ukm and that recorded by
+  // |num_entries_|.
+  int NumNewEntriesRecorded(const std::string& entry_name) const;
+
+  // Returns number of entries for |entry_name|.
+  size_t NumEntries(const std::string& entry_name) const;
+
+  // Returns the last recorded entry for |entry_name|.
+  const ukm::mojom::UkmEntry* LastUkmEntry(const std::string& entry_name) const;
+
+  ukm::SourceId GetSourceIdForUrl(const GURL& source_url) const;
+
+ private:
+  ukm::TestAutoSetUkmRecorder ukm_recorder_;
+
+  // Keyed by entry name, and tracks the expected number of entries to ensure we
+  // don't log duplicate or incorrect entries.
+  // |num_entries_| records number of entries up to last time we call
+  // ExpectNewEntry or ExpectNewEntries.
+  std::map<std::string, size_t> num_entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(UkmEntryChecker);
+};
+
+#endif  // CHROME_BROWSER_UI_TABS_TAB_UKM_TEST_HELPER_H_
diff --git a/chrome/browser/ui/tabs/web_contents_closer.cc b/chrome/browser/ui/tabs/web_contents_closer.cc
index 5c9943ae..24a0d4d 100644
--- a/chrome/browser/ui/tabs/web_contents_closer.cc
+++ b/chrome/browser/ui/tabs/web_contents_closer.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
-#include "chrome/browser/ui/tabs/tab_strip_model_impl.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/views/feature_promos/new_tab_promo_dialog_browsertest.cc b/chrome/browser/ui/views/feature_promos/new_tab_promo_dialog_browsertest.cc
index 4c92c8d..6a4d573 100644
--- a/chrome/browser/ui/views/feature_promos/new_tab_promo_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/feature_promos/new_tab_promo_dialog_browsertest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/new_tab_button.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 
 class NewTabPromoDialogTest : public DialogBrowserTest {
  public:
@@ -13,13 +13,10 @@
 
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
-    // The promo only exists in the TabStripImpl.
-    TabStripImpl* tab_strip_impl =
-        BrowserView::GetBrowserViewForBrowser(browser())
-            ->tabstrip()
-            ->AsTabStripImpl();
-    if (tab_strip_impl)
-      tab_strip_impl->new_tab_button()->ShowPromo();
+    BrowserView::GetBrowserViewForBrowser(browser())
+        ->tabstrip()
+        ->new_tab_button()
+        ->ShowPromo();
   }
 
  private:
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index f1b08a85..4b403ba 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -87,7 +87,7 @@
 #include "chrome/browser/ui/views/status_bubble_views.h"
 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
 #include "chrome/browser/ui/views/toolbar/reload_button.h"
@@ -2121,11 +2121,10 @@
   // TabStrip takes ownership of the controller.
   BrowserTabStripController* tabstrip_controller =
       new BrowserTabStripController(browser_->tab_strip_model(), this);
-  TabStripImpl* tab_strip_impl = new TabStripImpl(
-      std::unique_ptr<TabStripController>(tabstrip_controller));
-  tabstrip_ = tab_strip_impl;
+  tabstrip_ =
+      new TabStrip(std::unique_ptr<TabStripController>(tabstrip_controller));
   top_container_->AddChildView(tabstrip_);  // Takes ownership.
-  tabstrip_controller->InitFromModel(tab_strip_impl);
+  tabstrip_controller->InitFromModel(tabstrip_);
 
   toolbar_ = new ToolbarView(browser_.get());
   top_container_->AddChildView(toolbar_);
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
index c757a5ad..3ca1592 100644
--- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view_observer.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -258,10 +258,7 @@
   content::TestNavigationObserver navigation_watcher(
       contents, 1, content::MessageLoopRunner::QuitMode::DEFERRED);
 
-  // This test only works for the TabStripImpl.
-  TabStripImpl* tab_strip = browser_view()->tabstrip()->AsTabStripImpl();
-  if (!tab_strip)
-    return;
+  TabStrip* tab_strip = browser_view()->tabstrip();
 
   // Navigate without blocking.
   ui_test_utils::NavigateToURLWithDispositionBlockUntilNavigationsComplete(
diff --git a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
index c75888b..2180973 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout_unittest.cc
@@ -10,8 +10,8 @@
 #include "chrome/browser/ui/views/frame/contents_layout_manager.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -137,7 +137,7 @@
     immersive_mode_controller_.reset(new MockImmersiveModeController);
 
     top_container_ = CreateFixedSizeView(gfx::Size(800, 60));
-    tab_strip_ = new TabStripImpl(std::unique_ptr<TabStripController>());
+    tab_strip_ = new TabStrip(std::unique_ptr<TabStripController>());
     top_container_->AddChildView(tab_strip_);
     toolbar_ = CreateFixedSizeView(gfx::Size(800, 30));
     top_container_->AddChildView(toolbar_);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index 913f966..3d68da1 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -26,7 +26,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "ui/aura/window.h"
 #include "ui/views/controls/webview/webview.h"
@@ -265,10 +265,7 @@
 TEST_F(ImmersiveModeControllerAshTest, LayeredSpinners) {
   AddTab(browser(), GURL("about:blank"));
 
-  // This test only works with the TabStripImpl.
-  TabStripImpl* tabstrip = browser_view()->tabstrip()->AsTabStripImpl();
-  if (!tabstrip)
-    return;
+  TabStrip* tabstrip = browser_view()->tabstrip();
 
   // Immersive fullscreen starts out disabled; layers are OK.
   EXPECT_FALSE(browser_view()->GetWidget()->IsFullscreen());
diff --git a/chrome/browser/ui/views/passwords/manage_password_items_view.cc b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
index 3dad6b95..0b8181d9 100644
--- a/chrome/browser/ui/views/passwords/manage_password_items_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
@@ -120,7 +120,7 @@
 std::unique_ptr<views::Label> CreatePasswordLabel(
     const autofill::PasswordForm& form,
     int federation_message_id,
-    bool is_password_visible) {
+    bool are_passwords_revealed) {
   base::string16 text =
       form.federation_origin.unique()
           ? form.password_value
@@ -130,7 +130,7 @@
   auto label = std::make_unique<views::Label>(text, CONTEXT_BODY_TEXT_LARGE,
                                               STYLE_SECONDARY);
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  if (form.federation_origin.unique() && !is_password_visible)
+  if (form.federation_origin.unique() && !are_passwords_revealed)
     label->SetObscured(true);
   if (!form.federation_origin.unique())
     label->SetElideBehavior(gfx::ELIDE_HEAD);
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
index 8cb3a39..2f3bf84 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -106,18 +106,18 @@
 
 enum TextRowType { ROW_SINGLE, ROW_MULTILINE };
 
-// A combobox model for password dropdown that allows to mask/unmask values in
+// A combobox model for password dropdown that allows to reveal/mask values in
 // the combobox.
 class PasswordDropdownModel : public ui::ComboboxModel {
  public:
-  explicit PasswordDropdownModel(const std::vector<base::string16>& items)
-      : masked_(true), passwords_(items) {}
+  PasswordDropdownModel(bool revealed, const std::vector<base::string16>& items)
+      : revealed_(revealed), passwords_(items) {}
   ~PasswordDropdownModel() override {}
 
-  void SetMasked(bool masked) {
-    if (masked_ == masked)
+  void SetRevealed(bool revealed) {
+    if (revealed_ == revealed)
       return;
-    masked_ = masked;
+    revealed_ = revealed;
     for (auto& observer : observers_)
       observer.OnComboboxModelChanged(this);
   }
@@ -125,8 +125,8 @@
   // ui::ComboboxModel:
   int GetItemCount() const override { return passwords_.size(); }
   base::string16 GetItemAt(int index) override {
-    return masked_ ? base::string16(passwords_[index].length(), kBulletChar)
-                   : passwords_[index];
+    return revealed_ ? passwords_[index]
+                     : base::string16(passwords_[index].length(), kBulletChar);
   }
   void AddObserver(ui::ComboboxModelObserver* observer) override {
     observers_.AddObserver(observer);
@@ -136,7 +136,7 @@
   }
 
  private:
-  bool masked_;
+  bool revealed_;
   const std::vector<base::string16> passwords_;
   // To be called when |masked_| was changed;
   base::ObserverList<ui::ComboboxModelObserver> observers_;
@@ -251,7 +251,8 @@
 }
 
 std::unique_ptr<views::ToggleImageButton> CreatePasswordViewButton(
-    views::ButtonListener* listener) {
+    views::ButtonListener* listener,
+    bool are_passwords_revealed) {
   std::unique_ptr<views::ToggleImageButton> button(
       new views::ToggleImageButton(listener));
   button->SetFocusForPlatform();
@@ -269,15 +270,18 @@
           IDR_HIDE_PASSWORD_HOVER));
   button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                             views::ImageButton::ALIGN_MIDDLE);
+  button->SetToggled(are_passwords_revealed);
   return button;
 }
 
-// Creates a dropdown from the other possible passwords.
+// Creates a dropdown from |PasswordForm.all_possible_passwords|.
 std::unique_ptr<views::Combobox> CreatePasswordDropdownView(
-    const autofill::PasswordForm& form) {
+    const autofill::PasswordForm& form,
+    bool are_passwords_revealed) {
   DCHECK(!form.all_possible_passwords.empty());
-  std::unique_ptr<views::Combobox> combobox = std::make_unique<views::Combobox>(
-      std::make_unique<PasswordDropdownModel>(form.all_possible_passwords));
+  std::unique_ptr<views::Combobox> combobox =
+      std::make_unique<views::Combobox>(std::make_unique<PasswordDropdownModel>(
+          are_passwords_revealed, form.all_possible_passwords));
   size_t index = std::distance(
       form.all_possible_passwords.begin(),
       find(form.all_possible_passwords.begin(),
@@ -285,6 +289,7 @@
   // Unlikely, but if we don't find the password in possible passwords,
   // we will set the default to first element.
   if (index == form.all_possible_passwords.size()) {
+    NOTREACHED();
     combobox->SetSelectedIndex(0);
   } else {
     combobox->SetSelectedIndex(index);
@@ -472,7 +477,7 @@
   views::Combobox* password_dropdown_;
   views::Label* password_label_;
 
-  bool password_visible_;
+  bool are_passwords_revealed_;
 
   DISALLOW_COPY_AND_ASSIGN(PendingView);
 };
@@ -486,7 +491,8 @@
       password_view_button_(nullptr),
       password_dropdown_(nullptr),
       password_label_(nullptr),
-      password_visible_(false) {
+      are_passwords_revealed_(
+          parent_->model()->are_passwords_revealed_when_bubble_is_opened()) {
   // Create credentials row.
   const autofill::PasswordForm& password_form =
       parent_->model()->pending_password();
@@ -503,8 +509,9 @@
 
   if (base::FeatureList::IsEnabled(
           password_manager::features::kEnablePasswordSelection) &&
-      !parent_->model()->hide_eye_icon() && is_password_credential) {
-    password_view_button_ = CreatePasswordViewButton(this).release();
+      is_password_credential) {
+    password_view_button_ =
+        CreatePasswordViewButton(this, are_passwords_revealed_).release();
   }
 
   // Create buttons.
@@ -586,26 +593,31 @@
   if (enable_password_selection &&
       password_form.all_possible_passwords.size() > 1 &&
       parent_->model()->enable_editing()) {
-    password_dropdown_ = CreatePasswordDropdownView(password_form).release();
+    password_dropdown_ =
+        CreatePasswordDropdownView(password_form, are_passwords_revealed_)
+            .release();
   } else {
     password_label_ =
         CreatePasswordLabel(password_form,
                             IDS_PASSWORD_MANAGER_SIGNIN_VIA_FEDERATION,
-                            password_visible_)
+                            are_passwords_revealed_)
             .release();
   }
 }
 
 void ManagePasswordsBubbleView::PendingView::TogglePasswordVisibility() {
+  if (!are_passwords_revealed_ && !parent_->model()->RevealPasswords())
+    return;
+
   UpdateUsernameAndPasswordInModel();
-  password_visible_ = !password_visible_;
-  password_view_button_->SetToggled(password_visible_);
+  are_passwords_revealed_ = !are_passwords_revealed_;
+  password_view_button_->SetToggled(are_passwords_revealed_);
   DCHECK(!password_dropdown_ || !password_label_);
   if (password_dropdown_) {
     static_cast<PasswordDropdownModel*>(password_dropdown_->model())
-        ->SetMasked(!password_visible_);
+        ->SetRevealed(are_passwords_revealed_);
   } else {
-    password_label_->SetObscured(!password_visible_);
+    password_label_->SetObscured(!are_passwords_revealed_);
   }
 }
 
diff --git a/chrome/browser/ui/views/tabs/alert_indicator_button_unittest.cc b/chrome/browser/ui/views/tabs/alert_indicator_button_unittest.cc
index b02f92db..9d2cdc4 100644
--- a/chrome/browser/ui/views/tabs/alert_indicator_button_unittest.cc
+++ b/chrome/browser/ui/views/tabs/alert_indicator_button_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/views/test/views_test_base.h"
 
@@ -22,8 +22,7 @@
     views::ViewsTestBase::SetUp();
 
     controller_ = new FakeBaseTabStripController;
-    tab_strip_ =
-        new TabStripImpl(std::unique_ptr<TabStripController>(controller_));
+    tab_strip_ = new TabStrip(std::unique_ptr<TabStripController>(controller_));
     controller_->set_tab_strip(tab_strip_);
     // The tab strip must be added to the view hierarchy for it to create the
     // buttons.
@@ -65,7 +64,7 @@
   FakeBaseTabStripController* controller_ = nullptr;
   // Owns |tab_strip_|.
   views::View parent_;
-  TabStripImpl* tab_strip_ = nullptr;
+  TabStrip* tab_strip_ = nullptr;
   std::unique_ptr<views::Widget> widget_;
 
  private:
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 148887d..fcbea931 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -30,7 +30,7 @@
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/feature_engagement/features.h"
@@ -204,7 +204,7 @@
   model_->RemoveObserver(this);
 }
 
-void BrowserTabStripController::InitFromModel(TabStripImpl* tabstrip) {
+void BrowserTabStripController::InitFromModel(TabStrip* tabstrip) {
   tabstrip_ = tabstrip;
 
   UpdateStackedLayout();
@@ -339,7 +339,7 @@
   Navigate(&params);
 }
 
-bool BrowserTabStripController::IsCompatibleWith(TabStripImpl* other) const {
+bool BrowserTabStripController::IsCompatibleWith(TabStrip* other) const {
   Profile* other_profile = other->controller()->GetProfile();
   return other_profile == GetProfile();
 }
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
index c3b3c09..1610a880 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -18,7 +18,6 @@
 
 class Browser;
 class Tab;
-class TabStripImpl;
 struct TabRendererData;
 
 namespace content {
@@ -37,7 +36,7 @@
   BrowserTabStripController(TabStripModel* model, BrowserView* browser_view);
   ~BrowserTabStripController() override;
 
-  void InitFromModel(TabStripImpl* tabstrip);
+  void InitFromModel(TabStrip* tabstrip);
 
   TabStripModel* model() const { return model_; }
 
@@ -67,7 +66,7 @@
   int HasAvailableDragActions() const override;
   void OnDropIndexUpdate(int index, bool drop_before) override;
   void PerformDrop(bool drop_before, int index, const GURL& url) override;
-  bool IsCompatibleWith(TabStripImpl* other) const override;
+  bool IsCompatibleWith(TabStrip* other) const override;
   void CreateNewTab() override;
   void CreateNewTabWithLocation(const base::string16& loc) override;
   bool IsIncognito() override;
@@ -147,7 +146,7 @@
 
   TabStripModel* model_;
 
-  TabStripImpl* tabstrip_;
+  TabStrip* tabstrip_;
 
   BrowserView* browser_view_;
 
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index f8943d3..27850d2 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 
 FakeBaseTabStripController::FakeBaseTabStripController() {}
 
@@ -112,7 +112,7 @@
                                              const GURL& url) {
 }
 
-bool FakeBaseTabStripController::IsCompatibleWith(TabStripImpl* other) const {
+bool FakeBaseTabStripController::IsCompatibleWith(TabStrip* other) const {
   return false;
 }
 
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
index 1573ef3..46eca0c 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -10,8 +10,6 @@
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "ui/base/models/list_selection_model.h"
 
-class TabStripImpl;
-
 class FakeBaseTabStripController : public TabStripController {
  public:
   FakeBaseTabStripController();
@@ -23,7 +21,7 @@
 
   ui::ListSelectionModel* selection_model() { return &selection_model_; }
 
-  void set_tab_strip(TabStripImpl* tab_strip) { tab_strip_ = tab_strip; }
+  void set_tab_strip(TabStrip* tab_strip) { tab_strip_ = tab_strip; }
 
   // TabStripController overrides:
   const ui::ListSelectionModel& GetSelectionModel() const override;
@@ -45,7 +43,7 @@
   int HasAvailableDragActions() const override;
   void OnDropIndexUpdate(int index, bool drop_before) override;
   void PerformDrop(bool drop_before, int index, const GURL& url) override;
-  bool IsCompatibleWith(TabStripImpl* other) const override;
+  bool IsCompatibleWith(TabStrip* other) const override;
   void CreateNewTab() override;
   void CreateNewTabWithLocation(const base::string16& loc) override;
   bool IsIncognito() override;
@@ -58,7 +56,7 @@
   Profile* GetProfile() const override;
 
  private:
-  TabStripImpl* tab_strip_ = nullptr;
+  TabStrip* tab_strip_ = nullptr;
 
   int num_tabs_ = 0;
   int active_index_ = -1;
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index da319c8..2814e20 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/feature_promos/new_tab_promo_bubble_view.h"
 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "components/feature_engagement/features.h"
 #include "third_party/skia/include/core/SkColorFilter.h"
 #include "third_party/skia/include/effects/SkBlurMaskFilter.h"
@@ -53,8 +53,7 @@
 
 }  // namespace
 
-NewTabButton::NewTabButton(TabStripImpl* tab_strip,
-                           views::ButtonListener* listener)
+NewTabButton::NewTabButton(TabStrip* tab_strip, views::ButtonListener* listener)
     : views::ImageButton(listener),
       tab_strip_(tab_strip),
       new_tab_promo_(nullptr),
@@ -86,20 +85,14 @@
   BrowserView* browser = static_cast<BrowserView*>(
       BrowserList::GetInstance()->GetLastActive()->window());
 
-  // The promo depends on the new tab button which only exists on the
-  // TabStripImpl.
-  TabStripImpl* tab_strip_impl = browser->tabstrip()->AsTabStripImpl();
-  if (tab_strip_impl)
-    tab_strip_impl->new_tab_button()->ShowPromo();
+  browser->tabstrip()->new_tab_button()->ShowPromo();
 }
 
 // static
 void NewTabButton::CloseBubbleForLastActiveBrowser() {
   BrowserView* browser = static_cast<BrowserView*>(
       BrowserList::GetInstance()->GetLastActive()->window());
-  TabStripImpl* tab_strip_impl = browser->tabstrip()->AsTabStripImpl();
-  if (tab_strip_impl)
-    tab_strip_impl->new_tab_button()->CloseBubble();
+  browser->tabstrip()->new_tab_button()->CloseBubble();
 }
 
 void NewTabButton::ShowPromo() {
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h
index 0e87ad4..5e1a1df 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.h
+++ b/chrome/browser/ui/views/tabs/new_tab_button.h
@@ -13,7 +13,6 @@
 #include "ui/views/widget/widget_observer.h"
 
 class NewTabPromoBubbleView;
-class TabStripImpl;
 
 ///////////////////////////////////////////////////////////////////////////////
 // NewTabButton
@@ -26,7 +25,7 @@
                      public views::MaskedTargeterDelegate,
                      public views::WidgetObserver {
  public:
-  NewTabButton(TabStripImpl* tab_strip, views::ButtonListener* listener);
+  NewTabButton(TabStrip* tab_strip, views::ButtonListener* listener);
   ~NewTabButton() override;
 
   // Set the background offset used to match the background image to the frame
@@ -93,7 +92,7 @@
                  gfx::Canvas* canvas) const;
 
   // Tab strip that contains this button.
-  TabStripImpl* tab_strip_;
+  TabStrip* tab_strip_;
 
   // Promotional UI that appears next to the NewTabButton and encourages its
   // use. Owned by its NativeWidget.
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 413a8af..52e84c4 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -26,7 +26,7 @@
 #include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/window_finder.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
@@ -100,7 +100,7 @@
 
 #if defined(OS_CHROMEOS)
 // Returns true if |tab_strip| browser window is snapped.
-bool IsSnapped(const TabStripImpl* tab_strip) {
+bool IsSnapped(const TabStrip* tab_strip) {
   DCHECK(tab_strip);
   ash::mojom::WindowStateType type =
       tab_strip->GetWidget()->GetNativeWindow()->GetProperty(
@@ -109,7 +109,7 @@
          type == ash::mojom::WindowStateType::RIGHT_SNAPPED;
 }
 #else
-bool IsSnapped(const TabStripImpl* tab_strip) {
+bool IsSnapped(const TabStrip* tab_strip) {
   return false;
 }
 #endif
@@ -235,13 +235,13 @@
     GetModel(source_tabstrip_)->RemoveObserver(this);
 
   if (event_source_ == EVENT_SOURCE_TOUCH) {
-    TabStripImpl* capture_tabstrip =
+    TabStrip* capture_tabstrip =
         attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_;
     capture_tabstrip->GetWidget()->ReleaseCapture();
   }
 }
 
-void TabDragController::Init(TabStripImpl* source_tabstrip,
+void TabDragController::Init(TabStrip* source_tabstrip,
                              Tab* source_tab,
                              const std::vector<Tab*>& tabs,
                              const gfx::Point& mouse_offset,
@@ -307,7 +307,7 @@
 }
 
 // static
-bool TabDragController::IsAttachedTo(const TabStripImpl* tab_strip) {
+bool TabDragController::IsAttachedTo(const TabStrip* tab_strip) {
   return (instance_ && instance_->active() &&
           instance_->attached_tabstrip() == tab_strip);
 }
@@ -512,7 +512,7 @@
 
   DCHECK(attached_tabstrip_);
 
-  TabStripImpl* target_tabstrip = source_tabstrip_;
+  TabStrip* target_tabstrip = source_tabstrip_;
   if (detach_behavior_ == DETACHABLE &&
       GetTargetTabStripForPoint(point_in_screen, &target_tabstrip) ==
           Liveness::DELETED) {
@@ -560,7 +560,7 @@
 }
 
 TabDragController::DragBrowserResultType
-TabDragController::DragBrowserToNewTabStrip(TabStripImpl* target_tabstrip,
+TabDragController::DragBrowserToNewTabStrip(TabStrip* target_tabstrip,
                                             const gfx::Point& point_in_screen) {
   TRACE_EVENT1("views", "TabDragController::DragBrowserToNewTabStrip",
                "point_in_screen", point_in_screen.ToString());
@@ -798,7 +798,7 @@
 
 TabDragController::Liveness TabDragController::GetTargetTabStripForPoint(
     const gfx::Point& point_in_screen,
-    TabStripImpl** tab_strip) {
+    TabStrip** tab_strip) {
   *tab_strip = nullptr;
   TRACE_EVENT1("views", "TabDragController::GetTargetTabStripForPoint",
                "point_in_screen", point_in_screen.ToString());
@@ -823,7 +823,7 @@
   // Do not allow dragging into a window with a modal dialog, it causes a weird
   // behavior.  See crbug.com/336691
   if (!GetModalTransient(local_window)) {
-    TabStripImpl* result = GetTabStripForWindow(local_window);
+    TabStrip* result = GetTabStripForWindow(local_window);
     if (result && DoesTabStripContain(result, point_in_screen)) {
       *tab_strip = result;
       return Liveness::ALIVE;
@@ -834,8 +834,7 @@
   return Liveness::ALIVE;
 }
 
-TabStripImpl* TabDragController::GetTabStripForWindow(
-    gfx::NativeWindow window) {
+TabStrip* TabDragController::GetTabStripForWindow(gfx::NativeWindow window) {
   if (!window)
     return NULL;
   BrowserView* browser_view =
@@ -846,10 +845,8 @@
           Browser::FEATURE_TABSTRIP))
     return NULL;
 
-  // TabDragController is a helper for TabStripImpl and will only be used
-  // when the Impl (not the experimental one) is used.
-  TabStripImpl* other_tabstrip = browser_view->tabstrip()->AsTabStripImpl();
-  TabStripImpl* tab_strip =
+  TabStrip* other_tabstrip = browser_view->tabstrip();
+  TabStrip* tab_strip =
       attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_;
   DCHECK(tab_strip);
 
@@ -858,7 +855,7 @@
 }
 
 bool TabDragController::DoesTabStripContain(
-    TabStripImpl* tabstrip,
+    TabStrip* tabstrip,
     const gfx::Point& point_in_screen) const {
   // Make sure the specified screen point is actually within the bounds of the
   // specified tabstrip...
@@ -870,7 +867,7 @@
                                            point_in_screen.y());
 }
 
-void TabDragController::Attach(TabStripImpl* attached_tabstrip,
+void TabDragController::Attach(TabStrip* attached_tabstrip,
                                const gfx::Point& point_in_screen) {
   TRACE_EVENT1("views", "TabDragController::Attach",
                "point_in_screen", point_in_screen.ToString());
@@ -1036,9 +1033,7 @@
   Detach(can_release_capture_ ? RELEASE_CAPTURE : DONT_RELEASE_CAPTURE);
 
   dragged_widget->SetVisibilityChangedAnimationsEnabled(false);
-  // TabDragController is a helper for TabStripImpl and will only be used
-  // when the Impl (not the experimental one) is used.
-  Attach(dragged_browser_view->tabstrip()->AsTabStripImpl(), gfx::Point());
+  Attach(dragged_browser_view->tabstrip(), gfx::Point());
   AdjustBrowserAndTabBoundsForDrag(last_tabstrip_width,
                                    point_in_screen,
                                    &drag_bounds);
@@ -1301,7 +1296,7 @@
 }
 
 std::vector<Tab*> TabDragController::GetTabsMatchingDraggedContents(
-    TabStripImpl* tabstrip) {
+    TabStrip* tabstrip) {
   TabStripModel* model = GetModel(attached_tabstrip_);
   std::vector<Tab*> tabs;
   for (size_t i = 0; i < drag_data_.size(); ++i) {
@@ -1357,7 +1352,7 @@
   // Clear out drag data so we don't attempt to do anything with it.
   drag_data_.clear();
 
-  TabStripImpl* owning_tabstrip =
+  TabStrip* owning_tabstrip =
       attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_;
   owning_tabstrip->DestroyDragController();
 }
@@ -1611,7 +1606,7 @@
   }
 }
 
-TabStripModel* TabDragController::GetModel(TabStripImpl* tabstrip) const {
+TabStripModel* TabDragController::GetModel(TabStrip* tabstrip) const {
   return static_cast<BrowserTabStripController*>(tabstrip->controller())->
       model();
 }
@@ -1631,7 +1626,7 @@
 }
 
 gfx::Rect TabDragController::CalculateDraggedBrowserBounds(
-    TabStripImpl* source,
+    TabStrip* source,
     const gfx::Point& point_in_screen,
     std::vector<gfx::Rect>* drag_bounds) {
   gfx::Point center(0, source->height() / 2);
@@ -1730,7 +1725,7 @@
 }
 
 Browser* TabDragController::CreateBrowserForDrag(
-    TabStripImpl* source,
+    TabStrip* source,
     const gfx::Point& point_in_screen,
     gfx::Vector2d* drag_offset,
     std::vector<gfx::Rect>* drag_bounds) {
@@ -1778,7 +1773,7 @@
 
 gfx::Vector2d TabDragController::GetWindowOffset(
     const gfx::Point& point_in_screen) {
-  TabStripImpl* owning_tabstrip =
+  TabStrip* owning_tabstrip =
       attached_tabstrip_ ? attached_tabstrip_ : source_tabstrip_;
   views::View* toplevel_view = owning_tabstrip->GetWidget()->GetContentsView();
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index 004426a..bf09347 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -32,7 +32,7 @@
 class Browser;
 class Tab;
 class TabDragControllerTest;
-class TabStripImpl;
+class TabStrip;
 class TabStripModel;
 class WindowFinder;
 
@@ -81,7 +81,7 @@
   // |mouse_offset| relative to |source_tab|. |initial_selection_model| is the
   // selection model before the drag started and is only non-empty if
   // |source_tab| was not initially selected.
-  void Init(TabStripImpl* source_tabstrip,
+  void Init(TabStrip* source_tabstrip,
             Tab* source_tab,
             const std::vector<Tab*>& tabs,
             const gfx::Point& mouse_offset,
@@ -94,7 +94,7 @@
   // |tab_strip|.
   // NOTE: this returns false if the TabDragController is in the process of
   // finishing the drag.
-  static bool IsAttachedTo(const TabStripImpl* tab_strip);
+  static bool IsAttachedTo(const TabStrip* tab_strip);
 
   // Returns true if there is a drag underway.
   static bool IsActive();
@@ -107,7 +107,7 @@
 
   // See description above fields for details on these.
   bool active() const { return active_; }
-  const TabStripImpl* attached_tabstrip() const { return attached_tabstrip_; }
+  const TabStrip* attached_tabstrip() const { return attached_tabstrip_; }
 
   // Returns true if a drag started.
   bool started_drag() const { return started_drag_; }
@@ -255,7 +255,7 @@
   // |target_tabstrip| is NULL if the mouse is not over a valid tab strip.  See
   // DragBrowserResultType for details of the return type.
   DragBrowserResultType DragBrowserToNewTabStrip(
-      TabStripImpl* target_tabstrip,
+      TabStrip* target_tabstrip,
       const gfx::Point& point_in_screen);
 
   // Handles dragging for a touch tabstrip when the tabs are stacked. Doesn't
@@ -278,16 +278,16 @@
 
   // Returns the TabStrip for the specified window, or NULL if one doesn't exist
   // or isn't compatible.
-  TabStripImpl* GetTabStripForWindow(gfx::NativeWindow window);
+  TabStrip* GetTabStripForWindow(gfx::NativeWindow window);
 
   // Returns the compatible TabStrip to drag to at the specified point (screen
   // coordinates), or NULL if there is none.
   Liveness GetTargetTabStripForPoint(const gfx::Point& point_in_screen,
-                                     TabStripImpl** tab_strip);
+                                     TabStrip** tab_strip);
 
   // Returns true if |tabstrip| contains the specified point in screen
   // coordinates.
-  bool DoesTabStripContain(TabStripImpl* tabstrip,
+  bool DoesTabStripContain(TabStrip* tabstrip,
                            const gfx::Point& point_in_screen) const;
 
   // Returns the DetachPosition given the specified location in screen
@@ -295,8 +295,7 @@
   DetachPosition GetDetachPosition(const gfx::Point& point_in_screen);
 
   // Attach the dragged Tab to the specified TabStrip.
-  void Attach(TabStripImpl* attached_tabstrip,
-              const gfx::Point& point_in_screen);
+  void Attach(TabStrip* attached_tabstrip, const gfx::Point& point_in_screen);
 
   // Detach the dragged Tab from the current TabStrip.
   void Detach(ReleaseCapture release_capture);
@@ -353,7 +352,7 @@
 
   // Finds the Tabs within the specified TabStrip that corresponds to the
   // WebContents of the dragged tabs. Returns an empty vector if not attached.
-  std::vector<Tab*> GetTabsMatchingDraggedContents(TabStripImpl* tabstrip);
+  std::vector<Tab*> GetTabsMatchingDraggedContents(TabStrip* tabstrip);
 
   // Returns the bounds for the tabs based on the attached tab strip.
   std::vector<gfx::Rect> CalculateBoundsForDraggedTabs();
@@ -415,7 +414,7 @@
   // such that the tab that was dragged remains under the |point_in_screen|.
   // Offsets |drag_bounds| if necessary when dragging to the right from the
   // source browser.
-  gfx::Rect CalculateDraggedBrowserBounds(TabStripImpl* source,
+  gfx::Rect CalculateDraggedBrowserBounds(TabStrip* source,
                                           const gfx::Point& point_in_screen,
                                           std::vector<gfx::Rect>* drag_bounds);
 
@@ -429,13 +428,13 @@
                                         std::vector<gfx::Rect>* drag_bounds);
 
   // Creates and returns a new Browser to handle the drag.
-  Browser* CreateBrowserForDrag(TabStripImpl* source,
+  Browser* CreateBrowserForDrag(TabStrip* source,
                                 const gfx::Point& point_in_screen,
                                 gfx::Vector2d* drag_offset,
                                 std::vector<gfx::Rect>* drag_bounds);
 
   // Returns the TabStripModel for the specified tabstrip.
-  TabStripModel* GetModel(TabStripImpl* tabstrip) const;
+  TabStripModel* GetModel(TabStrip* tabstrip) const;
 
   // Returns the location of the cursor. This is either the location of the
   // mouse or the location of the current touch point.
@@ -459,11 +458,11 @@
   EventSource event_source_;
 
   // The TabStrip the drag originated from.
-  TabStripImpl* source_tabstrip_;
+  TabStrip* source_tabstrip_;
 
   // The TabStrip the dragged Tab is currently attached to, or NULL if the
   // dragged Tab is detached.
-  TabStripImpl* attached_tabstrip_;
+  TabStrip* attached_tabstrip_;
 
   // Whether capture can be released during the drag. When false, capture should
   // not be released when transferring capture between widgets and when starting
@@ -578,7 +577,7 @@
   bool waiting_for_run_loop_to_exit_;
 
   // The TabStrip to attach to after the move loop completes.
-  TabStripImpl* tab_strip_to_attach_to_after_exit_;
+  TabStrip* tab_strip_to_attach_to_after_exit_;
 
   // Non-null for the duration of RunMoveLoop.
   views::Widget* move_loop_widget_;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index e432d9ac..0c89ca9 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -32,7 +32,7 @@
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/window_finder.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
@@ -158,9 +158,9 @@
   new QuitDraggingObserver();  // QuitDraggingObserver deletes itself.
 }
 
-TabStripImpl* GetTabStripForBrowser(Browser* browser) {
+TabStrip* GetTabStripForBrowser(Browser* browser) {
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
-  return browser_view->tabstrip()->AsTabStripImpl();
+  return browser_view->tabstrip();
 }
 
 }  // namespace test
@@ -177,7 +177,7 @@
 TabDragControllerTest::~TabDragControllerTest() {
 }
 
-void TabDragControllerTest::StopAnimating(TabStripImpl* tab_strip) {
+void TabDragControllerTest::StopAnimating(TabStrip* tab_strip) {
   tab_strip->StopAnimating(true);
 }
 
@@ -207,7 +207,7 @@
 }
 
 void TabDragControllerTest::SetWindowFinderForTabStrip(
-    TabStripImpl* tab_strip,
+    TabStrip* tab_strip,
     std::unique_ptr<WindowFinder> window_finder) {
   ASSERT_TRUE(tab_strip->drag_controller_.get());
   tab_strip->drag_controller_->window_finder_ = std::move(window_finder);
@@ -224,7 +224,7 @@
   INPUT_SOURCE_TOUCH = 1
 };
 
-int GetDetachY(TabStripImpl* tab_strip) {
+int GetDetachY(TabStrip* tab_strip) {
   return std::max(TabDragController::kTouchVerticalDetachMagnetism,
                   TabDragController::kVerticalDetachMagnetism) +
       tab_strip->height() + 1;
@@ -332,7 +332,7 @@
 IN_PROC_BROWSER_TEST_F(TabDragCaptureLostTest, ReleaseCaptureOnDrag) {
   AddTabAndResetBrowser(browser());
 
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
   ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(tab_1_center) &&
               ui_test_utils::SendMouseEventsSync(
@@ -352,7 +352,7 @@
 IN_PROC_BROWSER_TEST_F(TabDragControllerTest, GestureEndShouldEndDragTest) {
   AddTabAndResetBrowser(browser());
 
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   Tab* tab1 = tab_strip->tab_at(1);
   gfx::Point tab_1_center(tab1->width() / 2, tab1->height() / 2);
@@ -558,7 +558,7 @@
 
   AddTabAndResetBrowser(browser());
 
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   TabStripModel* model = browser()->tab_strip_model();
 
   gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
@@ -624,7 +624,7 @@
       gfx::Point(bounds.width() - 11, 0)));
   ASSERT_TRUE(masked_window->GetEventHandlerForPoint(
       gfx::Point(bounds.width() - 9, 0)));
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   TabStripModel* model = browser()->tab_strip_model();
 
   gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1)));
@@ -642,8 +642,8 @@
 
 // Invoked from the nested run loop.
 void DragToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
-                               TabStripImpl* not_attached_tab_strip,
-                               TabStripImpl* target_tab_strip) {
+                               TabStrip* not_attached_tab_strip,
+                               TabStrip* target_tab_strip) {
   ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
   ASSERT_TRUE(TabDragController::IsActive());
@@ -661,14 +661,14 @@
 // Creates two browsers, drags from first into second.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        DragToSeparateWindow) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
   AddTabAndResetBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
 
   // Move to the first tab and drag it enough so that it detaches, but not
   // enough that it attaches to browser2.
@@ -711,7 +711,7 @@
 // GetLocalProcessWindowAtPoint().
 class CaptureLoseWindowFinder : public WindowFinder {
  public:
-  explicit CaptureLoseWindowFinder(TabStripImpl* tab_strip)
+  explicit CaptureLoseWindowFinder(TabStrip* tab_strip)
       : tab_strip_(tab_strip) {}
   ~CaptureLoseWindowFinder() override {}
 
@@ -724,7 +724,7 @@
   }
 
  private:
-  TabStripImpl* tab_strip_;
+  TabStrip* tab_strip_;
 
   DISALLOW_COPY_AND_ASSIGN(CaptureLoseWindowFinder);
 };
@@ -742,7 +742,7 @@
 // and verifies we don't crash. This simulates a crash seen on windows.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_CaptureLostDuringDrag) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
   AddTabAndResetBrowser(browser());
@@ -839,7 +839,7 @@
   const gfx::Rect initial_bounds(browser()->window()->GetBounds());
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(
@@ -861,7 +861,7 @@
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
@@ -914,7 +914,7 @@
   const gfx::Rect initial_bounds(browser()->window()->GetBounds());
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
@@ -935,7 +935,7 @@
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
@@ -982,7 +982,7 @@
 
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(
@@ -1004,7 +1004,7 @@
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
@@ -1040,7 +1040,7 @@
 
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
@@ -1061,7 +1061,7 @@
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
@@ -1094,7 +1094,7 @@
                        DeleteBeforeStartedDragging) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Click on the first tab, but don't move it.
   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
@@ -1134,7 +1134,7 @@
 
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Click on the first tab and move it enough so that it starts dragging but is
   // still attached.
@@ -1180,7 +1180,7 @@
                        MAYBE_DeleteTabWhileDetached) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
@@ -1229,7 +1229,7 @@
   AddTabAndResetBrowser(browser());
   AddTabAndResetBrowser(browser());
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   EXPECT_EQ("0 1 2 3", IDString(browser()->tab_strip_model()));
 
   // Click the first tab and select two middle tabs.
@@ -1285,7 +1285,7 @@
                        MAYBE_DeleteSourceDetached) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
@@ -1335,7 +1335,7 @@
                        MAYBE_PressEscapeWhileDetached) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
@@ -1388,7 +1388,7 @@
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   browser()->tab_strip_model()->AddTabAtToSelection(0);
   browser()->tab_strip_model()->AddTabAtToSelection(1);
   const gfx::Rect initial_bounds = browser()->window()->GetBounds();
@@ -1428,8 +1428,8 @@
 
 // Invoked from the nested run loop.
 void DragAllToSeparateWindowStep2(DetachToBrowserTabDragControllerTest* test,
-                                  TabStripImpl* attached_tab_strip,
-                                  TabStripImpl* target_tab_strip,
+                                  TabStrip* attached_tab_strip,
+                                  TabStrip* target_tab_strip,
                                   const BrowserList* browser_list) {
   ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
@@ -1456,14 +1456,14 @@
 // Creates two browsers, selects all tabs in first and drags into second.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_DragAllToSeparateWindow) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
   AddTabAndResetBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
 
   browser()->tab_strip_model()->AddTabAtToSelection(0);
   browser()->tab_strip_model()->AddTabAtToSelection(1);
@@ -1501,8 +1501,8 @@
 // Invoked from the nested run loop.
 void DragAllToSeparateWindowAndCancelStep2(
     DetachToBrowserTabDragControllerTest* test,
-    TabStripImpl* attached_tab_strip,
-    TabStripImpl* target_tab_strip,
+    TabStrip* attached_tab_strip,
+    TabStrip* target_tab_strip,
     const BrowserList* browser_list) {
   ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
@@ -1531,14 +1531,14 @@
 // escape.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_DragAllToSeparateWindowAndCancel) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
   AddTabAndResetBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
 
   browser()->tab_strip_model()->AddTabAtToSelection(0);
   browser()->tab_strip_model()->AddTabAtToSelection(1);
@@ -1587,14 +1587,14 @@
 // no detaching should happen.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_DragDirectlyToSecondWindow) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
   AddTabAndResetBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
 
   // Move the tabstrip down enough so that we can detach.
   gfx::Rect bounds(browser2->window()->GetBounds());
@@ -1643,13 +1643,13 @@
 // second browser.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_DragSingleTabToSeparateWindow) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   ResetIDs(browser()->tab_strip_model(), 0);
 
   // Create another browser.
   Browser* browser2 = CreateAnotherWindowBrowserAndRelayout();
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
   const gfx::Rect initial_bounds(browser2->window()->GetBounds());
 
   // Move to the first tab and drag it enough so that it detaches, but not
@@ -1714,7 +1714,7 @@
 // verifies the run loop ends.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
                        MAYBE_CancelOnNewTabWhenDragging) {
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Add another tab to browser().
   AddTabAndResetBrowser(browser());
@@ -1753,14 +1753,14 @@
 
 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
                                 Browser* browser,
-                                TabStripImpl* tab_strip,
+                                TabStrip* tab_strip,
                                 const BrowserList* browser_list) {
   // There should be another browser.
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   EXPECT_NE(browser, new_browser);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
 
   ASSERT_TRUE(tab_strip2->IsDragSessionActive());
   ASSERT_FALSE(tab_strip->IsDragSessionActive());
@@ -1781,7 +1781,7 @@
   AddTabAndResetBrowser(browser());
   browser()->window()->Maximize();
 
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   gfx::Point tab_0_center(
@@ -1866,7 +1866,7 @@
                        DragSingleTabToSeparateWindowInSecondDisplay) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move to the first tab and drag it enough so that it detaches.
   // Then drag it to the final destination on the second screen.
@@ -1888,7 +1888,7 @@
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
   // This other browser should be on the second screen (with mouse drag)
@@ -1915,8 +1915,8 @@
 // Invoked from the nested run loop.
 void DragTabToWindowInSeparateDisplayStep2(
     DetachToBrowserTabDragControllerTest* test,
-    TabStripImpl* not_attached_tab_strip,
-    TabStripImpl* target_tab_strip) {
+    TabStrip* not_attached_tab_strip,
+    TabStrip* target_tab_strip) {
   ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
   ASSERT_FALSE(target_tab_strip->IsDragSessionActive());
   ASSERT_TRUE(TabDragController::IsActive());
@@ -1939,11 +1939,11 @@
                        DragTabToWindowInSeparateDisplay) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateBrowser(browser()->profile());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
   ResetIDs(browser2->tab_strip_model(), 100);
 
   // Move the second browser to the second display.
@@ -2001,7 +2001,7 @@
   // Start dragging the window by the tab strip, and move it only to the edge
   // of the first display. Expect at that point mouse would warp and the window
   // will therefore reside in the second display when mouse is released.
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   const gfx::Point tab_0_center =
       GetCenterInScreenCoordinates(tab_strip->tab_at(0));
   gfx::Point target_point = tab_0_center;
@@ -2044,11 +2044,11 @@
                        DragTabToWindowOnSecondDisplay) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateBrowser(browser()->profile());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
   ResetIDs(browser2->tab_strip_model(), 100);
 
   // Move both browsers to the second display.
@@ -2109,7 +2109,7 @@
   // Add another tab.
   AddTabAndResetBrowser(browser());
   browser()->window()->Maximize();
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Create another browser on the second display.
   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
@@ -2126,7 +2126,7 @@
   Browser* browser2 = new Browser(params);
   AddBlankTabAndShow(browser2);
 
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
   ResetIDs(browser2->tab_strip_model(), 100);
 
   EXPECT_EQ(second_root,
@@ -2175,11 +2175,11 @@
                        DISABLED_DragTabToImmersiveBrowserOnSeparateDisplay) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Create another browser.
   Browser* browser2 = CreateBrowser(browser()->profile());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(browser2);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(browser2);
   ResetIDs(browser2->tab_strip_model(), 100);
 
   // Move the second browser to the second display.
@@ -2310,7 +2310,7 @@
 // Drags tab to |kDragPoints[index]|, then calls the next step function.
 void CursorDeviceScaleFactorStep(
     DifferentDeviceScaleFactorDisplayTabDragControllerTest* test,
-    TabStripImpl* not_attached_tab_strip,
+    TabStrip* not_attached_tab_strip,
     size_t index) {
   ASSERT_FALSE(not_attached_tab_strip->IsDragSessionActive());
   ASSERT_TRUE(TabDragController::IsActive());
@@ -2338,7 +2338,7 @@
                        DISABLED_CursorDeviceScaleFactor) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   // Move the second browser to the second display.
   aura::Window::Windows roots = ash::Shell::GetAllRootWindows();
@@ -2392,7 +2392,7 @@
 
 // Invoked from the nested run loop.
 void CancelDragTabToWindowInSeparateDisplayStep3(
-    TabStripImpl* tab_strip,
+    TabStrip* tab_strip,
     const BrowserList* browser_list) {
   ASSERT_FALSE(tab_strip->IsDragSessionActive());
   ASSERT_TRUE(TabDragController::IsActive());
@@ -2407,7 +2407,7 @@
 // Invoked from the nested run loop.
 void CancelDragTabToWindowInSeparateDisplayStep2(
     DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest* test,
-    TabStripImpl* tab_strip,
+    TabStrip* tab_strip,
     aura::Window* current_root,
     gfx::Point final_destination,
     const BrowserList* browser_list) {
@@ -2433,7 +2433,7 @@
     CancelDragTabToWindowIn2ndDisplay) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
 
@@ -2475,7 +2475,7 @@
 
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
 
   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
   EXPECT_EQ(roots[0], browser()->window()->GetNativeWindow()->GetRootWindow());
@@ -2545,7 +2545,7 @@
                        PressSecondFingerWhileDetached) {
   // Add another tab.
   AddTabAndResetBrowser(browser());
-  TabStripImpl* tab_strip = GetTabStripForBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
   EXPECT_EQ("0 1", IDString(browser()->tab_strip_model()));
 
   // Move to the first tab and drag it enough so that it detaches.
@@ -2566,7 +2566,7 @@
   ASSERT_EQ(2u, browser_list->size());
   Browser* new_browser = browser_list->get(1);
   ASSERT_TRUE(new_browser->window()->IsActive());
-  TabStripImpl* tab_strip2 = GetTabStripForBrowser(new_browser);
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
   ASSERT_FALSE(tab_strip2->IsDragSessionActive());
 
   EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h
index 1e45be5..f322752 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h
@@ -12,7 +12,7 @@
 
 class Browser;
 class BrowserList;
-class TabStripImpl;
+class TabStrip;
 class TabStripModel;
 class WindowFinder;
 
@@ -28,7 +28,7 @@
   ~TabDragControllerTest() override;
 
   // Cover for TabStrip::StopAnimating(true).
-  void StopAnimating(TabStripImpl* tab_strip);
+  void StopAnimating(TabStrip* tab_strip);
 
   // Adds a new blank tab to |browser|, stops animations and resets the ids of
   // the tabs in |browser|.
@@ -38,7 +38,7 @@
   // side by side.
   Browser* CreateAnotherWindowBrowserAndRelayout();
 
-  void SetWindowFinderForTabStrip(TabStripImpl* tab_strip,
+  void SetWindowFinderForTabStrip(TabStrip* tab_strip,
                                   std::unique_ptr<WindowFinder> window_finder);
 
   const BrowserList* browser_list;
@@ -54,7 +54,7 @@
 namespace test {
 
 // Returns the TabStrip for |browser|.
-TabStripImpl* GetTabStripForBrowser(Browser* browser);
+TabStrip* GetTabStripForBrowser(Browser* browser);
 
 // Sets the id of |web_contents| to |id|.
 void SetID(content::WebContents* web_contents, int id);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 0844385..ffa26591 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -4,9 +4,305 @@
 
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 
-TabStrip::TabStrip() {}
+#include <stddef.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/containers/adapters.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "cc/paint/paint_flags.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/tabs/new_tab_button.h"
+#include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_layout.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
+#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/theme_resources.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
+#include "third_party/skia/include/pathops/SkPathOps.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/base/default_theme_provider.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/list_selection_model.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/compositor/compositing_recorder.h"
+#include "ui/compositor/paint_recorder.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/animation/animation_container.h"
+#include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/masked_targeter_delegate.h"
+#include "ui/views/mouse_watcher_view_host.h"
+#include "ui/views/rect_based_targeting_utils.h"
+#include "ui/views/view_model_utils.h"
+#include "ui/views/view_targeter.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/non_client_view.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#include "ui/display/win/screen_win.h"
+#include "ui/gfx/win/hwnd_util.h"
+#include "ui/views/win/hwnd_util.h"
+#endif
+
+using base::UserMetricsAction;
+using ui::DropTargetEvent;
+
+namespace {
+
+const int kTabStripAnimationVSlop = 40;
+
+// Inverse ratio of the width of a tab edge to the width of the tab. When
+// hovering over the left or right edge of a tab, the drop indicator will
+// point between tabs.
+const int kTabEdgeRatioInverse = 4;
+
+// Size of the drop indicator.
+int drop_indicator_width;
+int drop_indicator_height;
+
+// Max number of stacked tabs.
+const int kMaxStackedCount = 4;
+
+// Padding between stacked tabs.
+const int kStackedPadding = 6;
+
+// See UpdateLayoutTypeFromMouseEvent() for a description of these.
+#if !defined(OS_CHROMEOS)
+const int kMouseMoveTimeMS = 200;
+const int kMouseMoveCountBeforeConsiderReal = 3;
+#endif
+
+// Amount of time we delay before resizing after a close from a touch.
+const int kTouchResizeLayoutTimeMS = 2000;
+
+#if defined(OS_MACOSX)
+const int kPinnedToNonPinnedOffset = 2;
+#else
+const int kPinnedToNonPinnedOffset = 3;
+#endif
+
+// Returns the width needed for the new tab button (and padding).
+int GetNewTabButtonWidth() {
+  return GetLayoutSize(NEW_TAB_BUTTON).width() -
+         GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP);
+}
+
+// Animation delegate used for any automatic tab movement.  Hides the tab if it
+// is not fully visible within the tabstrip area, to prevent overflow clipping.
+class TabAnimationDelegate : public gfx::AnimationDelegate {
+ public:
+  TabAnimationDelegate(TabStrip* tab_strip, Tab* tab);
+  ~TabAnimationDelegate() override;
+
+  void AnimationProgressed(const gfx::Animation* animation) override;
+
+ protected:
+  TabStrip* tab_strip() { return tab_strip_; }
+  Tab* tab() { return tab_; }
+
+ private:
+  TabStrip* const tab_strip_;
+  Tab* const tab_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabAnimationDelegate);
+};
+
+TabAnimationDelegate::TabAnimationDelegate(TabStrip* tab_strip, Tab* tab)
+    : tab_strip_(tab_strip), tab_(tab) {}
+
+TabAnimationDelegate::~TabAnimationDelegate() {}
+
+void TabAnimationDelegate::AnimationProgressed(
+    const gfx::Animation* animation) {
+  tab_->SetVisible(tab_strip_->ShouldTabBeVisible(tab_));
+}
+
+// Animation delegate used when a dragged tab is released. When done sets the
+// dragging state to false.
+class ResetDraggingStateDelegate : public TabAnimationDelegate {
+ public:
+  ResetDraggingStateDelegate(TabStrip* tab_strip, Tab* tab);
+  ~ResetDraggingStateDelegate() override;
+
+  void AnimationEnded(const gfx::Animation* animation) override;
+  void AnimationCanceled(const gfx::Animation* animation) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate);
+};
+
+ResetDraggingStateDelegate::ResetDraggingStateDelegate(TabStrip* tab_strip,
+                                                       Tab* tab)
+    : TabAnimationDelegate(tab_strip, tab) {}
+
+ResetDraggingStateDelegate::~ResetDraggingStateDelegate() {}
+
+void ResetDraggingStateDelegate::AnimationEnded(
+    const gfx::Animation* animation) {
+  tab()->set_dragging(false);
+  AnimationProgressed(animation);  // Forces tab visibility to update.
+}
+
+void ResetDraggingStateDelegate::AnimationCanceled(
+    const gfx::Animation* animation) {
+  AnimationEnded(animation);
+}
+
+// If |dest| contains the point |point_in_source| the event handler from |dest|
+// is returned. Otherwise NULL is returned.
+views::View* ConvertPointToViewAndGetEventHandler(
+    views::View* source,
+    views::View* dest,
+    const gfx::Point& point_in_source) {
+  gfx::Point dest_point(point_in_source);
+  views::View::ConvertPointToTarget(source, dest, &dest_point);
+  return dest->HitTestPoint(dest_point)
+             ? dest->GetEventHandlerForPoint(dest_point)
+             : NULL;
+}
+
+// Gets a tooltip handler for |point_in_source| from |dest|. Note that |dest|
+// should return NULL if it does not contain the point.
+views::View* ConvertPointToViewAndGetTooltipHandler(
+    views::View* source,
+    views::View* dest,
+    const gfx::Point& point_in_source) {
+  gfx::Point dest_point(point_in_source);
+  views::View::ConvertPointToTarget(source, dest, &dest_point);
+  return dest->GetTooltipHandlerForPoint(dest_point);
+}
+
+TabDragController::EventSource EventSourceFromEvent(
+    const ui::LocatedEvent& event) {
+  return event.IsGestureEvent() ? TabDragController::EVENT_SOURCE_TOUCH
+                                : TabDragController::EVENT_SOURCE_MOUSE;
+}
+
+const TabSizeInfo& GetTabSizeInfo() {
+  static TabSizeInfo* tab_size_info = nullptr;
+  if (tab_size_info)
+    return *tab_size_info;
+
+  tab_size_info = new TabSizeInfo;
+  tab_size_info->pinned_tab_width = Tab::GetPinnedWidth();
+  tab_size_info->min_active_width = Tab::GetMinimumActiveSize().width();
+  tab_size_info->min_inactive_width = Tab::GetMinimumInactiveSize().width();
+  tab_size_info->max_size = Tab::GetStandardSize();
+  tab_size_info->tab_overlap = Tab::GetOverlap();
+  tab_size_info->pinned_to_normal_offset = kPinnedToNonPinnedOffset;
+  return *tab_size_info;
+}
+
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// TabStrip::RemoveTabDelegate
+//
+// AnimationDelegate used when removing a tab. Does the necessary cleanup when
+// done.
+class TabStrip::RemoveTabDelegate : public TabAnimationDelegate {
+ public:
+  RemoveTabDelegate(TabStrip* tab_strip, Tab* tab);
+
+  void AnimationEnded(const gfx::Animation* animation) override;
+  void AnimationCanceled(const gfx::Animation* animation) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate);
+};
+
+TabStrip::RemoveTabDelegate::RemoveTabDelegate(TabStrip* tab_strip, Tab* tab)
+    : TabAnimationDelegate(tab_strip, tab) {}
+
+void TabStrip::RemoveTabDelegate::AnimationEnded(
+    const gfx::Animation* animation) {
+  DCHECK(tab()->closing());
+  tab_strip()->RemoveAndDeleteTab(tab());
+
+  // Send the Container a message to simulate a mouse moved event at the current
+  // mouse position. This tickles the Tab the mouse is currently over to show
+  // the "hot" state of the close button.  Note that this is not required (and
+  // indeed may crash!) for removes spawned by non-mouse closes and
+  // drag-detaches.
+  if (!tab_strip()->IsDragSessionActive() &&
+      tab_strip()->ShouldHighlightCloseButtonAfterRemove()) {
+    // The widget can apparently be null during shutdown.
+    views::Widget* widget = tab_strip()->GetWidget();
+    if (widget)
+      widget->SynthesizeMouseMoveEvent();
+  }
+}
+
+void TabStrip::RemoveTabDelegate::AnimationCanceled(
+    const gfx::Animation* animation) {
+  AnimationEnded(animation);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TabStrip, public:
+
+TabStrip::TabStrip(std::unique_ptr<TabStripController> controller)
+    : controller_(std::move(controller)),
+      current_inactive_width_(Tab::GetStandardSize().width()),
+      current_active_width_(Tab::GetStandardSize().width()),
+      animation_container_(new gfx::AnimationContainer()),
+      bounds_animator_(this) {
+  Init();
+  SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
+}
 
 TabStrip::~TabStrip() {
+  for (TabStripObserver& observer : observers_)
+    observer.TabStripDeleted(this);
+
+  // The animations may reference the tabs. Shut down the animation before we
+  // delete the tabs.
+  StopAnimating(false);
+
+  DestroyDragController();
+
+  // Make sure we unhook ourselves as a message loop observer so that we don't
+  // crash in the case where the user closes the window after closing a tab
+  // but before moving the mouse.
+  RemoveMessageLoopObserver();
+
+  // The children (tabs) may callback to us from their destructor. Delete them
+  // so that if they call back we aren't in a weird state.
+  RemoveAllChildViews(true);
 }
 
 void TabStrip::AddObserver(TabStripObserver* observer) {
@@ -17,3 +313,2188 @@
   observers_.RemoveObserver(observer);
 }
 
+int TabStrip::GetMaxX() const {
+  return new_tab_button_bounds_.right();
+}
+
+void TabStrip::SetBackgroundOffset(const gfx::Point& offset) {
+  for (int i = 0; i < tab_count(); ++i)
+    tab_at(i)->set_background_offset(offset);
+  new_tab_button_->set_background_offset(offset);
+}
+
+bool TabStrip::IsRectInWindowCaption(const gfx::Rect& rect) {
+  views::View* v = GetEventHandlerForRect(rect);
+
+  // If there is no control at this location, claim the hit was in the title
+  // bar to get a move action.
+  if (v == this)
+    return true;
+
+  // Check to see if the rect intersects the non-button parts of the new tab
+  // button. The button has a non-rectangular shape, so if it's not in the
+  // visual portions of the button we treat it as a click to the caption.
+  gfx::RectF rect_in_new_tab_coords_f(rect);
+  View::ConvertRectToTarget(this, new_tab_button_, &rect_in_new_tab_coords_f);
+  gfx::Rect rect_in_new_tab_coords =
+      gfx::ToEnclosingRect(rect_in_new_tab_coords_f);
+  if (new_tab_button_->GetLocalBounds().Intersects(rect_in_new_tab_coords) &&
+      !new_tab_button_->HitTestRect(rect_in_new_tab_coords))
+    return true;
+
+  // All other regions, including the new Tab button, should be considered part
+  // of the containing Window's client area so that regular events can be
+  // processed for them.
+  return false;
+}
+
+bool TabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
+  return IsRectInWindowCaption(gfx::Rect(point, gfx::Size(1, 1)));
+}
+
+bool TabStrip::IsTabStripCloseable() const {
+  return !IsDragSessionActive();
+}
+
+bool TabStrip::IsTabStripEditable() const {
+  return !IsDragSessionActive() && !IsActiveDropTarget();
+}
+
+bool TabStrip::IsTabCrashed(int tab_index) const {
+  return tab_at(tab_index)->data().IsCrashed();
+}
+
+bool TabStrip::TabHasNetworkError(int tab_index) const {
+  return tab_at(tab_index)->data().network_state == TabNetworkState::kError;
+}
+
+TabAlertState TabStrip::GetTabAlertState(int tab_index) const {
+  return tab_at(tab_index)->data().alert_state;
+}
+
+void TabStrip::UpdateLoadingAnimations() {
+  for (int i = 0; i < tab_count(); i++)
+    tab_at(i)->StepLoadingAnimation();
+}
+
+void TabStrip::SetStackedLayout(bool stacked_layout) {
+  if (stacked_layout == stacked_layout_)
+    return;
+
+  const int active_index = controller_->GetActiveIndex();
+  int active_center = 0;
+  if (active_index != -1) {
+    active_center =
+        ideal_bounds(active_index).x() + ideal_bounds(active_index).width() / 2;
+  }
+  stacked_layout_ = stacked_layout;
+  SetResetToShrinkOnExit(false);
+  SwapLayoutIfNecessary();
+  // When transitioning to stacked try to keep the active tab centered.
+  if (touch_layout_ && active_index != -1) {
+    touch_layout_->SetActiveTabLocation(active_center -
+                                        ideal_bounds(active_index).width() / 2);
+    AnimateToIdealBounds();
+  }
+
+  for (int i = 0; i < tab_count(); ++i)
+    tab_at(i)->HideCloseButtonForInactiveTabsChanged();
+}
+
+gfx::Rect TabStrip::GetNewTabButtonBounds() {
+  return new_tab_button_->bounds();
+}
+
+bool TabStrip::SizeTabButtonToTopOfTabStrip() {
+  // Extend the button to the screen edge in maximized and immersive fullscreen.
+  views::Widget* widget = GetWidget();
+  return browser_defaults::kSizeTabButtonToTopOfTabStrip ||
+         (widget && (widget->IsMaximized() || widget->IsFullscreen()));
+}
+
+void TabStrip::StartHighlight(int model_index) {
+  tab_at(model_index)->StartPulse();
+}
+
+void TabStrip::StopAllHighlighting() {
+  for (int i = 0; i < tab_count(); ++i)
+    tab_at(i)->StopPulse();
+}
+
+void TabStrip::AddTabAt(int model_index, TabRendererData data, bool is_active) {
+  Tab* tab = new Tab(this, animation_container_.get());
+  AddChildView(tab);
+  const bool pinned = data.pinned;
+  tab->SetData(std::move(data));
+  UpdateTabsClosingMap(model_index, 1);
+  tabs_.Add(tab, model_index);
+
+  if (touch_layout_) {
+    GenerateIdealBoundsForPinnedTabs(NULL);
+    int add_types = 0;
+    if (pinned)
+      add_types |= StackedTabStripLayout::kAddTypePinned;
+    if (is_active)
+      add_types |= StackedTabStripLayout::kAddTypeActive;
+    touch_layout_->AddTab(model_index, add_types, GetStartXForNormalTabs());
+  }
+
+  // Don't animate the first tab, it looks weird, and don't animate anything
+  // if the containing window isn't visible yet.
+  if (tab_count() > 1 && GetWidget() && GetWidget()->IsVisible())
+    StartInsertTabAnimation(model_index);
+  else
+    DoLayout();
+
+  SwapLayoutIfNecessary();
+
+  for (TabStripObserver& observer : observers_)
+    observer.TabStripAddedTabAt(this, model_index);
+
+  // Stop dragging when a new tab is added and dragging a window. Doing
+  // otherwise results in a confusing state if the user attempts to reattach. We
+  // could allow this and make TabDragController update itself during the add,
+  // but this comes up infrequently enough that it's not worth the complexity.
+  //
+  // At the start of AddTabAt() the model and tabs are out sync. Any queries to
+  // find a tab given a model index can go off the end of |tabs_|. As such, it
+  // is important that we complete the drag *after* adding the tab so that the
+  // model and tabstrip are in sync.
+  if (drag_controller_.get() && !drag_controller_->is_mutating() &&
+      drag_controller_->is_dragging_window()) {
+    EndDrag(END_DRAG_COMPLETE);
+  }
+}
+
+void TabStrip::MoveTab(int from_model_index,
+                       int to_model_index,
+                       TabRendererData data) {
+  DCHECK_GT(tabs_.view_size(), 0);
+  const Tab* last_tab = GetLastVisibleTab();
+  tab_at(from_model_index)->SetData(std::move(data));
+  if (touch_layout_) {
+    tabs_.MoveViewOnly(from_model_index, to_model_index);
+    int pinned_count = 0;
+    GenerateIdealBoundsForPinnedTabs(&pinned_count);
+    touch_layout_->MoveTab(from_model_index, to_model_index,
+                           controller_->GetActiveIndex(),
+                           GetStartXForNormalTabs(), pinned_count);
+  } else {
+    tabs_.Move(from_model_index, to_model_index);
+  }
+  StartMoveTabAnimation();
+  if (TabDragController::IsAttachedTo(this) &&
+      (last_tab != GetLastVisibleTab() || last_tab->dragging())) {
+    new_tab_button_->SetVisible(false);
+  }
+  SwapLayoutIfNecessary();
+
+  for (TabStripObserver& observer : observers_)
+    observer.TabStripMovedTab(this, from_model_index, to_model_index);
+}
+
+void TabStrip::RemoveTabAt(content::WebContents* contents, int model_index) {
+  if (touch_layout_) {
+    Tab* tab = tab_at(model_index);
+    tab->set_closing(true);
+    int old_x = tabs_.ideal_bounds(model_index).x();
+    // We still need to paint the tab until we actually remove it. Put it in
+    // tabs_closing_map_ so we can find it.
+    RemoveTabFromViewModel(model_index);
+    touch_layout_->RemoveTab(model_index,
+                             GenerateIdealBoundsForPinnedTabs(NULL), old_x);
+    ScheduleRemoveTabAnimation(tab);
+  } else if (in_tab_close_ && model_index != GetModelCount()) {
+    StartMouseInitiatedRemoveTabAnimation(model_index);
+  } else {
+    StartRemoveTabAnimation(model_index);
+  }
+  SwapLayoutIfNecessary();
+
+  for (TabStripObserver& observer : observers_)
+    observer.TabStripRemovedTabAt(this, model_index);
+
+  // Stop dragging when a new tab is removed and dragging a window. Doing
+  // otherwise results in a confusing state if the user attempts to reattach. We
+  // could allow this and make TabDragController update itself during the
+  // remove operation, but this comes up infrequently enough that it's not worth
+  // the complexity.
+  //
+  // At the start of RemoveTabAt() the model and tabs are out sync. Any queries
+  // to find a tab given a model index can go off the end of |tabs_|. As such,
+  // it is important that we complete the drag *after* removing the tab so that
+  // the model and tabstrip are in sync.
+  if (contents && drag_controller_.get() && !drag_controller_->is_mutating() &&
+      drag_controller_->IsDraggingTab(contents)) {
+    EndDrag(END_DRAG_COMPLETE);
+  }
+}
+
+void TabStrip::SetTabData(int model_index, TabRendererData data) {
+  Tab* tab = tab_at(model_index);
+  bool pinned_state_changed = tab->data().pinned != data.pinned;
+  tab->SetData(std::move(data));
+
+  if (pinned_state_changed) {
+    if (touch_layout_) {
+      int pinned_tab_count = 0;
+      int start_x = GenerateIdealBoundsForPinnedTabs(&pinned_tab_count);
+      touch_layout_->SetXAndPinnedCount(start_x, pinned_tab_count);
+    }
+    if (GetWidget() && GetWidget()->IsVisible())
+      StartPinnedTabAnimation();
+    else
+      DoLayout();
+  }
+  SwapLayoutIfNecessary();
+}
+
+bool TabStrip::ShouldTabBeVisible(const Tab* tab) const {
+  // Detached tabs should always be invisible (as they close).
+  if (tab->detached())
+    return false;
+
+  // When stacking tabs, all tabs should always be visible.
+  if (stacked_layout_)
+    return true;
+
+  // If the tab is currently clipped, it shouldn't be visible.  Note that we
+  // allow dragged tabs to draw over the "New Tab button" region as well,
+  // because either the New Tab button will be hidden, or the dragged tabs will
+  // be animating back to their normal positions and we don't want to hide them
+  // in the New Tab button region in case they re-appear after leaving it.
+  // (This prevents flickeriness.)  We never draw non-dragged tabs in New Tab
+  // button area, even when the button is invisible, so that they don't appear
+  // to "pop in" when the button disappears.
+  // TODO: Probably doesn't work for RTL
+  int right_edge = tab->bounds().right();
+  const int visible_width = tab->dragging() ? width() : GetTabAreaWidth();
+  if (right_edge > visible_width)
+    return false;
+
+  // Non-clipped dragging tabs should always be visible.
+  if (tab->dragging())
+    return true;
+
+  // Let all non-clipped closing tabs be visible.  These will probably finish
+  // closing before the user changes the active tab, so there's little reason to
+  // try and make the more complex logic below apply.
+  if (tab->closing())
+    return true;
+
+  // Now we need to check whether the tab isn't currently clipped, but could
+  // become clipped if we changed the active tab, widening either this tab or
+  // the tabstrip portion before it.
+
+  // Pinned tabs don't change size when activated, so any tab in the pinned tab
+  // region is safe.
+  if (tab->data().pinned)
+    return true;
+
+  // If the active tab is on or before this tab, we're safe.
+  if (controller_->GetActiveIndex() <= GetModelIndexOfTab(tab))
+    return true;
+
+  // We need to check what would happen if the active tab were to move to this
+  // tab or before.
+  return (right_edge + current_active_width_ - current_inactive_width_) <=
+         GetTabAreaWidth();
+}
+
+void TabStrip::PrepareForCloseAt(int model_index, CloseTabSource source) {
+  if (!in_tab_close_ && IsAnimating()) {
+    // Cancel any current animations. We do this as remove uses the current
+    // ideal bounds and we need to know ideal bounds is in a good state.
+    StopAnimating(true);
+  }
+
+  if (!GetWidget())
+    return;
+
+  int model_count = GetModelCount();
+  if (model_count > 1 && model_index != model_count - 1) {
+    // The user is about to close a tab other than the last tab. Set
+    // available_width_for_tabs_ so that if we do a layout we don't position a
+    // tab past the end of the second to last tab. We do this so that as the
+    // user closes tabs with the mouse a tab continues to fall under the mouse.
+    Tab* last_tab = tab_at(model_count - 1);
+    Tab* tab_being_removed = tab_at(model_index);
+    available_width_for_tabs_ = last_tab->bounds().right() -
+                                tab_being_removed->width() + Tab::GetOverlap();
+    if (model_index == 0 && tab_being_removed->data().pinned &&
+        !tab_at(1)->data().pinned) {
+      available_width_for_tabs_ -= kPinnedToNonPinnedOffset;
+    }
+  }
+
+  in_tab_close_ = true;
+  resize_layout_timer_.Stop();
+  if (source == CLOSE_TAB_FROM_TOUCH) {
+    StartResizeLayoutTabsFromTouchTimer();
+  } else {
+    AddMessageLoopObserver();
+  }
+}
+
+void TabStrip::SetSelection(const ui::ListSelectionModel& old_selection,
+                            const ui::ListSelectionModel& new_selection) {
+  if (old_selection.active() != new_selection.active()) {
+    if (old_selection.active() >= 0)
+      tab_at(old_selection.active())->ActiveStateChanged();
+    if (new_selection.active() >= 0)
+      tab_at(new_selection.active())->ActiveStateChanged();
+  }
+
+  if (touch_layout_) {
+    touch_layout_->SetActiveIndex(new_selection.active());
+    // Only start an animation if we need to. Otherwise clicking on an
+    // unselected tab and dragging won't work because dragging is only allowed
+    // if not animating.
+    if (!views::ViewModelUtils::IsAtIdealBounds(tabs_))
+      AnimateToIdealBounds();
+    SchedulePaint();
+  } else {
+    // We have "tiny tabs" if the tabs are so tiny that the unselected ones are
+    // a different size to the selected ones.
+    bool tiny_tabs = current_inactive_width_ != current_active_width_;
+    if (!IsAnimating() && (!in_tab_close_ || tiny_tabs)) {
+      DoLayout();
+    } else {
+      SchedulePaint();
+    }
+  }
+
+  // Use STLSetDifference to get the indices of elements newly selected
+  // and no longer selected, since selected_indices() is always sorted.
+  ui::ListSelectionModel::SelectedIndices no_longer_selected =
+      base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>(
+          old_selection.selected_indices(), new_selection.selected_indices());
+  ui::ListSelectionModel::SelectedIndices newly_selected =
+      base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>(
+          new_selection.selected_indices(), old_selection.selected_indices());
+
+  // Fire accessibility events that reflect the changes to selection.
+  for (size_t i = 0; i < no_longer_selected.size(); ++i) {
+    tab_at(no_longer_selected[i])
+        ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_REMOVE, true);
+  }
+  for (size_t i = 0; i < newly_selected.size(); ++i) {
+    tab_at(newly_selected[i])
+        ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_ADD, true);
+  }
+  tab_at(new_selection.active())
+      ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
+}
+
+void TabStrip::TabTitleChangedNotLoading(int model_index) {
+  tab_at(model_index)->TabTitleChangedNotLoading();
+}
+
+void TabStrip::SetTabNeedsAttention(int model_index, bool attention) {
+  tab_at(model_index)->SetTabNeedsAttention(attention);
+}
+
+int TabStrip::GetModelIndexOfTab(const Tab* tab) const {
+  return tabs_.GetIndexOfView(tab);
+}
+
+int TabStrip::GetModelCount() const {
+  return controller_->GetCount();
+}
+
+bool TabStrip::IsValidModelIndex(int model_index) const {
+  return controller_->IsValidIndex(model_index);
+}
+
+bool TabStrip::IsDragSessionActive() const {
+  return drag_controller_.get() != NULL;
+}
+
+bool TabStrip::IsActiveDropTarget() const {
+  for (int i = 0; i < tab_count(); ++i) {
+    Tab* tab = tab_at(i);
+    if (tab->dragging())
+      return true;
+  }
+  return false;
+}
+
+SkAlpha TabStrip::GetInactiveAlpha(bool for_new_tab_button) const {
+#if defined(OS_CHROMEOS)
+  static const SkAlpha kInactiveTabAlphaAsh = 230;
+  const SkAlpha base_alpha = kInactiveTabAlphaAsh;
+#else
+  static const SkAlpha kInactiveTabAlphaGlass = 200;
+  static const SkAlpha kInactiveTabAlphaOpaque = 255;
+  const SkAlpha base_alpha = TitlebarBackgroundIsTransparent()
+                                 ? kInactiveTabAlphaGlass
+                                 : kInactiveTabAlphaOpaque;
+#endif  // OS_CHROMEOS
+  static const double kMultiSelectionMultiplier = 0.6;
+  return (for_new_tab_button || (GetSelectionModel().size() <= 1))
+             ? base_alpha
+             : static_cast<SkAlpha>(kMultiSelectionMultiplier * base_alpha);
+}
+
+bool TabStrip::IsAnimating() const {
+  return bounds_animator_.IsAnimating();
+}
+
+void TabStrip::StopAnimating(bool layout) {
+  if (!IsAnimating())
+    return;
+
+  bounds_animator_.Cancel();
+
+  if (layout)
+    DoLayout();
+}
+
+void TabStrip::FileSupported(const GURL& url, bool supported) {
+  if (drop_info_.get() && drop_info_->url == url)
+    drop_info_->file_supported = supported;
+}
+
+const ui::ListSelectionModel& TabStrip::GetSelectionModel() const {
+  return controller_->GetSelectionModel();
+}
+
+bool TabStrip::SupportsMultipleSelection() {
+  // TODO: currently only allow single selection in touch layout mode.
+  return touch_layout_ == nullptr;
+}
+
+bool TabStrip::ShouldHideCloseButtonForInactiveTabs() {
+  return touch_layout_ != nullptr;
+}
+
+bool TabStrip::MaySetClip() {
+  // Only touch layout needs to restrict the clip.
+  return touch_layout_ || IsStackingDraggedTabs();
+}
+
+void TabStrip::SelectTab(Tab* tab) {
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    controller_->SelectTab(model_index);
+}
+
+void TabStrip::ExtendSelectionTo(Tab* tab) {
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    controller_->ExtendSelectionTo(model_index);
+}
+
+void TabStrip::ToggleSelected(Tab* tab) {
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    controller_->ToggleSelected(model_index);
+}
+
+void TabStrip::AddSelectionFromAnchorTo(Tab* tab) {
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    controller_->AddSelectionFromAnchorTo(model_index);
+}
+
+void TabStrip::CloseTab(Tab* tab, CloseTabSource source) {
+  if (tab->closing()) {
+    // If the tab is already closing, close the next tab. We do this so that the
+    // user can rapidly close tabs by clicking the close button and not have
+    // the animations interfere with that.
+    const int closed_tab_index = FindClosingTab(tab).first->first;
+    if (closed_tab_index < GetModelCount())
+      controller_->CloseTab(closed_tab_index, source);
+    return;
+  }
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    controller_->CloseTab(model_index, source);
+}
+
+void TabStrip::ToggleTabAudioMute(Tab* tab) {
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    controller_->ToggleTabAudioMute(model_index);
+}
+
+void TabStrip::ShowContextMenuForTab(Tab* tab,
+                                     const gfx::Point& p,
+                                     ui::MenuSourceType source_type) {
+  controller_->ShowContextMenuForTab(tab, p, source_type);
+}
+
+bool TabStrip::IsActiveTab(const Tab* tab) const {
+  int model_index = GetModelIndexOfTab(tab);
+  return IsValidModelIndex(model_index) &&
+         controller_->IsActiveTab(model_index);
+}
+
+bool TabStrip::IsTabSelected(const Tab* tab) const {
+  int model_index = GetModelIndexOfTab(tab);
+  return IsValidModelIndex(model_index) &&
+         controller_->IsTabSelected(model_index);
+}
+
+bool TabStrip::IsTabPinned(const Tab* tab) const {
+  if (tab->closing())
+    return false;
+
+  int model_index = GetModelIndexOfTab(tab);
+  return IsValidModelIndex(model_index) &&
+         controller_->IsTabPinned(model_index);
+}
+
+void TabStrip::MaybeStartDrag(
+    Tab* tab,
+    const ui::LocatedEvent& event,
+    const ui::ListSelectionModel& original_selection) {
+  // Don't accidentally start any drag operations during animations if the
+  // mouse is down... during an animation tabs are being resized automatically,
+  // so the View system can misinterpret this easily if the mouse is down that
+  // the user is dragging.
+  if (IsAnimating() || tab->closing() ||
+      controller_->HasAvailableDragActions() == 0) {
+    return;
+  }
+
+  int model_index = GetModelIndexOfTab(tab);
+  if (!IsValidModelIndex(model_index)) {
+    CHECK(false);
+    return;
+  }
+  Tabs tabs;
+  int size_to_selected = 0;
+  int x = tab->GetMirroredXInView(event.x());
+  int y = event.y();
+  // Build the set of selected tabs to drag and calculate the offset from the
+  // first selected tab.
+  for (int i = 0; i < tab_count(); ++i) {
+    Tab* other_tab = tab_at(i);
+    if (IsTabSelected(other_tab)) {
+      tabs.push_back(other_tab);
+      if (other_tab == tab) {
+        size_to_selected = GetSizeNeededForTabs(tabs);
+        x = size_to_selected - tab->width() + x;
+      }
+    }
+  }
+  DCHECK(!tabs.empty());
+  DCHECK(base::ContainsValue(tabs, tab));
+  ui::ListSelectionModel selection_model;
+  if (!original_selection.IsSelected(model_index))
+    selection_model = original_selection;
+  // Delete the existing DragController before creating a new one. We do this as
+  // creating the DragController remembers the WebContents delegates and we need
+  // to make sure the existing DragController isn't still a delegate.
+  drag_controller_.reset();
+  TabDragController::MoveBehavior move_behavior = TabDragController::REORDER;
+  // Use MOVE_VISIBLE_TABS in the following conditions:
+  // . Mouse event generated from touch and the left button is down (the right
+  //   button corresponds to a long press, which we want to reorder).
+  // . Gesture tap down and control key isn't down.
+  // . Real mouse event and control is down. This is mostly for testing.
+  DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
+         event.type() == ui::ET_GESTURE_TAP_DOWN);
+  if (touch_layout_ &&
+      ((event.type() == ui::ET_MOUSE_PRESSED &&
+        (((event.flags() & ui::EF_FROM_TOUCH) &&
+          static_cast<const ui::MouseEvent&>(event).IsLeftMouseButton()) ||
+         (!(event.flags() & ui::EF_FROM_TOUCH) &&
+          static_cast<const ui::MouseEvent&>(event).IsControlDown()))) ||
+       (event.type() == ui::ET_GESTURE_TAP_DOWN && !event.IsControlDown()))) {
+    move_behavior = TabDragController::MOVE_VISIBLE_TABS;
+  }
+
+  drag_controller_.reset(new TabDragController);
+  drag_controller_->Init(this, tab, tabs, gfx::Point(x, y), event.x(),
+                         std::move(selection_model), move_behavior,
+                         EventSourceFromEvent(event));
+}
+
+void TabStrip::ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
+  if (drag_controller_.get() &&
+      drag_controller_->event_source() == EventSourceFromEvent(event)) {
+    gfx::Point screen_location(event.location());
+    views::View::ConvertPointToScreen(view, &screen_location);
+    drag_controller_->Drag(screen_location);
+  }
+}
+
+bool TabStrip::EndDrag(EndDragReason reason) {
+  if (!drag_controller_.get())
+    return false;
+  bool started_drag = drag_controller_->started_drag();
+  drag_controller_->EndDrag(reason);
+  return started_drag;
+}
+
+Tab* TabStrip::GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) {
+  gfx::Point local_point = tab_in_tab_coordinates;
+  ConvertPointToTarget(tab, this, &local_point);
+
+  views::View* view = GetEventHandlerForPoint(local_point);
+  if (!view)
+    return NULL;  // No tab contains the point.
+
+  // Walk up the view hierarchy until we find a tab, or the TabStrip.
+  while (view && view != this && view->id() != VIEW_ID_TAB)
+    view = view->parent();
+
+  return view && view->id() == VIEW_ID_TAB ? static_cast<Tab*>(view) : NULL;
+}
+
+void TabStrip::OnMouseEventInTab(views::View* source,
+                                 const ui::MouseEvent& event) {
+  UpdateStackedLayoutFromMouseEvent(source, event);
+}
+
+bool TabStrip::ShouldPaintTab(
+    const Tab* tab,
+    const base::Callback<gfx::Path(const gfx::Size&)>& border_callback,
+    gfx::Path* clip) {
+  if (!MaySetClip())
+    return true;
+
+  int index = GetModelIndexOfTab(tab);
+  if (index == -1)
+    return true;  // Tab is closing, paint it all.
+
+  int active_index = IsStackingDraggedTabs() ? controller_->GetActiveIndex()
+                                             : touch_layout_->active_index();
+  if (active_index == tab_count())
+    active_index--;
+
+  const int current_x = tab_at(index)->x();
+  if (index < active_index) {
+    const int next_x = tab_at(index + 1)->x();
+    if (current_x == next_x)
+      return false;
+
+    if (current_x > next_x)
+      return true;  // Can happen during dragging.
+
+    *clip = border_callback.Run(tab_at(index + 1)->size());
+    clip->offset(SkIntToScalar(next_x - current_x), 0);
+  } else if (index > active_index && index > 0) {
+    const gfx::Rect& previous_bounds(tab_at(index - 1)->bounds());
+    const int previous_x = previous_bounds.x();
+    if (current_x == previous_x)
+      return false;
+
+    if (current_x < previous_x)
+      return true;  // Can happen during dragging.
+
+    if (previous_bounds.right() - Tab::GetOverlap() != current_x) {
+      *clip = border_callback.Run(tab_at(index - 1)->size());
+      clip->offset(SkIntToScalar(previous_x - current_x), 0);
+    }
+  }
+  return true;
+}
+
+bool TabStrip::CanPaintThrobberToLayer() const {
+  // Disable layer-painting of throbbers if dragging, if any tab animation is in
+  // progress, or if stacked tabs are enabled. Also disable in fullscreen: when
+  // "immersive" the tab strip could be sliding in or out; for other modes,
+  // there's no tab strip.
+  const bool dragging = drag_controller_ && drag_controller_->started_drag();
+  const views::Widget* widget = GetWidget();
+  return widget && !touch_layout_ && !dragging && !IsAnimating() &&
+         !widget->IsFullscreen();
+}
+
+SkColor TabStrip::GetToolbarTopSeparatorColor() const {
+  return controller_->GetToolbarTopSeparatorColor();
+}
+
+// Returns the accessible tab name for the tab.
+base::string16 TabStrip::GetAccessibleTabName(const Tab* tab) const {
+  int model_index = GetModelIndexOfTab(tab);
+  if (IsValidModelIndex(model_index))
+    return controller_->GetAccessibleTabName(tab);
+  return base::string16();
+}
+
+int TabStrip::GetBackgroundResourceId(bool* custom_image) const {
+  const ui::ThemeProvider* tp = GetThemeProvider();
+
+  if (TitlebarBackgroundIsTransparent()) {
+    const int kBackgroundIdGlass = IDR_THEME_TAB_BACKGROUND_V;
+    *custom_image = tp->HasCustomImage(kBackgroundIdGlass);
+    return kBackgroundIdGlass;
+  }
+
+  // If a custom theme does not provide a replacement tab background, but does
+  // provide a replacement frame image, HasCustomImage() on the tab background
+  // ID will return false, but the theme provider will make a custom image from
+  // the frame image.  Furthermore, since the theme provider will create the
+  // incognito frame image from the normal frame image, in incognito mode we
+  // need to look for a custom incognito _or_ regular frame image.
+  const bool incognito = controller_->IsIncognito();
+  const int id =
+      incognito ? IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
+  *custom_image = tp->HasCustomImage(id) ||
+                  tp->HasCustomImage(IDR_THEME_FRAME) ||
+                  (incognito && tp->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
+  return id;
+}
+
+void TabStrip::MouseMovedOutOfHost() {
+  ResizeLayoutTabs();
+  if (reset_to_shrink_on_exit_) {
+    reset_to_shrink_on_exit_ = false;
+    SetStackedLayout(false);
+    controller_->StackedLayoutMaybeChanged();
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TabStrip, views::View overrides:
+
+void TabStrip::Layout() {
+  // Only do a layout if our size changed.
+  if (last_layout_size_ == size())
+    return;
+  if (IsDragSessionActive())
+    return;
+  DoLayout();
+}
+
+void TabStrip::PaintChildren(const views::PaintInfo& paint_info) {
+  // The view order doesn't match the paint order (tabs_ contains the tab
+  // ordering). Additionally we need to paint the tabs that are closing in
+  // |tabs_closing_map_|.
+  bool is_dragging = false;
+  Tab* active_tab = NULL;
+  Tabs tabs_dragging;
+  Tabs selected_tabs;
+
+  {
+    // We pass false for |lcd_text_requires_opaque_layer| so that background
+    // tab titles will get LCD AA.  These are rendered opaquely on an opaque tab
+    // background before the layer is composited, so this is safe.
+    ui::CompositingRecorder opacity_recorder(paint_info.context(),
+                                             GetInactiveAlpha(false), false);
+
+    PaintClosingTabs(tab_count(), paint_info);
+
+    int active_tab_index = -1;
+    for (int i = tab_count() - 1; i >= 0; --i) {
+      Tab* tab = tab_at(i);
+      if (tab->dragging() && !stacked_layout_) {
+        is_dragging = true;
+        if (tab->IsActive()) {
+          active_tab = tab;
+          active_tab_index = i;
+        } else {
+          tabs_dragging.push_back(tab);
+        }
+      } else if (!tab->IsActive()) {
+        if (!tab->IsSelected()) {
+          if (!stacked_layout_)
+            tab->Paint(paint_info);
+        } else {
+          selected_tabs.push_back(tab);
+        }
+      } else {
+        active_tab = tab;
+        active_tab_index = i;
+      }
+      PaintClosingTabs(i, paint_info);
+    }
+
+    // Draw from the left and then the right if we're in touch mode.
+    if (stacked_layout_ && active_tab_index >= 0) {
+      for (int i = 0; i < active_tab_index; ++i) {
+        Tab* tab = tab_at(i);
+        tab->Paint(paint_info);
+      }
+
+      for (int i = tab_count() - 1; i > active_tab_index; --i) {
+        Tab* tab = tab_at(i);
+        tab->Paint(paint_info);
+      }
+    }
+  }
+
+  // Now selected but not active. We don't want these dimmed if using native
+  // frame, so they're painted after initial pass.
+  for (size_t i = 0; i < selected_tabs.size(); ++i)
+    selected_tabs[i]->Paint(paint_info);
+
+  // Next comes the active tab.
+  if (active_tab && !is_dragging)
+    active_tab->Paint(paint_info);
+
+  // Paint the New Tab button.
+  if (new_tab_button_->state() == views::Button::STATE_PRESSED) {
+    new_tab_button_->Paint(paint_info);
+  } else {
+    // Match the inactive tab opacity for non-pressed states.  See comments in
+    // NewTabButton::PaintFill() for why we don't do this for the pressed state.
+    // This call doesn't need to set |lcd_text_requires_opaque_layer| to false
+    // because no text will be drawn.
+    ui::CompositingRecorder opacity_recorder(paint_info.context(),
+                                             GetInactiveAlpha(true), true);
+    new_tab_button_->Paint(paint_info);
+  }
+
+  // And the dragged tabs.
+  for (size_t i = 0; i < tabs_dragging.size(); ++i)
+    tabs_dragging[i]->Paint(paint_info);
+
+  // If the active tab is being dragged, it goes last.
+  if (active_tab && is_dragging)
+    active_tab->Paint(paint_info);
+
+  // Keep the recording scales consistent for the tab strip and its children.
+  // See crbug/753911
+  ui::PaintRecorder recorder(paint_info.context(),
+                             paint_info.paint_recording_size(),
+                             paint_info.paint_recording_scale_x(),
+                             paint_info.paint_recording_scale_y(), nullptr);
+
+  gfx::Canvas* canvas = recorder.canvas();
+  if (active_tab) {
+    canvas->sk_canvas()->clipRect(
+        gfx::RectToSkRect(active_tab->GetMirroredBounds()),
+        SkClipOp::kDifference);
+  }
+  BrowserView::Paint1pxHorizontalLine(canvas, GetToolbarTopSeparatorColor(),
+                                      GetLocalBounds(), true);
+}
+
+const char* TabStrip::GetClassName() const {
+  static const char kViewClassName[] = "TabStrip";
+  return kViewClassName;
+}
+
+gfx::Size TabStrip::CalculatePreferredSize() const {
+  int needed_tab_width;
+  if (touch_layout_ || adjust_layout_) {
+    // For stacked tabs the minimum size is calculated as the size needed to
+    // handle showing any number of tabs.
+    needed_tab_width =
+        Tab::GetTouchWidth() + (2 * kStackedPadding * kMaxStackedCount);
+  } else {
+    // Otherwise the minimum width is based on the actual number of tabs.
+    const int pinned_tab_count = GetPinnedTabCount();
+    needed_tab_width = pinned_tab_count * Tab::GetPinnedWidth();
+    const int remaining_tab_count = tab_count() - pinned_tab_count;
+    const int min_selected_width = Tab::GetMinimumActiveSize().width();
+    const int min_unselected_width = Tab::GetMinimumInactiveSize().width();
+    if (remaining_tab_count > 0) {
+      needed_tab_width += kPinnedToNonPinnedOffset + min_selected_width +
+                          ((remaining_tab_count - 1) * min_unselected_width);
+    }
+
+    const int overlap = Tab::GetOverlap();
+    if (tab_count() > 1)
+      needed_tab_width -= (tab_count() - 1) * overlap;
+
+    // Don't let the tabstrip shrink smaller than is necessary to show one tab,
+    // and don't force it to be larger than is necessary to show 20 tabs.
+    const int largest_min_tab_width =
+        min_selected_width + 19 * (min_unselected_width - overlap);
+    needed_tab_width = std::min(std::max(needed_tab_width, min_selected_width),
+                                largest_min_tab_width);
+  }
+  return gfx::Size(needed_tab_width + GetNewTabButtonWidth(),
+                   Tab::GetMinimumInactiveSize().height());
+}
+
+void TabStrip::OnDragEntered(const DropTargetEvent& event) {
+  // Force animations to stop, otherwise it makes the index calculation tricky.
+  StopAnimating(true);
+
+  UpdateDropIndex(event);
+
+  GURL url;
+  base::string16 title;
+
+  // Check whether the event data includes supported drop data.
+  if (event.data().GetURLAndTitle(ui::OSExchangeData::CONVERT_FILENAMES, &url,
+                                  &title) &&
+      url.is_valid()) {
+    drop_info_->url = url;
+
+    // For file:// URLs, kick off a MIME type request in case they're dropped.
+    if (url.SchemeIsFile())
+      controller_->CheckFileSupported(url);
+  }
+}
+
+int TabStrip::OnDragUpdated(const DropTargetEvent& event) {
+  // Update the drop index even if the file is unsupported, to allow
+  // dragging a file to the contents of another tab.
+  UpdateDropIndex(event);
+
+  if (!drop_info_->file_supported ||
+      drop_info_->url.SchemeIs(url::kJavaScriptScheme))
+    return ui::DragDropTypes::DRAG_NONE;
+
+  return GetDropEffect(event);
+}
+
+void TabStrip::OnDragExited() {
+  SetDropIndex(-1, false);
+}
+
+int TabStrip::OnPerformDrop(const DropTargetEvent& event) {
+  if (!drop_info_.get())
+    return ui::DragDropTypes::DRAG_NONE;
+
+  const int drop_index = drop_info_->drop_index;
+  const bool drop_before = drop_info_->drop_before;
+  const bool file_supported = drop_info_->file_supported;
+
+  // Hide the drop indicator.
+  SetDropIndex(-1, false);
+
+  // Do nothing if the file was unsupported, the URL is invalid, or this is a
+  // javascript: URL (prevent self-xss). The URL may have been changed after
+  // |drop_info_| was created.
+  GURL url;
+  base::string16 title;
+  if (!file_supported ||
+      !event.data().GetURLAndTitle(ui::OSExchangeData::CONVERT_FILENAMES, &url,
+                                   &title) ||
+      !url.is_valid() || url.SchemeIs(url::kJavaScriptScheme))
+    return ui::DragDropTypes::DRAG_NONE;
+
+  controller_->PerformDrop(drop_before, drop_index, url);
+
+  return GetDropEffect(event);
+}
+
+void TabStrip::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  node_data->role = ui::AX_ROLE_TAB_LIST;
+}
+
+views::View* TabStrip::GetTooltipHandlerForPoint(const gfx::Point& point) {
+  if (!HitTestPoint(point))
+    return NULL;
+
+  if (!touch_layout_) {
+    // Return any view that isn't a Tab or this TabStrip immediately. We don't
+    // want to interfere.
+    views::View* v = View::GetTooltipHandlerForPoint(point);
+    if (v && v != this && strcmp(v->GetClassName(), Tab::kViewClassName))
+      return v;
+
+    views::View* tab = FindTabHitByPoint(point);
+    if (tab)
+      return tab;
+  } else {
+    if (new_tab_button_->visible()) {
+      views::View* view =
+          ConvertPointToViewAndGetTooltipHandler(this, new_tab_button_, point);
+      if (view)
+        return view;
+    }
+    Tab* tab = FindTabForEvent(point);
+    if (tab)
+      return ConvertPointToViewAndGetTooltipHandler(this, tab, point);
+  }
+  return this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TabStrip, private:
+
+void TabStrip::Init() {
+  set_id(VIEW_ID_TAB_STRIP);
+  // So we get enter/exit on children to switch stacked layout on and off.
+  set_notify_enter_exit_on_child(true);
+
+  new_tab_button_bounds_.set_size(GetLayoutSize(NEW_TAB_BUTTON));
+  new_tab_button_bounds_.Inset(0, 0, 0, -NewTabButton::GetTopOffset());
+  new_tab_button_ = new NewTabButton(this, this);
+  new_tab_button_->SetTooltipText(
+      l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB));
+  new_tab_button_->SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB));
+  new_tab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
+                                     views::ImageButton::ALIGN_BOTTOM);
+  new_tab_button_->SetEventTargeter(
+      std::make_unique<views::ViewTargeter>(new_tab_button_));
+  AddChildView(new_tab_button_);
+
+  if (drop_indicator_width == 0) {
+    // Direction doesn't matter, both images are the same size.
+    gfx::ImageSkia* drop_image = GetDropArrowImage(true);
+    drop_indicator_width = drop_image->width();
+    drop_indicator_height = drop_image->height();
+  }
+}
+
+void TabStrip::StartInsertTabAnimation(int model_index) {
+  PrepareForAnimation();
+
+  // The TabStrip can now use its entire width to lay out Tabs.
+  in_tab_close_ = false;
+  available_width_for_tabs_ = -1;
+
+  GenerateIdealBounds();
+
+  // Set the current bounds to be the correct place but 0 width.
+  Tab* tab = tab_at(model_index);
+  if (model_index == 0) {
+    tab->SetBounds(0, ideal_bounds(model_index).y(), 0,
+                   ideal_bounds(model_index).height());
+  } else {
+    Tab* prev_tab = tab_at(model_index - 1);
+    tab->SetBounds(prev_tab->bounds().right() - Tab::GetOverlap(),
+                   ideal_bounds(model_index).y(), 0,
+                   ideal_bounds(model_index).height());
+  }
+
+  // Animate in to the full width.
+  AnimateToIdealBounds();
+}
+
+void TabStrip::StartMoveTabAnimation() {
+  PrepareForAnimation();
+  GenerateIdealBounds();
+  AnimateToIdealBounds();
+}
+
+void TabStrip::StartRemoveTabAnimation(int model_index) {
+  PrepareForAnimation();
+
+  // Mark the tab as closing.
+  Tab* tab = tab_at(model_index);
+  tab->set_closing(true);
+
+  RemoveTabFromViewModel(model_index);
+
+  ScheduleRemoveTabAnimation(tab);
+}
+
+void TabStrip::ScheduleRemoveTabAnimation(Tab* tab) {
+  // Start an animation for the tabs.
+  GenerateIdealBounds();
+  AnimateToIdealBounds();
+
+  // Animate the tab being closed to zero width.
+  gfx::Rect tab_bounds = tab->bounds();
+  tab_bounds.set_width(0);
+  bounds_animator_.AnimateViewTo(tab, tab_bounds);
+  bounds_animator_.SetAnimationDelegate(
+      tab, std::make_unique<RemoveTabDelegate>(this, tab));
+
+  // Don't animate the new tab button when dragging tabs. Otherwise it looks
+  // like the new tab button magically appears from beyond the end of the tab
+  // strip.
+  if (TabDragController::IsAttachedTo(this)) {
+    bounds_animator_.StopAnimatingView(new_tab_button_);
+    new_tab_button_->SetBoundsRect(new_tab_button_bounds_);
+  }
+}
+
+void TabStrip::AnimateToIdealBounds() {
+  for (int i = 0; i < tab_count(); ++i) {
+    Tab* tab = tab_at(i);
+    if (!tab->dragging()) {
+      bounds_animator_.AnimateViewTo(tab, ideal_bounds(i));
+      bounds_animator_.SetAnimationDelegate(
+          tab, std::make_unique<TabAnimationDelegate>(this, tab));
+    }
+  }
+
+  bounds_animator_.AnimateViewTo(new_tab_button_, new_tab_button_bounds_);
+}
+
+bool TabStrip::ShouldHighlightCloseButtonAfterRemove() {
+  return in_tab_close_;
+}
+
+bool TabStrip::TitlebarBackgroundIsTransparent() const {
+#if defined(OS_WIN)
+  // Windows 8+ uses transparent window contents (because the titlebar area is
+  // drawn by the system and not Chrome), but the actual titlebar is opaque.
+  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+    return false;
+#endif
+  return GetWidget()->ShouldWindowContentsBeTransparent();
+}
+
+void TabStrip::DoLayout() {
+  last_layout_size_ = size();
+
+  StopAnimating(false);
+
+  SwapLayoutIfNecessary();
+
+  if (touch_layout_)
+    touch_layout_->SetWidth(GetTabAreaWidth());
+
+  GenerateIdealBounds();
+
+  views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_);
+  SetTabVisibility();
+
+  SchedulePaint();
+
+  bounds_animator_.StopAnimatingView(new_tab_button_);
+  new_tab_button_->SetBoundsRect(new_tab_button_bounds_);
+}
+
+void TabStrip::SetTabVisibility() {
+  // We could probably be more efficient here by making use of the fact that the
+  // tabstrip will always have any visible tabs, and then any invisible tabs, so
+  // we could e.g. binary-search for the changeover point.  But since we have to
+  // iterate through all the tabs to call SetVisible() anyway, it doesn't seem
+  // worth it.
+  for (int i = 0; i < tab_count(); ++i) {
+    Tab* tab = tab_at(i);
+    tab->SetVisible(ShouldTabBeVisible(tab));
+  }
+  for (const auto& closing_tab : tabs_closing_map_) {
+    for (Tab* tab : closing_tab.second)
+      tab->SetVisible(ShouldTabBeVisible(tab));
+  }
+}
+
+void TabStrip::DragActiveTab(const std::vector<int>& initial_positions,
+                             int delta) {
+  DCHECK_EQ(tab_count(), static_cast<int>(initial_positions.size()));
+  if (!touch_layout_) {
+    StackDraggedTabs(delta);
+    return;
+  }
+  SetIdealBoundsFromPositions(initial_positions);
+  touch_layout_->DragActiveTab(delta);
+  DoLayout();
+}
+
+void TabStrip::SetIdealBoundsFromPositions(const std::vector<int>& positions) {
+  if (static_cast<size_t>(tab_count()) != positions.size())
+    return;
+
+  for (int i = 0; i < tab_count(); ++i) {
+    gfx::Rect bounds(ideal_bounds(i));
+    bounds.set_x(positions[i]);
+    tabs_.set_ideal_bounds(i, bounds);
+  }
+}
+
+void TabStrip::StackDraggedTabs(int delta) {
+  DCHECK(!touch_layout_);
+  GenerateIdealBounds();
+  const int active_index = controller_->GetActiveIndex();
+  DCHECK_NE(-1, active_index);
+  if (delta < 0) {
+    // Drag the tabs to the left, stacking tabs before the active tab.
+    const int adjusted_delta =
+        std::min(ideal_bounds(active_index).x() -
+                     kStackedPadding * std::min(active_index, kMaxStackedCount),
+                 -delta);
+    for (int i = 0; i <= active_index; ++i) {
+      const int min_x = std::min(i, kMaxStackedCount) * kStackedPadding;
+      gfx::Rect new_bounds(ideal_bounds(i));
+      new_bounds.set_x(std::max(min_x, new_bounds.x() - adjusted_delta));
+      tabs_.set_ideal_bounds(i, new_bounds);
+    }
+    const bool is_active_pinned = tab_at(active_index)->data().pinned;
+    const int active_width = ideal_bounds(active_index).width();
+    for (int i = active_index + 1; i < tab_count(); ++i) {
+      const int max_x =
+          ideal_bounds(active_index).x() +
+          (kStackedPadding * std::min(i - active_index, kMaxStackedCount));
+      gfx::Rect new_bounds(ideal_bounds(i));
+      int new_x = std::max(new_bounds.x() + delta, max_x);
+      if (new_x == max_x && !tab_at(i)->data().pinned && !is_active_pinned &&
+          new_bounds.width() != active_width)
+        new_x += (active_width - new_bounds.width());
+      new_bounds.set_x(new_x);
+      tabs_.set_ideal_bounds(i, new_bounds);
+    }
+  } else {
+    // Drag the tabs to the right, stacking tabs after the active tab.
+    const int last_tab_width = ideal_bounds(tab_count() - 1).width();
+    const int last_tab_x = GetTabAreaWidth() - last_tab_width;
+    if (active_index == tab_count() - 1 &&
+        ideal_bounds(tab_count() - 1).x() == last_tab_x)
+      return;
+    const int adjusted_delta =
+        std::min(last_tab_x -
+                     kStackedPadding * std::min(tab_count() - active_index - 1,
+                                                kMaxStackedCount) -
+                     ideal_bounds(active_index).x(),
+                 delta);
+    for (int last_index = tab_count() - 1, i = last_index; i >= active_index;
+         --i) {
+      const int max_x =
+          last_tab_x -
+          std::min(tab_count() - i - 1, kMaxStackedCount) * kStackedPadding;
+      gfx::Rect new_bounds(ideal_bounds(i));
+      int new_x = std::min(max_x, new_bounds.x() + adjusted_delta);
+      // Because of rounding not all tabs are the same width. Adjust the
+      // position to accommodate this, otherwise the stacking is off.
+      if (new_x == max_x && !tab_at(i)->data().pinned &&
+          new_bounds.width() != last_tab_width)
+        new_x += (last_tab_width - new_bounds.width());
+      new_bounds.set_x(new_x);
+      tabs_.set_ideal_bounds(i, new_bounds);
+    }
+    for (int i = active_index - 1; i >= 0; --i) {
+      const int min_x =
+          ideal_bounds(active_index).x() -
+          std::min(active_index - i, kMaxStackedCount) * kStackedPadding;
+      gfx::Rect new_bounds(ideal_bounds(i));
+      new_bounds.set_x(std::min(min_x, new_bounds.x() + delta));
+      tabs_.set_ideal_bounds(i, new_bounds);
+    }
+    if (ideal_bounds(tab_count() - 1).right() >= new_tab_button_->x())
+      new_tab_button_->SetVisible(false);
+  }
+  views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_);
+  SchedulePaint();
+}
+
+bool TabStrip::IsStackingDraggedTabs() const {
+  return drag_controller_.get() && drag_controller_->started_drag() &&
+         (drag_controller_->move_behavior() ==
+          TabDragController::MOVE_VISIBLE_TABS);
+}
+
+void TabStrip::LayoutDraggedTabsAt(const Tabs& tabs,
+                                   Tab* active_tab,
+                                   const gfx::Point& location,
+                                   bool initial_drag) {
+  // Immediately hide the new tab button if the last tab is being dragged.
+  const Tab* last_visible_tab = GetLastVisibleTab();
+  if (last_visible_tab && last_visible_tab->dragging())
+    new_tab_button_->SetVisible(false);
+  std::vector<gfx::Rect> bounds;
+  CalculateBoundsForDraggedTabs(tabs, &bounds);
+  DCHECK_EQ(tabs.size(), bounds.size());
+  int active_tab_model_index = GetModelIndexOfTab(active_tab);
+  int active_tab_index = static_cast<int>(
+      std::find(tabs.begin(), tabs.end(), active_tab) - tabs.begin());
+  for (size_t i = 0; i < tabs.size(); ++i) {
+    Tab* tab = tabs[i];
+    gfx::Rect new_bounds = bounds[i];
+    new_bounds.Offset(location.x(), location.y());
+    int consecutive_index =
+        active_tab_model_index - (active_tab_index - static_cast<int>(i));
+    // If this is the initial layout during a drag and the tabs aren't
+    // consecutive animate the view into position. Do the same if the tab is
+    // already animating (which means we previously caused it to animate).
+    if ((initial_drag && GetModelIndexOfTab(tabs[i]) != consecutive_index) ||
+        bounds_animator_.IsAnimating(tabs[i])) {
+      bounds_animator_.SetTargetBounds(tabs[i], new_bounds);
+    } else {
+      tab->SetBoundsRect(new_bounds);
+    }
+  }
+  SetTabVisibility();
+}
+
+void TabStrip::CalculateBoundsForDraggedTabs(const Tabs& tabs,
+                                             std::vector<gfx::Rect>* bounds) {
+  const int overlap = Tab::GetOverlap();
+  int x = 0;
+  for (size_t i = 0; i < tabs.size(); ++i) {
+    Tab* tab = tabs[i];
+    if (i > 0 && tab->data().pinned != tabs[i - 1]->data().pinned)
+      x += kPinnedToNonPinnedOffset;
+    gfx::Rect new_bounds = tab->bounds();
+    new_bounds.set_origin(gfx::Point(x, 0));
+    bounds->push_back(new_bounds);
+    x += tab->width() - overlap;
+  }
+}
+
+int TabStrip::GetSizeNeededForTabs(const Tabs& tabs) {
+  int width = 0;
+  for (size_t i = 0; i < tabs.size(); ++i) {
+    Tab* tab = tabs[i];
+    width += tab->width();
+    if (i > 0 && tab->data().pinned != tabs[i - 1]->data().pinned)
+      width += kPinnedToNonPinnedOffset;
+  }
+  if (!tabs.empty())
+    width -= Tab::GetOverlap() * (tabs.size() - 1);
+  return width;
+}
+
+int TabStrip::GetPinnedTabCount() const {
+  int pinned_count = 0;
+  while (pinned_count < tab_count() && tab_at(pinned_count)->data().pinned)
+    pinned_count++;
+  return pinned_count;
+}
+
+const Tab* TabStrip::GetLastVisibleTab() const {
+  for (int i = tab_count() - 1; i >= 0; --i) {
+    const Tab* tab = tab_at(i);
+    if (tab->visible())
+      return tab;
+  }
+  // While in normal use the tabstrip should always be wide enough to have at
+  // least one visible tab, it can be zero-width in tests, meaning we get here.
+  return NULL;
+}
+
+void TabStrip::RemoveTabFromViewModel(int index) {
+  // We still need to paint the tab until we actually remove it. Put it
+  // in tabs_closing_map_ so we can find it.
+  tabs_closing_map_[index].push_back(tab_at(index));
+  UpdateTabsClosingMap(index + 1, -1);
+  tabs_.Remove(index);
+}
+
+void TabStrip::RemoveAndDeleteTab(Tab* tab) {
+  std::unique_ptr<Tab> deleter(tab);
+  FindClosingTabResult res(FindClosingTab(tab));
+  res.first->second.erase(res.second);
+  if (res.first->second.empty())
+    tabs_closing_map_.erase(res.first);
+}
+
+void TabStrip::UpdateTabsClosingMap(int index, int delta) {
+  if (tabs_closing_map_.empty())
+    return;
+
+  if (delta == -1 &&
+      tabs_closing_map_.find(index - 1) != tabs_closing_map_.end() &&
+      tabs_closing_map_.find(index) != tabs_closing_map_.end()) {
+    const Tabs& tabs(tabs_closing_map_[index]);
+    tabs_closing_map_[index - 1].insert(tabs_closing_map_[index - 1].end(),
+                                        tabs.begin(), tabs.end());
+  }
+  TabsClosingMap updated_map;
+  for (auto& i : tabs_closing_map_) {
+    if (i.first > index)
+      updated_map[i.first + delta] = i.second;
+    else if (i.first < index)
+      updated_map[i.first] = i.second;
+  }
+  if (delta > 0 && tabs_closing_map_.find(index) != tabs_closing_map_.end())
+    updated_map[index + delta] = tabs_closing_map_[index];
+  tabs_closing_map_.swap(updated_map);
+}
+
+void TabStrip::StartedDraggingTabs(const Tabs& tabs) {
+  // Let the controller know that the user started dragging tabs.
+  controller_->OnStartedDraggingTabs();
+
+  // Hide the new tab button immediately if we didn't originate the drag.
+  if (!drag_controller_.get())
+    new_tab_button_->SetVisible(false);
+
+  PrepareForAnimation();
+
+  // Reset dragging state of existing tabs.
+  for (int i = 0; i < tab_count(); ++i)
+    tab_at(i)->set_dragging(false);
+
+  for (size_t i = 0; i < tabs.size(); ++i) {
+    tabs[i]->set_dragging(true);
+    bounds_animator_.StopAnimatingView(tabs[i]);
+  }
+
+  // Move the dragged tabs to their ideal bounds.
+  GenerateIdealBounds();
+
+  // Sets the bounds of the dragged tabs.
+  for (size_t i = 0; i < tabs.size(); ++i) {
+    int tab_data_index = GetModelIndexOfTab(tabs[i]);
+    DCHECK_NE(-1, tab_data_index);
+    tabs[i]->SetBoundsRect(ideal_bounds(tab_data_index));
+  }
+  SetTabVisibility();
+  SchedulePaint();
+}
+
+void TabStrip::DraggedTabsDetached() {
+  // Let the controller know that the user is not dragging this tabstrip's tabs
+  // anymore.
+  controller_->OnStoppedDraggingTabs();
+  new_tab_button_->SetVisible(true);
+}
+
+void TabStrip::StoppedDraggingTabs(const Tabs& tabs,
+                                   const std::vector<int>& initial_positions,
+                                   bool move_only,
+                                   bool completed) {
+  // Let the controller know that the user stopped dragging tabs.
+  controller_->OnStoppedDraggingTabs();
+
+  new_tab_button_->SetVisible(true);
+  if (move_only && touch_layout_) {
+    if (completed)
+      touch_layout_->SizeToFit();
+    else
+      SetIdealBoundsFromPositions(initial_positions);
+  }
+  bool is_first_tab = true;
+  for (size_t i = 0; i < tabs.size(); ++i)
+    StoppedDraggingTab(tabs[i], &is_first_tab);
+}
+
+void TabStrip::StoppedDraggingTab(Tab* tab, bool* is_first_tab) {
+  int tab_data_index = GetModelIndexOfTab(tab);
+  if (tab_data_index == -1) {
+    // The tab was removed before the drag completed. Don't do anything.
+    return;
+  }
+
+  if (*is_first_tab) {
+    *is_first_tab = false;
+    PrepareForAnimation();
+
+    // Animate the view back to its correct position.
+    GenerateIdealBounds();
+    AnimateToIdealBounds();
+  }
+  bounds_animator_.AnimateViewTo(tab, ideal_bounds(tab_data_index));
+  // Install a delegate to reset the dragging state when done. We have to leave
+  // dragging true for the tab otherwise it'll draw beneath the new tab button.
+  bounds_animator_.SetAnimationDelegate(
+      tab, std::make_unique<ResetDraggingStateDelegate>(this, tab));
+}
+
+void TabStrip::OwnDragController(TabDragController* controller) {
+  // Typically, ReleaseDragController() and OwnDragController() calls are paired
+  // via corresponding calls to TabDragController::Detach() and
+  // TabDragController::Attach(). There is one exception to that rule: when a
+  // drag might start, we create a TabDragController that is owned by the
+  // potential source tabstrip in MaybeStartDrag(). If a drag actually starts,
+  // we then call Attach() on the source tabstrip, but since the source tabstrip
+  // already owns the TabDragController, so we don't need to do anything.
+  if (controller != drag_controller_.get())
+    drag_controller_.reset(controller);
+}
+
+void TabStrip::DestroyDragController() {
+  new_tab_button_->SetVisible(true);
+  drag_controller_.reset();
+}
+
+TabDragController* TabStrip::ReleaseDragController() {
+  return drag_controller_.release();
+}
+
+TabStrip::FindClosingTabResult TabStrip::FindClosingTab(const Tab* tab) {
+  DCHECK(tab->closing());
+  for (auto i = tabs_closing_map_.begin(); i != tabs_closing_map_.end(); ++i) {
+    Tabs::iterator j = std::find(i->second.begin(), i->second.end(), tab);
+    if (j != i->second.end())
+      return FindClosingTabResult(i, j);
+  }
+  NOTREACHED();
+  return FindClosingTabResult(tabs_closing_map_.end(), Tabs::iterator());
+}
+
+void TabStrip::PaintClosingTabs(int index, const views::PaintInfo& paint_info) {
+  if (tabs_closing_map_.find(index) == tabs_closing_map_.end())
+    return;
+  for (Tab* tab : base::Reversed(tabs_closing_map_[index]))
+    tab->Paint(paint_info);
+}
+
+void TabStrip::UpdateStackedLayoutFromMouseEvent(views::View* source,
+                                                 const ui::MouseEvent& event) {
+  if (!adjust_layout_)
+    return;
+
+  // The following code attempts to switch to shrink (not stacked) layout when
+  // the mouse exits the tabstrip (or the mouse is pressed on a stacked tab) and
+  // to stacked layout when a touch device is used. This is made problematic by
+  // windows generating mouse move events that do not clearly indicate the move
+  // is the result of a touch device. This assumes a real mouse is used if
+  // |kMouseMoveCountBeforeConsiderReal| mouse move events are received within
+  // the time window |kMouseMoveTimeMS|.  At the time we get a mouse press we
+  // know whether its from a touch device or not, but we don't layout then else
+  // everything shifts. Instead we wait for the release.
+  //
+  // TODO(sky): revisit this when touch events are really plumbed through.
+
+  switch (event.type()) {
+    case ui::ET_MOUSE_PRESSED:
+      mouse_move_count_ = 0;
+      last_mouse_move_time_ = base::TimeTicks();
+      SetResetToShrinkOnExit((event.flags() & ui::EF_FROM_TOUCH) == 0);
+      if (reset_to_shrink_on_exit_ && touch_layout_) {
+        gfx::Point tab_strip_point(event.location());
+        views::View::ConvertPointToTarget(source, this, &tab_strip_point);
+        Tab* tab = FindTabForEvent(tab_strip_point);
+        if (tab && touch_layout_->IsStacked(GetModelIndexOfTab(tab))) {
+          SetStackedLayout(false);
+          controller_->StackedLayoutMaybeChanged();
+        }
+      }
+      break;
+
+    case ui::ET_MOUSE_MOVED: {
+#if defined(OS_CHROMEOS)
+      // Ash does not synthesize mouse events from touch events.
+      SetResetToShrinkOnExit(true);
+#else
+      gfx::Point location(event.location());
+      ConvertPointToTarget(source, this, &location);
+      if (location == last_mouse_move_location_)
+        return;  // Ignore spurious moves.
+      last_mouse_move_location_ = location;
+      if ((event.flags() & ui::EF_FROM_TOUCH) == 0 &&
+          (event.flags() & ui::EF_IS_SYNTHESIZED) == 0) {
+        if ((base::TimeTicks::Now() - last_mouse_move_time_).InMilliseconds() <
+            kMouseMoveTimeMS) {
+          if (mouse_move_count_++ == kMouseMoveCountBeforeConsiderReal)
+            SetResetToShrinkOnExit(true);
+        } else {
+          mouse_move_count_ = 1;
+          last_mouse_move_time_ = base::TimeTicks::Now();
+        }
+      } else {
+        last_mouse_move_time_ = base::TimeTicks();
+      }
+#endif
+      break;
+    }
+
+    case ui::ET_MOUSE_RELEASED: {
+      gfx::Point location(event.location());
+      ConvertPointToTarget(source, this, &location);
+      last_mouse_move_location_ = location;
+      mouse_move_count_ = 0;
+      last_mouse_move_time_ = base::TimeTicks();
+      if ((event.flags() & ui::EF_FROM_TOUCH) == ui::EF_FROM_TOUCH) {
+        SetStackedLayout(true);
+        controller_->StackedLayoutMaybeChanged();
+      }
+      break;
+    }
+
+    default:
+      break;
+  }
+}
+
+void TabStrip::ResizeLayoutTabs() {
+  // We've been called back after the TabStrip has been emptied out (probably
+  // just prior to the window being destroyed). We need to do nothing here or
+  // else GetTabAt below will crash.
+  if (tab_count() == 0)
+    return;
+
+  // It is critically important that this is unhooked here, otherwise we will
+  // keep spying on messages forever.
+  RemoveMessageLoopObserver();
+
+  in_tab_close_ = false;
+  available_width_for_tabs_ = -1;
+  int pinned_tab_count = GetPinnedTabCount();
+  if (pinned_tab_count == tab_count()) {
+    // Only pinned tabs, we know the tab widths won't have changed (all
+    // pinned tabs have the same width), so there is nothing to do.
+    return;
+  }
+  // Don't try and avoid layout based on tab sizes. If tabs are small enough
+  // then the width of the active tab may not change, but other widths may
+  // have. This is particularly important if we've overflowed (all tabs are at
+  // the min).
+  StartResizeLayoutAnimation();
+}
+
+void TabStrip::ResizeLayoutTabsFromTouch() {
+  // Don't resize if the user is interacting with the tabstrip.
+  if (!drag_controller_.get())
+    ResizeLayoutTabs();
+  else
+    StartResizeLayoutTabsFromTouchTimer();
+}
+
+void TabStrip::StartResizeLayoutTabsFromTouchTimer() {
+  resize_layout_timer_.Stop();
+  resize_layout_timer_.Start(
+      FROM_HERE, base::TimeDelta::FromMilliseconds(kTouchResizeLayoutTimeMS),
+      this, &TabStrip::ResizeLayoutTabsFromTouch);
+}
+
+void TabStrip::SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds) {
+  StopAnimating(false);
+  DCHECK_EQ(tab_count(), static_cast<int>(tab_bounds.size()));
+  for (int i = 0; i < tab_count(); ++i)
+    tab_at(i)->SetBoundsRect(tab_bounds[i]);
+  // Reset the layout size as we've effectively layed out a different size.
+  // This ensures a layout happens after the drag is done.
+  last_layout_size_ = gfx::Size();
+}
+
+void TabStrip::AddMessageLoopObserver() {
+  if (!mouse_watcher_.get()) {
+    mouse_watcher_ = std::make_unique<views::MouseWatcher>(
+        std::make_unique<views::MouseWatcherViewHost>(
+            this, gfx::Insets(0, 0, kTabStripAnimationVSlop, 0)),
+        this);
+  }
+  mouse_watcher_->Start();
+}
+
+void TabStrip::RemoveMessageLoopObserver() {
+  mouse_watcher_.reset(NULL);
+}
+
+gfx::Rect TabStrip::GetDropBounds(int drop_index,
+                                  bool drop_before,
+                                  bool* is_beneath) {
+  DCHECK_NE(drop_index, -1);
+
+  const int overlap = Tab::GetOverlap();
+  int center_x;
+  if (drop_index < tab_count()) {
+    Tab* tab = tab_at(drop_index);
+    center_x = tab->x() + ((drop_before ? overlap : tab->width()) / 2);
+  } else {
+    Tab* last_tab = tab_at(drop_index - 1);
+    center_x = last_tab->x() + last_tab->width() - (overlap / 2);
+  }
+
+  // Mirror the center point if necessary.
+  center_x = GetMirroredXInView(center_x);
+
+  // Determine the screen bounds.
+  gfx::Point drop_loc(center_x - drop_indicator_width / 2,
+                      -drop_indicator_height);
+  ConvertPointToScreen(this, &drop_loc);
+  gfx::Rect drop_bounds(drop_loc.x(), drop_loc.y(), drop_indicator_width,
+                        drop_indicator_height);
+
+  // If the rect doesn't fit on the monitor, push the arrow to the bottom.
+  display::Screen* screen = display::Screen::GetScreen();
+  display::Display display = screen->GetDisplayMatching(drop_bounds);
+  *is_beneath = !display.bounds().Contains(drop_bounds);
+  if (*is_beneath)
+    drop_bounds.Offset(0, drop_bounds.height() + height());
+
+  return drop_bounds;
+}
+
+void TabStrip::UpdateDropIndex(const DropTargetEvent& event) {
+  // If the UI layout is right-to-left, we need to mirror the mouse
+  // coordinates since we calculate the drop index based on the
+  // original (and therefore non-mirrored) positions of the tabs.
+  const int x = GetMirroredXInView(event.x());
+  // We don't allow replacing the urls of pinned tabs.
+  for (int i = GetPinnedTabCount(); i < tab_count(); ++i) {
+    Tab* tab = tab_at(i);
+    const int tab_max_x = tab->x() + tab->width();
+    const int hot_width = tab->width() / kTabEdgeRatioInverse;
+    if (x < tab_max_x) {
+      if (x < tab->x() + hot_width)
+        SetDropIndex(i, true);
+      else if (x >= tab_max_x - hot_width)
+        SetDropIndex(i + 1, true);
+      else
+        SetDropIndex(i, false);
+      return;
+    }
+  }
+
+  // The drop isn't over a tab, add it to the end.
+  SetDropIndex(tab_count(), true);
+}
+
+void TabStrip::SetDropIndex(int tab_data_index, bool drop_before) {
+  // Let the controller know of the index update.
+  controller_->OnDropIndexUpdate(tab_data_index, drop_before);
+
+  if (tab_data_index == -1) {
+    if (drop_info_.get())
+      drop_info_.reset(NULL);
+    return;
+  }
+
+  if (drop_info_.get() && drop_info_->drop_index == tab_data_index &&
+      drop_info_->drop_before == drop_before) {
+    return;
+  }
+
+  bool is_beneath;
+  gfx::Rect drop_bounds =
+      GetDropBounds(tab_data_index, drop_before, &is_beneath);
+
+  if (!drop_info_.get()) {
+    drop_info_.reset(
+        new DropInfo(tab_data_index, drop_before, !is_beneath, GetWidget()));
+  } else {
+    drop_info_->drop_index = tab_data_index;
+    drop_info_->drop_before = drop_before;
+    if (is_beneath == drop_info_->point_down) {
+      drop_info_->point_down = !is_beneath;
+      drop_info_->arrow_view->SetImage(
+          GetDropArrowImage(drop_info_->point_down));
+    }
+  }
+
+  // Reposition the window. Need to show it too as the window is initially
+  // hidden.
+  drop_info_->arrow_window->SetBounds(drop_bounds);
+  drop_info_->arrow_window->Show();
+}
+
+int TabStrip::GetDropEffect(const ui::DropTargetEvent& event) {
+  const int source_ops = event.source_operations();
+  if (source_ops & ui::DragDropTypes::DRAG_COPY)
+    return ui::DragDropTypes::DRAG_COPY;
+  if (source_ops & ui::DragDropTypes::DRAG_LINK)
+    return ui::DragDropTypes::DRAG_LINK;
+  return ui::DragDropTypes::DRAG_MOVE;
+}
+
+// static
+gfx::ImageSkia* TabStrip::GetDropArrowImage(bool is_down) {
+  return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+      is_down ? IDR_TAB_DROP_DOWN : IDR_TAB_DROP_UP);
+}
+
+// TabStrip::DropInfo
+// ----------------------------------------------------------
+
+TabStrip::DropInfo::DropInfo(int drop_index,
+                             bool drop_before,
+                             bool point_down,
+                             views::Widget* context)
+    : drop_index(drop_index),
+      drop_before(drop_before),
+      point_down(point_down),
+      file_supported(true) {
+  arrow_view = new views::ImageView;
+  arrow_view->SetImage(GetDropArrowImage(point_down));
+
+  arrow_window = new views::Widget;
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
+  params.keep_on_top = true;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+  params.accept_events = false;
+  params.bounds = gfx::Rect(drop_indicator_width, drop_indicator_height);
+  params.context = context->GetNativeWindow();
+  arrow_window->Init(params);
+  arrow_window->SetContentsView(arrow_view);
+}
+
+TabStrip::DropInfo::~DropInfo() {
+  // Close eventually deletes the window, which deletes arrow_view too.
+  arrow_window->Close();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void TabStrip::PrepareForAnimation() {
+  if (!IsDragSessionActive() && !TabDragController::IsAttachedTo(this)) {
+    for (int i = 0; i < tab_count(); ++i)
+      tab_at(i)->set_dragging(false);
+  }
+}
+
+void TabStrip::GenerateIdealBounds() {
+  if (tab_count() == 0)
+    return;  // Should only happen during creation/destruction, ignore.
+
+  if (!touch_layout_) {
+    const int available_width = (available_width_for_tabs_ < 0)
+                                    ? GetTabAreaWidth()
+                                    : available_width_for_tabs_;
+    const std::vector<gfx::Rect> tabs_bounds =
+        CalculateBounds(GetTabSizeInfo(), GetPinnedTabCount(), tab_count(),
+                        controller_->GetActiveIndex(), available_width,
+                        &current_active_width_, &current_inactive_width_);
+    DCHECK_EQ(static_cast<size_t>(tab_count()), tabs_bounds.size());
+
+    for (size_t i = 0; i < tabs_bounds.size(); ++i)
+      tabs_.set_ideal_bounds(i, tabs_bounds[i]);
+  }
+
+  const int max_new_tab_x = width() - new_tab_button_bounds_.width();
+  // For non-stacked tabs the ideal bounds may go outside the bounds of the
+  // tabstrip. Constrain the x-coordinate of the new tab button so that it is
+  // always visible.
+  const int new_tab_x = std::min(
+      max_new_tab_x, tabs_.ideal_bounds(tabs_.view_size() - 1).right() -
+                         GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP));
+  const int old_max_x = new_tab_button_bounds_.right();
+  new_tab_button_bounds_.set_origin(gfx::Point(new_tab_x, 0));
+  if (new_tab_button_bounds_.right() != old_max_x) {
+    for (TabStripObserver& observer : observers_)
+      observer.TabStripMaxXChanged(this);
+  }
+}
+
+int TabStrip::GenerateIdealBoundsForPinnedTabs(int* first_non_pinned_index) {
+  const int num_pinned_tabs = GetPinnedTabCount();
+
+  if (first_non_pinned_index)
+    *first_non_pinned_index = num_pinned_tabs;
+
+  if (num_pinned_tabs == 0)
+    return 0;
+
+  std::vector<gfx::Rect> tab_bounds(tab_count());
+  CalculateBoundsForPinnedTabs(GetTabSizeInfo(), num_pinned_tabs, tab_count(),
+                               &tab_bounds);
+  for (int i = 0; i < num_pinned_tabs; ++i)
+    tabs_.set_ideal_bounds(i, tab_bounds[i]);
+  return (num_pinned_tabs < tab_count())
+             ? tab_bounds[num_pinned_tabs].x()
+             : tab_bounds[num_pinned_tabs - 1].right() - Tab::GetOverlap();
+}
+
+int TabStrip::GetTabAreaWidth() const {
+  return width() - GetNewTabButtonWidth();
+}
+
+void TabStrip::StartResizeLayoutAnimation() {
+  PrepareForAnimation();
+  GenerateIdealBounds();
+  AnimateToIdealBounds();
+}
+
+void TabStrip::StartPinnedTabAnimation() {
+  in_tab_close_ = false;
+  available_width_for_tabs_ = -1;
+
+  PrepareForAnimation();
+
+  GenerateIdealBounds();
+  AnimateToIdealBounds();
+}
+
+void TabStrip::StartMouseInitiatedRemoveTabAnimation(int model_index) {
+  // The user initiated the close. We want to persist the bounds of all the
+  // existing tabs, so we manually shift ideal_bounds then animate.
+  Tab* tab_closing = tab_at(model_index);
+  int delta = tab_closing->width() - Tab::GetOverlap();
+  // If the tab being closed is a pinned tab next to a non-pinned tab, be sure
+  // to add the extra padding.
+  DCHECK_LT(model_index, tab_count() - 1);
+  if (tab_closing->data().pinned && !tab_at(model_index + 1)->data().pinned)
+    delta += kPinnedToNonPinnedOffset;
+
+  // Set the ideal bounds of everything to be moved over to cover for the
+  // removed tab. This does not recompute the ideal bounds so every tab slides
+  // over without expansion until the user moves the mouse away.
+  for (int i = model_index + 1; i < tab_count(); ++i) {
+    gfx::Rect bounds = ideal_bounds(i);
+    bounds.set_x(bounds.x() - delta);
+    tabs_.set_ideal_bounds(i, bounds);
+  }
+
+  // Don't just subtract |delta| from the New Tab x-coordinate, as we might have
+  // overflow tabs that will be able to animate into the strip, in which case
+  // the new tab button should stay where it is.
+  new_tab_button_bounds_.set_x(
+      std::min(width() - new_tab_button_bounds_.width(),
+               ideal_bounds(tab_count() - 1).right() -
+                   GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP)));
+
+  PrepareForAnimation();
+
+  tab_closing->set_closing(true);
+
+  // We still need to paint the tab until we actually remove it. Put it in
+  // tabs_closing_map_ so we can find it.
+  RemoveTabFromViewModel(model_index);
+
+  AnimateToIdealBounds();
+
+  gfx::Rect tab_bounds = tab_closing->bounds();
+  tab_bounds.set_width(0);
+  bounds_animator_.AnimateViewTo(tab_closing, tab_bounds);
+
+  // Register delegate to do cleanup when done.
+  bounds_animator_.SetAnimationDelegate(
+      tab_closing, std::make_unique<RemoveTabDelegate>(this, tab_closing));
+}
+
+bool TabStrip::IsPointInTab(Tab* tab,
+                            const gfx::Point& point_in_tabstrip_coords) {
+  gfx::Point point_in_tab_coords(point_in_tabstrip_coords);
+  View::ConvertPointToTarget(this, tab, &point_in_tab_coords);
+  return tab->HitTestPoint(point_in_tab_coords);
+}
+
+int TabStrip::GetStartXForNormalTabs() const {
+  int pinned_tab_count = GetPinnedTabCount();
+  if (pinned_tab_count == 0)
+    return 0;
+  return pinned_tab_count * (Tab::GetPinnedWidth() - Tab::GetOverlap()) +
+         kPinnedToNonPinnedOffset;
+}
+
+Tab* TabStrip::FindTabForEvent(const gfx::Point& point) {
+  DCHECK(touch_layout_);
+  int active_tab_index = touch_layout_->active_index();
+  Tab* tab = FindTabForEventFrom(point, active_tab_index, -1);
+  return tab ? tab : FindTabForEventFrom(point, active_tab_index + 1, 1);
+}
+
+Tab* TabStrip::FindTabForEventFrom(const gfx::Point& point,
+                                   int start,
+                                   int delta) {
+  // |start| equals tab_count() when there are only pinned tabs.
+  if (start == tab_count())
+    start += delta;
+  for (int i = start; i >= 0 && i < tab_count(); i += delta) {
+    if (IsPointInTab(tab_at(i), point))
+      return tab_at(i);
+  }
+  return NULL;
+}
+
+Tab* TabStrip::FindTabHitByPoint(const gfx::Point& point) {
+  // The display order doesn't necessarily match the child order, so we iterate
+  // in display order.
+  for (int i = 0; i < tab_count(); ++i) {
+    // If we don't first exclude points outside the current tab, the code below
+    // will return the wrong tab if the next tab is selected, the following tab
+    // is active, and |point| is in the overlap region between the two.
+    Tab* tab = tab_at(i);
+    if (!IsPointInTab(tab, point))
+      continue;
+
+    // Selected tabs render atop unselected ones, and active tabs render atop
+    // everything.  Check whether the next tab renders atop this one and |point|
+    // is in the overlap region.
+    Tab* next_tab = i < (tab_count() - 1) ? tab_at(i + 1) : nullptr;
+    if (next_tab &&
+        (next_tab->IsActive() ||
+         (next_tab->IsSelected() && !tab->IsSelected())) &&
+        IsPointInTab(next_tab, point))
+      return next_tab;
+
+    // This is the topmost tab for this point.
+    return tab;
+  }
+
+  return nullptr;
+}
+
+std::vector<int> TabStrip::GetTabXCoordinates() {
+  std::vector<int> results;
+  for (int i = 0; i < tab_count(); ++i)
+    results.push_back(ideal_bounds(i).x());
+  return results;
+}
+
+void TabStrip::SwapLayoutIfNecessary() {
+  bool needs_touch = NeedsTouchLayout();
+  bool using_touch = touch_layout_ != NULL;
+  if (needs_touch == using_touch)
+    return;
+
+  if (needs_touch) {
+    gfx::Size tab_size(Tab::GetTouchWidth(), GetLayoutConstant(TAB_HEIGHT));
+
+    const int overlap = Tab::GetOverlap();
+    touch_layout_.reset(new StackedTabStripLayout(
+        tab_size, overlap, kStackedPadding, kMaxStackedCount, &tabs_));
+    touch_layout_->SetWidth(GetTabAreaWidth());
+    // This has to be after SetWidth() as SetWidth() is going to reset the
+    // bounds of the pinned tabs (since StackedTabStripLayout doesn't yet know
+    // how many pinned tabs there are).
+    GenerateIdealBoundsForPinnedTabs(NULL);
+    touch_layout_->SetXAndPinnedCount(GetStartXForNormalTabs(),
+                                      GetPinnedTabCount());
+    touch_layout_->SetActiveIndex(controller_->GetActiveIndex());
+
+    base::RecordAction(UserMetricsAction("StackedTab_EnteredStackedLayout"));
+  } else {
+    touch_layout_.reset();
+  }
+  PrepareForAnimation();
+  GenerateIdealBounds();
+  SetTabVisibility();
+  AnimateToIdealBounds();
+}
+
+bool TabStrip::NeedsTouchLayout() const {
+  if (!stacked_layout_)
+    return false;
+
+  int pinned_tab_count = GetPinnedTabCount();
+  int normal_count = tab_count() - pinned_tab_count;
+  if (normal_count <= 1 || normal_count == pinned_tab_count)
+    return false;
+  return (Tab::GetTouchWidth() * normal_count -
+          Tab::GetOverlap() * (normal_count - 1)) >
+         GetTabAreaWidth() - GetStartXForNormalTabs();
+}
+
+void TabStrip::SetResetToShrinkOnExit(bool value) {
+  if (!adjust_layout_)
+    return;
+
+  if (value && !stacked_layout_)
+    value = false;  // We're already using shrink (not stacked) layout.
+
+  if (value == reset_to_shrink_on_exit_)
+    return;
+
+  reset_to_shrink_on_exit_ = value;
+  // Add an observer so we know when the mouse moves out of the tabstrip.
+  if (reset_to_shrink_on_exit_)
+    AddMessageLoopObserver();
+  else
+    RemoveMessageLoopObserver();
+}
+
+void TabStrip::ButtonPressed(views::Button* sender, const ui::Event& event) {
+  if (sender == new_tab_button_) {
+    base::RecordAction(UserMetricsAction("NewTab_Button"));
+    UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_BUTTON,
+                              TabStripModel::NEW_TAB_ENUM_COUNT);
+    if (event.IsMouseEvent()) {
+      const ui::MouseEvent& mouse = static_cast<const ui::MouseEvent&>(event);
+      if (mouse.IsOnlyMiddleMouseButton()) {
+        if (ui::Clipboard::IsSupportedClipboardType(
+                ui::CLIPBOARD_TYPE_SELECTION)) {
+          ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+          CHECK(clipboard);
+          base::string16 clipboard_text;
+          clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &clipboard_text);
+          if (!clipboard_text.empty())
+            controller_->CreateNewTabWithLocation(clipboard_text);
+        }
+        return;
+      }
+    }
+
+    controller_->CreateNewTab();
+    if (event.type() == ui::ET_GESTURE_TAP)
+      TouchUMA::RecordGestureAction(TouchUMA::GESTURE_NEWTAB_TAP);
+  }
+}
+
+// Overridden to support automation. See automation_proxy_uitest.cc.
+const views::View* TabStrip::GetViewByID(int view_id) const {
+  if (tab_count() > 0) {
+    if (view_id == VIEW_ID_TAB_LAST)
+      return tab_at(tab_count() - 1);
+    if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) {
+      int index = view_id - VIEW_ID_TAB_0;
+      return (index >= 0 && index < tab_count()) ? tab_at(index) : NULL;
+    }
+  }
+
+  return View::GetViewByID(view_id);
+}
+
+bool TabStrip::OnMousePressed(const ui::MouseEvent& event) {
+  UpdateStackedLayoutFromMouseEvent(this, event);
+  // We can't return true here, else clicking in an empty area won't drag the
+  // window.
+  return false;
+}
+
+bool TabStrip::OnMouseDragged(const ui::MouseEvent& event) {
+  ContinueDrag(this, event);
+  return true;
+}
+
+void TabStrip::OnMouseReleased(const ui::MouseEvent& event) {
+  EndDrag(END_DRAG_COMPLETE);
+  UpdateStackedLayoutFromMouseEvent(this, event);
+}
+
+void TabStrip::OnMouseCaptureLost() {
+  EndDrag(END_DRAG_CAPTURE_LOST);
+}
+
+void TabStrip::OnMouseMoved(const ui::MouseEvent& event) {
+  UpdateStackedLayoutFromMouseEvent(this, event);
+}
+
+void TabStrip::OnMouseEntered(const ui::MouseEvent& event) {
+  SetResetToShrinkOnExit(true);
+}
+
+void TabStrip::OnGestureEvent(ui::GestureEvent* event) {
+  SetResetToShrinkOnExit(false);
+  switch (event->type()) {
+    case ui::ET_GESTURE_SCROLL_END:
+    case ui::ET_SCROLL_FLING_START:
+    case ui::ET_GESTURE_END:
+      EndDrag(END_DRAG_COMPLETE);
+      if (adjust_layout_) {
+        SetStackedLayout(true);
+        controller_->StackedLayoutMaybeChanged();
+      }
+      break;
+
+    case ui::ET_GESTURE_LONG_PRESS:
+      if (drag_controller_.get())
+        drag_controller_->SetMoveBehavior(TabDragController::REORDER);
+      break;
+
+    case ui::ET_GESTURE_LONG_TAP: {
+      EndDrag(END_DRAG_CANCEL);
+      gfx::Point local_point = event->location();
+      Tab* tab = touch_layout_ ? FindTabForEvent(local_point)
+                               : FindTabHitByPoint(local_point);
+      if (tab) {
+        ConvertPointToScreen(this, &local_point);
+        ShowContextMenuForTab(tab, local_point, ui::MENU_SOURCE_TOUCH);
+      }
+      break;
+    }
+
+    case ui::ET_GESTURE_SCROLL_UPDATE:
+      ContinueDrag(this, *event);
+      break;
+
+    case ui::ET_GESTURE_TAP_DOWN:
+      EndDrag(END_DRAG_CANCEL);
+      break;
+
+    case ui::ET_GESTURE_TAP: {
+      const int active_index = controller_->GetActiveIndex();
+      DCHECK_NE(-1, active_index);
+      Tab* active_tab = tab_at(active_index);
+      TouchUMA::GestureActionType action = TouchUMA::GESTURE_TABNOSWITCH_TAP;
+      if (active_tab->tab_activated_with_last_tap_down())
+        action = TouchUMA::GESTURE_TABSWITCH_TAP;
+      TouchUMA::RecordGestureAction(action);
+      break;
+    }
+
+    default:
+      break;
+  }
+  event->SetHandled();
+}
+
+views::View* TabStrip::TargetForRect(views::View* root, const gfx::Rect& rect) {
+  CHECK_EQ(root, this);
+
+  if (!views::UsePointBasedTargeting(rect))
+    return views::ViewTargeterDelegate::TargetForRect(root, rect);
+  const gfx::Point point(rect.CenterPoint());
+
+  if (!touch_layout_) {
+    // Return any view that isn't a Tab or this TabStrip immediately. We don't
+    // want to interfere.
+    views::View* v = views::ViewTargeterDelegate::TargetForRect(root, rect);
+    if (v && v != this && strcmp(v->GetClassName(), Tab::kViewClassName))
+      return v;
+
+    views::View* tab = FindTabHitByPoint(point);
+    if (tab)
+      return tab;
+  } else {
+    if (new_tab_button_->visible()) {
+      views::View* view =
+          ConvertPointToViewAndGetEventHandler(this, new_tab_button_, point);
+      if (view)
+        return view;
+    }
+    Tab* tab = FindTabForEvent(point);
+    if (tab)
+      return ConvertPointToViewAndGetEventHandler(this, tab, point);
+  }
+  return this;
+}
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index d9ac05f..ba95796 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -5,86 +5,662 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
 
-#include "base/observer_list.h"
-#include "chrome/browser/ui/tabs/tab_utils.h"
-#include "ui/views/view.h"
+#include <memory>
+#include <vector>
 
-class TabStripImpl;
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/ui/tabs/tab_utils.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/browser/ui/views/tabs/tab_controller.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "ui/gfx/animation/animation_container.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/animation/bounds_animator.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/mouse_watcher.h"
+#include "ui/views/view.h"
+#include "ui/views/view_model.h"
+#include "ui/views/view_targeter_delegate.h"
+
+class NewTabButton;
+class StackedTabStripLayout;
+class Tab;
+class TabDragController;
+class TabStripController;
 class TabStripObserver;
 
 namespace gfx {
 class Rect;
 }
 
-// A common base class for functions the BrowserView needs to call on the
-// tab strip. This allows the normal tab strip to be swapped out for an
-// experimental one. See AsTabStripImpl below for more.
-class TabStrip : public views::View {
+namespace ui {
+class ListSelectionModel;
+}
+
+namespace views {
+class ImageView;
+}
+
+// A View that represents the TabStripModel. The TabStrip has the
+// following responsibilities:
+//
+//  - It implements the TabStripModelObserver interface, and acts as a
+//    container for Tabs, and is also responsible for creating them.
+//
+//  - It takes part in Tab Drag & Drop with Tab, TabDragHelper and
+//    DraggedTab, focusing on tasks that require reshuffling other tabs
+//    in response to dragged tabs.
+class TabStrip : public views::View,
+                 public views::ButtonListener,
+                 public views::MouseWatcherListener,
+                 public views::ViewTargeterDelegate,
+                 public TabController {
  public:
-  TabStrip();
+  TabStrip(std::unique_ptr<TabStripController> controller);
   ~TabStrip() override;
 
   // Add and remove observers to changes within this TabStrip.
   void AddObserver(TabStripObserver* observer);
   void RemoveObserver(TabStripObserver* observer);
 
-  // In an ideal world there would be one set of classes that are tied directly
-  // to the tab strip implementation (the drag helper, new tab button, etc.)
-  // and they refer to the TabStripImpl and are constructed from it. These
-  // things can't easily be virtualized because they reach inside to get things
-  // like the TabRendererData or the position of the new tab button.
-  //
-  // Then there would be everything else which depends only on the virtual
-  // TabStrip interface so it can be swapped out with experimental
-  // implementations.
-  //
-  // However, many of the helper classes related to TabStripImpl are
-  // constructed in different places and grab the TabStrip from the
-  // BrowserView. This means they have no way to get to the TabStripImpl which
-  // is where this function comes in.
-  //
-  // This function will return the TabStripImpl for this tab strip if it
-  // exists, or nullptr if this tab strip is an experimental implementation.
-  virtual TabStripImpl* AsTabStripImpl() = 0;
-
   // Max x-coordinate the tabstrip draws at, which is the right edge of the new
   // tab button.
-  virtual int GetMaxX() const = 0;
+  int GetMaxX() const;
 
   // Set the background offset used by inactive tabs to match the frame image.
-  virtual void SetBackgroundOffset(const gfx::Point& offset) = 0;
+  void SetBackgroundOffset(const gfx::Point& offset);
 
   // Returns true if the specified rect (in TabStrip coordinates) intersects
   // the window caption area of the browser window.
-  virtual bool IsRectInWindowCaption(const gfx::Rect& rect) = 0;
+  bool IsRectInWindowCaption(const gfx::Rect& rect);
 
   // Returns true if the specified point (in TabStrip coordinates) is in the
   // window caption area of the browser window.
-  virtual bool IsPositionInWindowCaption(const gfx::Point& point) = 0;
+  bool IsPositionInWindowCaption(const gfx::Point& point);
 
   // Returns false when there is a drag operation in progress so that the frame
   // doesn't close.
-  virtual bool IsTabStripCloseable() const = 0;
+  bool IsTabStripCloseable() const;
 
   // Returns true if the tab strip is editable. Returns false if the tab strip
   // is being dragged or animated to prevent extensions from messing things up
   // while that's happening.
-  virtual bool IsTabStripEditable() const = 0;
+  bool IsTabStripEditable() const;
 
   // Returns information about tabs at given indices.
-  virtual bool IsTabCrashed(int tab_index) const = 0;
-  virtual bool TabHasNetworkError(int tab_index) const = 0;
-  virtual TabAlertState GetTabAlertState(int tab_index) const = 0;
+  bool IsTabCrashed(int tab_index) const;
+  bool TabHasNetworkError(int tab_index) const;
+  TabAlertState GetTabAlertState(int tab_index) const;
 
   // Updates the loading animations displayed by tabs in the tabstrip to the
   // next frame.
-  virtual void UpdateLoadingAnimations() = 0;
+  void UpdateLoadingAnimations();
 
- protected:
-  base::ObserverList<TabStripObserver>& observers() { return observers_; }
+  // If |adjust_layout| is true the stacked layout changes based on whether the
+  // user uses a mouse or a touch device with the tabstrip.
+  void set_adjust_layout(bool adjust_layout) { adjust_layout_ = adjust_layout; }
+
+  // |stacked_layout_| defines what should happen when the tabs won't fit at
+  // their ideal size. When |stacked_layout_| is true the tabs are always sized
+  // to their ideal size and stacked on top of each other so that only a certain
+  // set of tabs are visible. This is used when the user uses a touch device.
+  // When |stacked_layout_| is false the tabs shrink to accommodate the
+  // available space. This is the default.
+  bool stacked_layout() const { return stacked_layout_; }
+
+  // Sets |stacked_layout_| and animates if necessary.
+  void SetStackedLayout(bool stacked_layout);
+
+  // Returns the bounds of the new tab button.
+  gfx::Rect GetNewTabButtonBounds();
+
+  // Returns true if the new tab button should be sized to the top of the tab
+  // strip.
+  bool SizeTabButtonToTopOfTabStrip();
+
+  // Starts highlighting the tab at the specified index.
+  void StartHighlight(int model_index);
+
+  // Stops all tab higlighting.
+  void StopAllHighlighting();
+
+  // Adds a tab at the specified index.
+  void AddTabAt(int model_index, TabRendererData data, bool is_active);
+
+  // Moves a tab.
+  void MoveTab(int from_model_index, int to_model_index, TabRendererData data);
+
+  // Removes a tab at the specified index. If the tab with |contents| is being
+  // dragged then the drag is completed.
+  void RemoveTabAt(content::WebContents* contents, int model_index);
+
+  // Sets the tab data at the specified model index.
+  void SetTabData(int model_index, TabRendererData data);
+
+  // Returns true if the tab is not partly or fully clipped (due to overflow),
+  // and the tab couldn't become partly clipped due to changing the selected tab
+  // (for example, if currently the strip has the last tab selected, and
+  // changing that to the first tab would cause |tab| to be pushed over enough
+  // to clip).
+  bool ShouldTabBeVisible(const Tab* tab) const;
+
+  // Invoked from the controller when the close initiates from the TabController
+  // (the user clicked the tab close button or middle clicked the tab). This is
+  // invoked from Close. Because of unload handlers Close is not always
+  // immediately followed by RemoveTabAt.
+  void PrepareForCloseAt(int model_index, CloseTabSource source);
+
+  // Invoked when the selection changes from |old_selection| to
+  // |new_selection|.
+  void SetSelection(const ui::ListSelectionModel& old_selection,
+                    const ui::ListSelectionModel& new_selection);
+
+  // Invoked when the title of a tab changes and the tab isn't loading. This is
+  // used by pinned tabs to indicate they need attention.
+  void TabTitleChangedNotLoading(int model_index);
+
+  // Invoked when a tab needs to show UI that it needs the user's attention.
+  void SetTabNeedsAttention(int model_index, bool attention);
+
+  // Retrieves the ideal bounds for the Tab at the specified index.
+  const gfx::Rect& ideal_bounds(int tab_data_index) {
+    return tabs_.ideal_bounds(tab_data_index);
+  }
+
+  // Returns the Tab at |index|.
+  Tab* tab_at(int index) const { return tabs_.view_at(index); }
+
+  // Returns the NewTabButton.
+  NewTabButton* new_tab_button() { return new_tab_button_; }
+
+  // Returns the index of the specified tab in the model coordinate system, or
+  // -1 if tab is closing or not valid.
+  int GetModelIndexOfTab(const Tab* tab) const;
+
+  // Gets the number of Tabs in the tab strip.
+  int tab_count() const { return tabs_.view_size(); }
+
+  // Cover method for TabStripController::GetCount.
+  int GetModelCount() const;
+
+  // Cover method for TabStripController::IsValidIndex.
+  bool IsValidModelIndex(int model_index) const;
+
+  TabStripController* controller() const { return controller_.get(); }
+
+  // Returns true if a drag session is currently active.
+  bool IsDragSessionActive() const;
+
+  // Returns true if a tab is being dragged into this tab strip.
+  bool IsActiveDropTarget() const;
+
+  // Returns the alpha that inactive tabs and the new tab button should use to
+  // blend against the frame background.  Inactive tabs and the new tab button
+  // differ in whether they change alpha when tab multiselection is occurring;
+  // |for_new_tab_button| toggles between the two calculations.
+  SkAlpha GetInactiveAlpha(bool for_new_tab_button) const;
+
+  // Returns true if Tabs in this TabStrip are currently changing size or
+  // position.
+  bool IsAnimating() const;
+
+  // Stops any ongoing animations. If |layout| is true and an animation is
+  // ongoing this does a layout.
+  void StopAnimating(bool layout);
+
+  // Called to indicate whether the given URL is a supported file.
+  void FileSupported(const GURL& url, bool supported);
+
+  // TabController overrides:
+  const ui::ListSelectionModel& GetSelectionModel() const override;
+  bool SupportsMultipleSelection() override;
+  bool ShouldHideCloseButtonForInactiveTabs() override;
+  bool MaySetClip() override;
+  void SelectTab(Tab* tab) override;
+  void ExtendSelectionTo(Tab* tab) override;
+  void ToggleSelected(Tab* tab) override;
+  void AddSelectionFromAnchorTo(Tab* tab) override;
+  void CloseTab(Tab* tab, CloseTabSource source) override;
+  void ToggleTabAudioMute(Tab* tab) override;
+  void ShowContextMenuForTab(Tab* tab,
+                             const gfx::Point& p,
+                             ui::MenuSourceType source_type) override;
+  bool IsActiveTab(const Tab* tab) const override;
+  bool IsTabSelected(const Tab* tab) const override;
+  bool IsTabPinned(const Tab* tab) const override;
+  void MaybeStartDrag(
+      Tab* tab,
+      const ui::LocatedEvent& event,
+      const ui::ListSelectionModel& original_selection) override;
+  void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override;
+  bool EndDrag(EndDragReason reason) override;
+  Tab* GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) override;
+  void OnMouseEventInTab(views::View* source,
+                         const ui::MouseEvent& event) override;
+  bool ShouldPaintTab(
+      const Tab* tab,
+      const base::Callback<gfx::Path(const gfx::Size&)>& border_callback,
+      gfx::Path* clip) override;
+  bool CanPaintThrobberToLayer() const override;
+  SkColor GetToolbarTopSeparatorColor() const override;
+  base::string16 GetAccessibleTabName(const Tab* tab) const override;
+  int GetBackgroundResourceId(bool* custom_image) const override;
+
+  // MouseWatcherListener overrides:
+  void MouseMovedOutOfHost() override;
+
+  // views::View overrides:
+  void Layout() override;
+  void PaintChildren(const views::PaintInfo& paint_info) override;
+  const char* GetClassName() const override;
+  gfx::Size CalculatePreferredSize() const override;
+  // NOTE: the drag and drop methods are invoked from FrameView. This is done
+  // to allow for a drop region that extends outside the bounds of the TabStrip.
+  void OnDragEntered(const ui::DropTargetEvent& event) override;
+  int OnDragUpdated(const ui::DropTargetEvent& event) override;
+  void OnDragExited() override;
+  int OnPerformDrop(const ui::DropTargetEvent& event) override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
 
  private:
+  using Tabs = std::vector<Tab*>;
+  using TabsClosingMap = std::map<int, Tabs>;
+  using FindClosingTabResult =
+      std::pair<TabsClosingMap::iterator, Tabs::iterator>;
+
+  class RemoveTabDelegate;
+
+  friend class TabDragController;
+  friend class TabDragControllerTest;
+  friend class TabStripTest;
+  FRIEND_TEST_ALL_PREFIXES(TabDragControllerTest, GestureEndShouldEndDragTest);
+  FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabForEventWhenStacked);
+  FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabCloseButtonVisibilityWhenStacked);
+
+  // Used during a drop session of a url. Tracks the position of the drop as
+  // well as a window used to highlight where the drop occurs.
+  struct DropInfo {
+    DropInfo(int drop_index,
+             bool drop_before,
+             bool point_down,
+             views::Widget* context);
+    ~DropInfo();
+
+    // Index of the tab to drop on. If drop_before is true, the drop should
+    // occur between the tab at drop_index - 1 and drop_index.
+    // WARNING: if drop_before is true it is possible this will == tab_count,
+    // which indicates the drop should create a new tab at the end of the tabs.
+    int drop_index;
+    bool drop_before;
+
+    // Direction the arrow should point in. If true, the arrow is displayed
+    // above the tab and points down. If false, the arrow is displayed beneath
+    // the tab and points up.
+    bool point_down;
+
+    // Renders the drop indicator.
+    views::Widget* arrow_window;
+    views::ImageView* arrow_view;
+
+    // The URL for the drop event.
+    GURL url;
+
+    // Whether the MIME type of the file pointed to by |url| is supported.
+    bool file_supported;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(DropInfo);
+  };
+
+  void Init();
+
+  // Invoked from |AddTabAt| after the newly created tab has been inserted.
+  void StartInsertTabAnimation(int model_index);
+
+  // Invoked from |MoveTab| after |tab_data_| has been updated to animate the
+  // move.
+  void StartMoveTabAnimation();
+
+  // Starts the remove tab animation.
+  void StartRemoveTabAnimation(int model_index);
+
+  // Schedules the animations and bounds changes necessary for a remove tab
+  // animation.
+  void ScheduleRemoveTabAnimation(Tab* tab);
+
+  // Animates all the views to their ideal bounds.
+  // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds
+  // currently set in ideal_bounds.
+  void AnimateToIdealBounds();
+
+  // Returns whether the highlight button should be highlighted after a remove.
+  bool ShouldHighlightCloseButtonAfterRemove();
+
+  // Returns whether the window background behind the tabstrip is transparent.
+  bool TitlebarBackgroundIsTransparent() const;
+
+  // Invoked from Layout if the size changes or layout is really needed.
+  void DoLayout();
+
+  // Sets the visibility state of all tabs based on ShouldTabBeVisible().
+  void SetTabVisibility();
+
+  // Drags the active tab by |delta|. |initial_positions| is the x-coordinates
+  // of the tabs when the drag started.
+  void DragActiveTab(const std::vector<int>& initial_positions, int delta);
+
+  // Sets the ideal bounds x-coordinates to |positions|.
+  void SetIdealBoundsFromPositions(const std::vector<int>& positions);
+
+  // Stacks the dragged tabs. This is used if the drag operation is
+  // MOVE_VISIBLE_TABS and the tabs don't fill the tabstrip. When this happens
+  // the active tab follows the mouse and the other tabs stack around it.
+  void StackDraggedTabs(int delta);
+
+  // Returns true if dragging has resulted in temporarily stacking the tabs.
+  bool IsStackingDraggedTabs() const;
+
+  // Invoked during drag to layout the tabs being dragged in |tabs| at
+  // |location|. If |initial_drag| is true, this is the initial layout after the
+  // user moved the mouse far enough to trigger a drag.
+  void LayoutDraggedTabsAt(const Tabs& tabs,
+                           Tab* active_tab,
+                           const gfx::Point& location,
+                           bool initial_drag);
+
+  // Calculates the bounds needed for each of the tabs, placing the result in
+  // |bounds|.
+  void CalculateBoundsForDraggedTabs(const Tabs& tabs,
+                                     std::vector<gfx::Rect>* bounds);
+
+  // Returns the size needed for the specified tabs. This is invoked during drag
+  // and drop to calculate offsets and positioning.
+  int GetSizeNeededForTabs(const Tabs& tabs);
+
+  // Returns the number of pinned tabs.
+  int GetPinnedTabCount() const;
+
+  // Returns the last tab in the strip that's actually visible.  This will be
+  // the actual last tab unless the strip is in the overflow node_data.
+  const Tab* GetLastVisibleTab() const;
+
+  // Adds the tab at |index| to |tabs_closing_map_| and removes the tab from
+  // |tabs_|.
+  void RemoveTabFromViewModel(int index);
+
+  // Cleans up the Tab from the TabStrip. This is called from the tab animation
+  // code and is not a general-purpose method.
+  void RemoveAndDeleteTab(Tab* tab);
+
+  // Adjusts the indices of all tabs in |tabs_closing_map_| whose index is
+  // >= |index| to have a new index of |index + delta|.
+  void UpdateTabsClosingMap(int index, int delta);
+
+  // Used by TabDragController when the user starts or stops dragging tabs.
+  void StartedDraggingTabs(const Tabs& tabs);
+
+  // Invoked when TabDragController detaches a set of tabs.
+  void DraggedTabsDetached();
+
+  // Used by TabDragController when the user stops dragging tabs. |move_only| is
+  // true if the move behavior is TabDragController::MOVE_VISIBLE_TABS.
+  // |completed| is true if the drag operation completed successfully, false if
+  // it was reverted.
+  void StoppedDraggingTabs(const Tabs& tabs,
+                           const std::vector<int>& initial_positions,
+                           bool move_only,
+                           bool completed);
+
+  // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
+  // |is_first_tab| is set to true.
+  void StoppedDraggingTab(Tab* tab, bool* is_first_tab);
+
+  // Takes ownership of |controller|.
+  void OwnDragController(TabDragController* controller);
+
+  // Destroys the current TabDragController. This cancel the existing drag
+  // operation.
+  void DestroyDragController();
+
+  // Releases ownership of the current TabDragController.
+  TabDragController* ReleaseDragController();
+
+  // Finds |tab| in the |tab_closing_map_| and returns a pair of iterators
+  // indicating precisely where it is.
+  FindClosingTabResult FindClosingTab(const Tab* tab);
+
+  // Paints all the tabs in |tabs_closing_map_[index]|.
+  void PaintClosingTabs(int index, const views::PaintInfo& paint_info);
+
+  // Invoked when a mouse event occurs over |source|. Potentially switches the
+  // |stacked_layout_|.
+  void UpdateStackedLayoutFromMouseEvent(views::View* source,
+                                         const ui::MouseEvent& event);
+
+  // -- Tab Resize Layout -----------------------------------------------------
+
+  // Returns the current width of each tab. If the space for tabs is not evenly
+  // divisible into these widths, the initial tabs in the strip will be 1 px
+  // larger.
+  int current_inactive_width() const { return current_inactive_width_; }
+  int current_active_width() const { return current_active_width_; }
+
+  // Perform an animated resize-relayout of the TabStrip immediately.
+  void ResizeLayoutTabs();
+
+  // Invokes ResizeLayoutTabs() as long as we're not in a drag session. If we
+  // are in a drag session this restarts the timer.
+  void ResizeLayoutTabsFromTouch();
+
+  // Restarts |resize_layout_timer_|.
+  void StartResizeLayoutTabsFromTouchTimer();
+
+  // Sets the bounds of the tabs to |tab_bounds|.
+  void SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds);
+
+  // Ensure that the message loop observer used for event spying is added and
+  // removed appropriately so we can tell when to resize layout the tab strip.
+  void AddMessageLoopObserver();
+  void RemoveMessageLoopObserver();
+
+  // -- Link Drag & Drop ------------------------------------------------------
+
+  // Returns the bounds to render the drop at, in screen coordinates. Sets
+  // |is_beneath| to indicate whether the arrow is beneath the tab, or above
+  // it.
+  gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath);
+
+  // Updates the location of the drop based on the event.
+  void UpdateDropIndex(const ui::DropTargetEvent& event);
+
+  // Sets the location of the drop, repainting as necessary.
+  void SetDropIndex(int tab_data_index, bool drop_before);
+
+  // Returns the drop effect for dropping a URL on the tab strip. This does
+  // not query the data in anyway, it only looks at the source operations.
+  int GetDropEffect(const ui::DropTargetEvent& event);
+
+  // Returns the image to use for indicating a drop on a tab. If is_down is
+  // true, this returns an arrow pointing down.
+  static gfx::ImageSkia* GetDropArrowImage(bool is_down);
+
+  // -- Animations ------------------------------------------------------------
+
+  // Invoked prior to starting a new animation.
+  void PrepareForAnimation();
+
+  // Generates the ideal bounds for each of the tabs as well as the new tab
+  // button.
+  void GenerateIdealBounds();
+
+  // Generates the ideal bounds for the pinned tabs. Returns the index to
+  // position the first non-pinned tab and sets |first_non_pinned_index| to the
+  // index of the first non-pinned tab.
+  int GenerateIdealBoundsForPinnedTabs(int* first_non_pinned_index);
+
+  // Returns the width of the area that contains tabs. This does not include
+  // the width of the new tab button.
+  int GetTabAreaWidth() const;
+
+  // Starts various types of TabStrip animations.
+  void StartResizeLayoutAnimation();
+  void StartPinnedTabAnimation();
+  void StartMouseInitiatedRemoveTabAnimation(int model_index);
+
+  // Returns true if the specified point in TabStrip coords is within the
+  // hit-test region of the specified Tab.
+  bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords);
+
+  // -- Touch Layout ----------------------------------------------------------
+
+  // Returns the position normal tabs start at.
+  int GetStartXForNormalTabs() const;
+
+  // Returns the tab to use for event handling. This uses FindTabForEventFrom()
+  // to do the actual searching.  This method should be called when
+  // |touch_layout_| is set.
+  Tab* FindTabForEvent(const gfx::Point& point);
+
+  // Helper for FindTabForEvent().  Returns the tab to use for event handling
+  // starting at index |start| and iterating by |delta|.
+  Tab* FindTabForEventFrom(const gfx::Point& point, int start, int delta);
+
+  // For a given point, finds a tab that is hit by the point. If the point hits
+  // an area on which two tabs are overlapping, the tab is selected as follows:
+  // - If one of the tabs is active, select it.
+  // - Select the left one.
+  // If no tabs are hit, returns null.  This method should be called when
+  // |touch_layout_| is not set.
+  Tab* FindTabHitByPoint(const gfx::Point& point);
+
+  // Returns the x-coordinates of the tabs.
+  std::vector<int> GetTabXCoordinates();
+
+  // Creates/Destroys |touch_layout_| as necessary.
+  void SwapLayoutIfNecessary();
+
+  // Returns true if |touch_layout_| is needed.
+  bool NeedsTouchLayout() const;
+
+  // Sets the value of |reset_to_shrink_on_exit_|. If true |mouse_watcher_| is
+  // used to track when the mouse truly exits the tabstrip and the stacked
+  // layout is reset.
+  void SetResetToShrinkOnExit(bool value);
+
+  // views::ButtonListener implementation:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+  // View overrides.
+  const views::View* GetViewByID(int id) const override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  bool OnMouseDragged(const ui::MouseEvent& event) override;
+  void OnMouseReleased(const ui::MouseEvent& event) override;
+  void OnMouseCaptureLost() override;
+  void OnMouseMoved(const ui::MouseEvent& event) override;
+  void OnMouseEntered(const ui::MouseEvent& event) override;
+
+  // ui::EventHandler overrides.
+  void OnGestureEvent(ui::GestureEvent* event) override;
+
+  // views::ViewTargeterDelegate:
+  views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
+
+  // -- Member Variables ------------------------------------------------------
+
   base::ObserverList<TabStripObserver> observers_;
+
+  // There is a one-to-one mapping between each of the tabs in the
+  // TabStripController (TabStripModel) and |tabs_|. Because we animate tab
+  // removal there exists a period of time where a tab is displayed but not in
+  // the model. When this occurs the tab is removed from |tabs_| and placed in
+  // |tabs_closing_map_|. When the animation completes the tab is removed from
+  // |tabs_closing_map_|. The painting code ensures both sets of tabs are
+  // painted, and the event handling code ensures only tabs in |tabs_| are used.
+  views::ViewModelT<Tab> tabs_;
+  TabsClosingMap tabs_closing_map_;
+
+  std::unique_ptr<TabStripController> controller_;
+
+  // The "New Tab" button.
+  NewTabButton* new_tab_button_ = nullptr;
+
+  // Ideal bounds of the new tab button.
+  gfx::Rect new_tab_button_bounds_;
+
+  // Returns the current widths of each type of tab.  If the tabstrip width is
+  // not evenly divisible into these widths, the initial tabs in the strip will
+  // be 1 px larger.
+  int current_inactive_width_;
+  int current_active_width_;
+
+  // If this value is nonnegative, it is used as the width to lay out tabs
+  // (instead of tab_area_width()). Most of the time this will be -1, but while
+  // we're handling closing a tab via the mouse, we'll set this to the edge of
+  // the last tab before closing, so that if we are closing the last tab and
+  // need to resize immediately, we'll resize only back to this width, thus
+  // once again placing the last tab under the mouse cursor.
+  int available_width_for_tabs_ = -1;
+
+  // True if PrepareForCloseAt has been invoked. When true remove animations
+  // preserve current tab bounds.
+  bool in_tab_close_ = false;
+
+  // Valid for the lifetime of a drag over us.
+  std::unique_ptr<DropInfo> drop_info_;
+
+  // To ensure all tabs pulse at the same time they share the same animation
+  // container. This is that animation container.
+  scoped_refptr<gfx::AnimationContainer> animation_container_;
+
+  // MouseWatcher is used for two things:
+  // . When a tab is closed to reset the layout.
+  // . When a mouse is used and the layout dynamically adjusts and is currently
+  //   stacked (|stacked_layout_| is true).
+  std::unique_ptr<views::MouseWatcher> mouse_watcher_;
+
+  // The controller for a drag initiated from a Tab. Valid for the lifetime of
+  // the drag session.
+  std::unique_ptr<TabDragController> drag_controller_;
+
+  views::BoundsAnimator bounds_animator_;
+
+  // Size we last layed out at.
+  gfx::Size last_layout_size_;
+
+  // See description above stacked_layout().
+  bool stacked_layout_ = false;
+
+  // Should the layout dynamically adjust?
+  bool adjust_layout_ = false;
+
+  // Only used while in touch mode.
+  std::unique_ptr<StackedTabStripLayout> touch_layout_;
+
+  // If true the |stacked_layout_| is set to false when the mouse exits the
+  // tabstrip (as determined using MouseWatcher).
+  bool reset_to_shrink_on_exit_ = false;
+
+  // Location of the mouse at the time of the last move.
+  gfx::Point last_mouse_move_location_;
+
+  // Time of the last mouse move event.
+  base::TimeTicks last_mouse_move_time_;
+
+  // Number of mouse moves.
+  int mouse_move_count_ = 0;
+
+  // Timer used when a tab is closed and we need to relayout. Only used when a
+  // tab close comes from a touch device.
+  base::OneShotTimer resize_layout_timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabStrip);
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_H_
diff --git a/chrome/browser/ui/views/tabs/tab_strip_controller.h b/chrome/browser/ui/views/tabs/tab_strip_controller.h
index af0af74..284be46 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_controller.h
@@ -13,7 +13,7 @@
 
 class GURL;
 class Tab;
-class TabStripImpl;
+class TabStrip;
 
 namespace gfx {
 class Point;
@@ -88,7 +88,7 @@
 
   // Return true if this tab strip is compatible with the provided tab strip.
   // Compatible tab strips can transfer tabs during drag and drop.
-  virtual bool IsCompatibleWith(TabStripImpl* other) const = 0;
+  virtual bool IsCompatibleWith(TabStrip* other) const = 0;
 
   // Creates the new tab.
   virtual void CreateNewTab() = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_strip_impl.cc b/chrome/browser/ui/views/tabs/tab_strip_impl.cc
deleted file mode 100644
index 320e6184..0000000
--- a/chrome/browser/ui/views/tabs/tab_strip_impl.cc
+++ /dev/null
@@ -1,2512 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <iterator>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/containers/adapters.h"
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "cc/paint/paint_flags.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/ui/layout_constants.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/view_ids.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/tabs/new_tab_button.h"
-#include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h"
-#include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_layout.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
-#include "chrome/browser/ui/views/touch_uma/touch_uma.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
-#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
-#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
-#include "third_party/skia/include/pathops/SkPathOps.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/base/default_theme_provider.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/models/list_selection_model.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/compositor/compositing_recorder.h"
-#include "ui/compositor/paint_recorder.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/gfx/animation/animation_container.h"
-#include "ui/gfx/animation/throb_animation.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/scoped_canvas.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/masked_targeter_delegate.h"
-#include "ui/views/mouse_watcher_view_host.h"
-#include "ui/views/rect_based_targeting_utils.h"
-#include "ui/views/view_model_utils.h"
-#include "ui/views/view_targeter.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/window/non_client_view.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#include "ui/display/win/screen_win.h"
-#include "ui/gfx/win/hwnd_util.h"
-#include "ui/views/win/hwnd_util.h"
-#endif
-
-using base::UserMetricsAction;
-using ui::DropTargetEvent;
-
-namespace {
-
-const int kTabStripAnimationVSlop = 40;
-
-// Inverse ratio of the width of a tab edge to the width of the tab. When
-// hovering over the left or right edge of a tab, the drop indicator will
-// point between tabs.
-const int kTabEdgeRatioInverse = 4;
-
-// Size of the drop indicator.
-int drop_indicator_width;
-int drop_indicator_height;
-
-// Max number of stacked tabs.
-const int kMaxStackedCount = 4;
-
-// Padding between stacked tabs.
-const int kStackedPadding = 6;
-
-// See UpdateLayoutTypeFromMouseEvent() for a description of these.
-#if !defined(OS_CHROMEOS)
-const int kMouseMoveTimeMS = 200;
-const int kMouseMoveCountBeforeConsiderReal = 3;
-#endif
-
-// Amount of time we delay before resizing after a close from a touch.
-const int kTouchResizeLayoutTimeMS = 2000;
-
-#if defined(OS_MACOSX)
-const int kPinnedToNonPinnedOffset = 2;
-#else
-const int kPinnedToNonPinnedOffset = 3;
-#endif
-
-// Returns the width needed for the new tab button (and padding).
-int GetNewTabButtonWidth() {
-  return GetLayoutSize(NEW_TAB_BUTTON).width() -
-         GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP);
-}
-
-// Animation delegate used for any automatic tab movement.  Hides the tab if it
-// is not fully visible within the tabstrip area, to prevent overflow clipping.
-class TabAnimationDelegate : public gfx::AnimationDelegate {
- public:
-  TabAnimationDelegate(TabStripImpl* tab_strip, Tab* tab);
-  ~TabAnimationDelegate() override;
-
-  void AnimationProgressed(const gfx::Animation* animation) override;
-
- protected:
-  TabStripImpl* tab_strip() { return tab_strip_; }
-  Tab* tab() { return tab_; }
-
- private:
-  TabStripImpl* const tab_strip_;
-  Tab* const tab_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabAnimationDelegate);
-};
-
-TabAnimationDelegate::TabAnimationDelegate(TabStripImpl* tab_strip, Tab* tab)
-    : tab_strip_(tab_strip), tab_(tab) {}
-
-TabAnimationDelegate::~TabAnimationDelegate() {}
-
-void TabAnimationDelegate::AnimationProgressed(
-    const gfx::Animation* animation) {
-  tab_->SetVisible(tab_strip_->ShouldTabBeVisible(tab_));
-}
-
-// Animation delegate used when a dragged tab is released. When done sets the
-// dragging state to false.
-class ResetDraggingStateDelegate : public TabAnimationDelegate {
- public:
-  ResetDraggingStateDelegate(TabStripImpl* tab_strip, Tab* tab);
-  ~ResetDraggingStateDelegate() override;
-
-  void AnimationEnded(const gfx::Animation* animation) override;
-  void AnimationCanceled(const gfx::Animation* animation) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate);
-};
-
-ResetDraggingStateDelegate::ResetDraggingStateDelegate(TabStripImpl* tab_strip,
-                                                       Tab* tab)
-    : TabAnimationDelegate(tab_strip, tab) {}
-
-ResetDraggingStateDelegate::~ResetDraggingStateDelegate() {}
-
-void ResetDraggingStateDelegate::AnimationEnded(
-    const gfx::Animation* animation) {
-  tab()->set_dragging(false);
-  AnimationProgressed(animation);  // Forces tab visibility to update.
-}
-
-void ResetDraggingStateDelegate::AnimationCanceled(
-    const gfx::Animation* animation) {
-  AnimationEnded(animation);
-}
-
-// If |dest| contains the point |point_in_source| the event handler from |dest|
-// is returned. Otherwise NULL is returned.
-views::View* ConvertPointToViewAndGetEventHandler(
-    views::View* source,
-    views::View* dest,
-    const gfx::Point& point_in_source) {
-  gfx::Point dest_point(point_in_source);
-  views::View::ConvertPointToTarget(source, dest, &dest_point);
-  return dest->HitTestPoint(dest_point)
-             ? dest->GetEventHandlerForPoint(dest_point)
-             : NULL;
-}
-
-// Gets a tooltip handler for |point_in_source| from |dest|. Note that |dest|
-// should return NULL if it does not contain the point.
-views::View* ConvertPointToViewAndGetTooltipHandler(
-    views::View* source,
-    views::View* dest,
-    const gfx::Point& point_in_source) {
-  gfx::Point dest_point(point_in_source);
-  views::View::ConvertPointToTarget(source, dest, &dest_point);
-  return dest->GetTooltipHandlerForPoint(dest_point);
-}
-
-TabDragController::EventSource EventSourceFromEvent(
-    const ui::LocatedEvent& event) {
-  return event.IsGestureEvent() ? TabDragController::EVENT_SOURCE_TOUCH
-                                : TabDragController::EVENT_SOURCE_MOUSE;
-}
-
-const TabSizeInfo& GetTabSizeInfo() {
-  static TabSizeInfo* tab_size_info = nullptr;
-  if (tab_size_info)
-    return *tab_size_info;
-
-  tab_size_info = new TabSizeInfo;
-  tab_size_info->pinned_tab_width = Tab::GetPinnedWidth();
-  tab_size_info->min_active_width = Tab::GetMinimumActiveSize().width();
-  tab_size_info->min_inactive_width = Tab::GetMinimumInactiveSize().width();
-  tab_size_info->max_size = Tab::GetStandardSize();
-  tab_size_info->tab_overlap = Tab::GetOverlap();
-  tab_size_info->pinned_to_normal_offset = kPinnedToNonPinnedOffset;
-  return *tab_size_info;
-}
-
-}  // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// TabStripImpl::RemoveTabDelegate
-//
-// AnimationDelegate used when removing a tab. Does the necessary cleanup when
-// done.
-class TabStripImpl::RemoveTabDelegate : public TabAnimationDelegate {
- public:
-  RemoveTabDelegate(TabStripImpl* tab_strip, Tab* tab);
-
-  void AnimationEnded(const gfx::Animation* animation) override;
-  void AnimationCanceled(const gfx::Animation* animation) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate);
-};
-
-TabStripImpl::RemoveTabDelegate::RemoveTabDelegate(TabStripImpl* tab_strip,
-                                                   Tab* tab)
-    : TabAnimationDelegate(tab_strip, tab) {}
-
-void TabStripImpl::RemoveTabDelegate::AnimationEnded(
-    const gfx::Animation* animation) {
-  DCHECK(tab()->closing());
-  tab_strip()->RemoveAndDeleteTab(tab());
-
-  // Send the Container a message to simulate a mouse moved event at the current
-  // mouse position. This tickles the Tab the mouse is currently over to show
-  // the "hot" state of the close button.  Note that this is not required (and
-  // indeed may crash!) for removes spawned by non-mouse closes and
-  // drag-detaches.
-  if (!tab_strip()->IsDragSessionActive() &&
-      tab_strip()->ShouldHighlightCloseButtonAfterRemove()) {
-    // The widget can apparently be null during shutdown.
-    views::Widget* widget = tab_strip()->GetWidget();
-    if (widget)
-      widget->SynthesizeMouseMoveEvent();
-  }
-}
-
-void TabStripImpl::RemoveTabDelegate::AnimationCanceled(
-    const gfx::Animation* animation) {
-  AnimationEnded(animation);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// TabStripImpl, public:
-
-TabStripImpl::TabStripImpl(std::unique_ptr<TabStripController> controller)
-    : controller_(std::move(controller)),
-      current_inactive_width_(Tab::GetStandardSize().width()),
-      current_active_width_(Tab::GetStandardSize().width()),
-      animation_container_(new gfx::AnimationContainer()),
-      bounds_animator_(this) {
-  Init();
-  SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
-}
-
-TabStripImpl::~TabStripImpl() {
-  for (TabStripObserver& observer : observers())
-    observer.TabStripDeleted(this);
-
-  // The animations may reference the tabs. Shut down the animation before we
-  // delete the tabs.
-  StopAnimating(false);
-
-  DestroyDragController();
-
-  // Make sure we unhook ourselves as a message loop observer so that we don't
-  // crash in the case where the user closes the window after closing a tab
-  // but before moving the mouse.
-  RemoveMessageLoopObserver();
-
-  // The children (tabs) may callback to us from their destructor. Delete them
-  // so that if they call back we aren't in a weird state.
-  RemoveAllChildViews(true);
-}
-
-TabStripImpl* TabStripImpl::AsTabStripImpl() {
-  return this;
-}
-
-int TabStripImpl::GetMaxX() const {
-  return new_tab_button_bounds_.right();
-}
-
-void TabStripImpl::SetBackgroundOffset(const gfx::Point& offset) {
-  for (int i = 0; i < tab_count(); ++i)
-    tab_at(i)->set_background_offset(offset);
-  new_tab_button_->set_background_offset(offset);
-}
-
-bool TabStripImpl::IsRectInWindowCaption(const gfx::Rect& rect) {
-  views::View* v = GetEventHandlerForRect(rect);
-
-  // If there is no control at this location, claim the hit was in the title
-  // bar to get a move action.
-  if (v == this)
-    return true;
-
-  // Check to see if the rect intersects the non-button parts of the new tab
-  // button. The button has a non-rectangular shape, so if it's not in the
-  // visual portions of the button we treat it as a click to the caption.
-  gfx::RectF rect_in_new_tab_coords_f(rect);
-  View::ConvertRectToTarget(this, new_tab_button_, &rect_in_new_tab_coords_f);
-  gfx::Rect rect_in_new_tab_coords =
-      gfx::ToEnclosingRect(rect_in_new_tab_coords_f);
-  if (new_tab_button_->GetLocalBounds().Intersects(rect_in_new_tab_coords) &&
-      !new_tab_button_->HitTestRect(rect_in_new_tab_coords))
-    return true;
-
-  // All other regions, including the new Tab button, should be considered part
-  // of the containing Window's client area so that regular events can be
-  // processed for them.
-  return false;
-}
-
-bool TabStripImpl::IsPositionInWindowCaption(const gfx::Point& point) {
-  return IsRectInWindowCaption(gfx::Rect(point, gfx::Size(1, 1)));
-}
-
-bool TabStripImpl::IsTabStripCloseable() const {
-  return !IsDragSessionActive();
-}
-
-bool TabStripImpl::IsTabStripEditable() const {
-  return !IsDragSessionActive() && !IsActiveDropTarget();
-}
-
-bool TabStripImpl::IsTabCrashed(int tab_index) const {
-  return tab_at(tab_index)->data().IsCrashed();
-}
-
-bool TabStripImpl::TabHasNetworkError(int tab_index) const {
-  return tab_at(tab_index)->data().network_state == TabNetworkState::kError;
-}
-
-TabAlertState TabStripImpl::GetTabAlertState(int tab_index) const {
-  return tab_at(tab_index)->data().alert_state;
-}
-
-void TabStripImpl::UpdateLoadingAnimations() {
-  for (int i = 0; i < tab_count(); i++)
-    tab_at(i)->StepLoadingAnimation();
-}
-
-void TabStripImpl::SetStackedLayout(bool stacked_layout) {
-  if (stacked_layout == stacked_layout_)
-    return;
-
-  const int active_index = controller_->GetActiveIndex();
-  int active_center = 0;
-  if (active_index != -1) {
-    active_center =
-        ideal_bounds(active_index).x() + ideal_bounds(active_index).width() / 2;
-  }
-  stacked_layout_ = stacked_layout;
-  SetResetToShrinkOnExit(false);
-  SwapLayoutIfNecessary();
-  // When transitioning to stacked try to keep the active tab centered.
-  if (touch_layout_ && active_index != -1) {
-    touch_layout_->SetActiveTabLocation(active_center -
-                                        ideal_bounds(active_index).width() / 2);
-    AnimateToIdealBounds();
-  }
-
-  for (int i = 0; i < tab_count(); ++i)
-    tab_at(i)->HideCloseButtonForInactiveTabsChanged();
-}
-
-gfx::Rect TabStripImpl::GetNewTabButtonBounds() {
-  return new_tab_button_->bounds();
-}
-
-bool TabStripImpl::SizeTabButtonToTopOfTabStrip() {
-  // Extend the button to the screen edge in maximized and immersive fullscreen.
-  views::Widget* widget = GetWidget();
-  return browser_defaults::kSizeTabButtonToTopOfTabStrip ||
-         (widget && (widget->IsMaximized() || widget->IsFullscreen()));
-}
-
-void TabStripImpl::StartHighlight(int model_index) {
-  tab_at(model_index)->StartPulse();
-}
-
-void TabStripImpl::StopAllHighlighting() {
-  for (int i = 0; i < tab_count(); ++i)
-    tab_at(i)->StopPulse();
-}
-
-void TabStripImpl::AddTabAt(int model_index,
-                            TabRendererData data,
-                            bool is_active) {
-  Tab* tab = new Tab(this, animation_container_.get());
-  AddChildView(tab);
-  const bool pinned = data.pinned;
-  tab->SetData(std::move(data));
-  UpdateTabsClosingMap(model_index, 1);
-  tabs_.Add(tab, model_index);
-
-  if (touch_layout_) {
-    GenerateIdealBoundsForPinnedTabs(NULL);
-    int add_types = 0;
-    if (pinned)
-      add_types |= StackedTabStripLayout::kAddTypePinned;
-    if (is_active)
-      add_types |= StackedTabStripLayout::kAddTypeActive;
-    touch_layout_->AddTab(model_index, add_types, GetStartXForNormalTabs());
-  }
-
-  // Don't animate the first tab, it looks weird, and don't animate anything
-  // if the containing window isn't visible yet.
-  if (tab_count() > 1 && GetWidget() && GetWidget()->IsVisible())
-    StartInsertTabAnimation(model_index);
-  else
-    DoLayout();
-
-  SwapLayoutIfNecessary();
-
-  for (TabStripObserver& observer : observers())
-    observer.TabStripAddedTabAt(this, model_index);
-
-  // Stop dragging when a new tab is added and dragging a window. Doing
-  // otherwise results in a confusing state if the user attempts to reattach. We
-  // could allow this and make TabDragController update itself during the add,
-  // but this comes up infrequently enough that it's not worth the complexity.
-  //
-  // At the start of AddTabAt() the model and tabs are out sync. Any queries to
-  // find a tab given a model index can go off the end of |tabs_|. As such, it
-  // is important that we complete the drag *after* adding the tab so that the
-  // model and tabstrip are in sync.
-  if (drag_controller_.get() && !drag_controller_->is_mutating() &&
-      drag_controller_->is_dragging_window()) {
-    EndDrag(END_DRAG_COMPLETE);
-  }
-}
-
-void TabStripImpl::MoveTab(int from_model_index,
-                           int to_model_index,
-                           TabRendererData data) {
-  DCHECK_GT(tabs_.view_size(), 0);
-  const Tab* last_tab = GetLastVisibleTab();
-  tab_at(from_model_index)->SetData(std::move(data));
-  if (touch_layout_) {
-    tabs_.MoveViewOnly(from_model_index, to_model_index);
-    int pinned_count = 0;
-    GenerateIdealBoundsForPinnedTabs(&pinned_count);
-    touch_layout_->MoveTab(from_model_index, to_model_index,
-                           controller_->GetActiveIndex(),
-                           GetStartXForNormalTabs(), pinned_count);
-  } else {
-    tabs_.Move(from_model_index, to_model_index);
-  }
-  StartMoveTabAnimation();
-  if (TabDragController::IsAttachedTo(this) &&
-      (last_tab != GetLastVisibleTab() || last_tab->dragging())) {
-    new_tab_button_->SetVisible(false);
-  }
-  SwapLayoutIfNecessary();
-
-  for (TabStripObserver& observer : observers())
-    observer.TabStripMovedTab(this, from_model_index, to_model_index);
-}
-
-void TabStripImpl::RemoveTabAt(content::WebContents* contents,
-                               int model_index) {
-  if (touch_layout_) {
-    Tab* tab = tab_at(model_index);
-    tab->set_closing(true);
-    int old_x = tabs_.ideal_bounds(model_index).x();
-    // We still need to paint the tab until we actually remove it. Put it in
-    // tabs_closing_map_ so we can find it.
-    RemoveTabFromViewModel(model_index);
-    touch_layout_->RemoveTab(model_index,
-                             GenerateIdealBoundsForPinnedTabs(NULL), old_x);
-    ScheduleRemoveTabAnimation(tab);
-  } else if (in_tab_close_ && model_index != GetModelCount()) {
-    StartMouseInitiatedRemoveTabAnimation(model_index);
-  } else {
-    StartRemoveTabAnimation(model_index);
-  }
-  SwapLayoutIfNecessary();
-
-  for (TabStripObserver& observer : observers())
-    observer.TabStripRemovedTabAt(this, model_index);
-
-  // Stop dragging when a new tab is removed and dragging a window. Doing
-  // otherwise results in a confusing state if the user attempts to reattach. We
-  // could allow this and make TabDragController update itself during the
-  // remove operation, but this comes up infrequently enough that it's not worth
-  // the complexity.
-  //
-  // At the start of RemoveTabAt() the model and tabs are out sync. Any queries
-  // to find a tab given a model index can go off the end of |tabs_|. As such,
-  // it is important that we complete the drag *after* removing the tab so that
-  // the model and tabstrip are in sync.
-  if (contents && drag_controller_.get() && !drag_controller_->is_mutating() &&
-      drag_controller_->IsDraggingTab(contents)) {
-    EndDrag(END_DRAG_COMPLETE);
-  }
-}
-
-void TabStripImpl::SetTabData(int model_index, TabRendererData data) {
-  Tab* tab = tab_at(model_index);
-  bool pinned_state_changed = tab->data().pinned != data.pinned;
-  tab->SetData(std::move(data));
-
-  if (pinned_state_changed) {
-    if (touch_layout_) {
-      int pinned_tab_count = 0;
-      int start_x = GenerateIdealBoundsForPinnedTabs(&pinned_tab_count);
-      touch_layout_->SetXAndPinnedCount(start_x, pinned_tab_count);
-    }
-    if (GetWidget() && GetWidget()->IsVisible())
-      StartPinnedTabAnimation();
-    else
-      DoLayout();
-  }
-  SwapLayoutIfNecessary();
-}
-
-bool TabStripImpl::ShouldTabBeVisible(const Tab* tab) const {
-  // Detached tabs should always be invisible (as they close).
-  if (tab->detached())
-    return false;
-
-  // When stacking tabs, all tabs should always be visible.
-  if (stacked_layout_)
-    return true;
-
-  // If the tab is currently clipped, it shouldn't be visible.  Note that we
-  // allow dragged tabs to draw over the "New Tab button" region as well,
-  // because either the New Tab button will be hidden, or the dragged tabs will
-  // be animating back to their normal positions and we don't want to hide them
-  // in the New Tab button region in case they re-appear after leaving it.
-  // (This prevents flickeriness.)  We never draw non-dragged tabs in New Tab
-  // button area, even when the button is invisible, so that they don't appear
-  // to "pop in" when the button disappears.
-  // TODO: Probably doesn't work for RTL
-  int right_edge = tab->bounds().right();
-  const int visible_width = tab->dragging() ? width() : GetTabAreaWidth();
-  if (right_edge > visible_width)
-    return false;
-
-  // Non-clipped dragging tabs should always be visible.
-  if (tab->dragging())
-    return true;
-
-  // Let all non-clipped closing tabs be visible.  These will probably finish
-  // closing before the user changes the active tab, so there's little reason to
-  // try and make the more complex logic below apply.
-  if (tab->closing())
-    return true;
-
-  // Now we need to check whether the tab isn't currently clipped, but could
-  // become clipped if we changed the active tab, widening either this tab or
-  // the tabstrip portion before it.
-
-  // Pinned tabs don't change size when activated, so any tab in the pinned tab
-  // region is safe.
-  if (tab->data().pinned)
-    return true;
-
-  // If the active tab is on or before this tab, we're safe.
-  if (controller_->GetActiveIndex() <= GetModelIndexOfTab(tab))
-    return true;
-
-  // We need to check what would happen if the active tab were to move to this
-  // tab or before.
-  return (right_edge + current_active_width_ - current_inactive_width_) <=
-         GetTabAreaWidth();
-}
-
-void TabStripImpl::PrepareForCloseAt(int model_index, CloseTabSource source) {
-  if (!in_tab_close_ && IsAnimating()) {
-    // Cancel any current animations. We do this as remove uses the current
-    // ideal bounds and we need to know ideal bounds is in a good state.
-    StopAnimating(true);
-  }
-
-  if (!GetWidget())
-    return;
-
-  int model_count = GetModelCount();
-  if (model_count > 1 && model_index != model_count - 1) {
-    // The user is about to close a tab other than the last tab. Set
-    // available_width_for_tabs_ so that if we do a layout we don't position a
-    // tab past the end of the second to last tab. We do this so that as the
-    // user closes tabs with the mouse a tab continues to fall under the mouse.
-    Tab* last_tab = tab_at(model_count - 1);
-    Tab* tab_being_removed = tab_at(model_index);
-    available_width_for_tabs_ = last_tab->bounds().right() -
-                                tab_being_removed->width() + Tab::GetOverlap();
-    if (model_index == 0 && tab_being_removed->data().pinned &&
-        !tab_at(1)->data().pinned) {
-      available_width_for_tabs_ -= kPinnedToNonPinnedOffset;
-    }
-  }
-
-  in_tab_close_ = true;
-  resize_layout_timer_.Stop();
-  if (source == CLOSE_TAB_FROM_TOUCH) {
-    StartResizeLayoutTabsFromTouchTimer();
-  } else {
-    AddMessageLoopObserver();
-  }
-}
-
-void TabStripImpl::SetSelection(const ui::ListSelectionModel& old_selection,
-                                const ui::ListSelectionModel& new_selection) {
-  if (old_selection.active() != new_selection.active()) {
-    if (old_selection.active() >= 0)
-      tab_at(old_selection.active())->ActiveStateChanged();
-    if (new_selection.active() >= 0)
-      tab_at(new_selection.active())->ActiveStateChanged();
-  }
-
-  if (touch_layout_) {
-    touch_layout_->SetActiveIndex(new_selection.active());
-    // Only start an animation if we need to. Otherwise clicking on an
-    // unselected tab and dragging won't work because dragging is only allowed
-    // if not animating.
-    if (!views::ViewModelUtils::IsAtIdealBounds(tabs_))
-      AnimateToIdealBounds();
-    SchedulePaint();
-  } else {
-    // We have "tiny tabs" if the tabs are so tiny that the unselected ones are
-    // a different size to the selected ones.
-    bool tiny_tabs = current_inactive_width_ != current_active_width_;
-    if (!IsAnimating() && (!in_tab_close_ || tiny_tabs)) {
-      DoLayout();
-    } else {
-      SchedulePaint();
-    }
-  }
-
-  // Use STLSetDifference to get the indices of elements newly selected
-  // and no longer selected, since selected_indices() is always sorted.
-  ui::ListSelectionModel::SelectedIndices no_longer_selected =
-      base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>(
-          old_selection.selected_indices(), new_selection.selected_indices());
-  ui::ListSelectionModel::SelectedIndices newly_selected =
-      base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>(
-          new_selection.selected_indices(), old_selection.selected_indices());
-
-  // Fire accessibility events that reflect the changes to selection.
-  for (size_t i = 0; i < no_longer_selected.size(); ++i) {
-    tab_at(no_longer_selected[i])
-        ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_REMOVE, true);
-  }
-  for (size_t i = 0; i < newly_selected.size(); ++i) {
-    tab_at(newly_selected[i])
-        ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_ADD, true);
-  }
-  tab_at(new_selection.active())
-      ->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
-}
-
-void TabStripImpl::TabTitleChangedNotLoading(int model_index) {
-  tab_at(model_index)->TabTitleChangedNotLoading();
-}
-
-void TabStripImpl::SetTabNeedsAttention(int model_index, bool attention) {
-  tab_at(model_index)->SetTabNeedsAttention(attention);
-}
-
-int TabStripImpl::GetModelIndexOfTab(const Tab* tab) const {
-  return tabs_.GetIndexOfView(tab);
-}
-
-int TabStripImpl::GetModelCount() const {
-  return controller_->GetCount();
-}
-
-bool TabStripImpl::IsValidModelIndex(int model_index) const {
-  return controller_->IsValidIndex(model_index);
-}
-
-bool TabStripImpl::IsDragSessionActive() const {
-  return drag_controller_.get() != NULL;
-}
-
-bool TabStripImpl::IsActiveDropTarget() const {
-  for (int i = 0; i < tab_count(); ++i) {
-    Tab* tab = tab_at(i);
-    if (tab->dragging())
-      return true;
-  }
-  return false;
-}
-
-SkAlpha TabStripImpl::GetInactiveAlpha(bool for_new_tab_button) const {
-#if defined(OS_CHROMEOS)
-  static const SkAlpha kInactiveTabAlphaAsh = 230;
-  const SkAlpha base_alpha = kInactiveTabAlphaAsh;
-#else
-  static const SkAlpha kInactiveTabAlphaGlass = 200;
-  static const SkAlpha kInactiveTabAlphaOpaque = 255;
-  const SkAlpha base_alpha = TitlebarBackgroundIsTransparent()
-                                 ? kInactiveTabAlphaGlass
-                                 : kInactiveTabAlphaOpaque;
-#endif  // OS_CHROMEOS
-  static const double kMultiSelectionMultiplier = 0.6;
-  return (for_new_tab_button || (GetSelectionModel().size() <= 1))
-             ? base_alpha
-             : static_cast<SkAlpha>(kMultiSelectionMultiplier * base_alpha);
-}
-
-bool TabStripImpl::IsAnimating() const {
-  return bounds_animator_.IsAnimating();
-}
-
-void TabStripImpl::StopAnimating(bool layout) {
-  if (!IsAnimating())
-    return;
-
-  bounds_animator_.Cancel();
-
-  if (layout)
-    DoLayout();
-}
-
-void TabStripImpl::FileSupported(const GURL& url, bool supported) {
-  if (drop_info_.get() && drop_info_->url == url)
-    drop_info_->file_supported = supported;
-}
-
-const ui::ListSelectionModel& TabStripImpl::GetSelectionModel() const {
-  return controller_->GetSelectionModel();
-}
-
-bool TabStripImpl::SupportsMultipleSelection() {
-  // TODO: currently only allow single selection in touch layout mode.
-  return touch_layout_ == nullptr;
-}
-
-bool TabStripImpl::ShouldHideCloseButtonForInactiveTabs() {
-  return touch_layout_ != nullptr;
-}
-
-bool TabStripImpl::MaySetClip() {
-  // Only touch layout needs to restrict the clip.
-  return touch_layout_ || IsStackingDraggedTabs();
-}
-
-void TabStripImpl::SelectTab(Tab* tab) {
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->SelectTab(model_index);
-}
-
-void TabStripImpl::ExtendSelectionTo(Tab* tab) {
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->ExtendSelectionTo(model_index);
-}
-
-void TabStripImpl::ToggleSelected(Tab* tab) {
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->ToggleSelected(model_index);
-}
-
-void TabStripImpl::AddSelectionFromAnchorTo(Tab* tab) {
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->AddSelectionFromAnchorTo(model_index);
-}
-
-void TabStripImpl::CloseTab(Tab* tab, CloseTabSource source) {
-  if (tab->closing()) {
-    // If the tab is already closing, close the next tab. We do this so that the
-    // user can rapidly close tabs by clicking the close button and not have
-    // the animations interfere with that.
-    const int closed_tab_index = FindClosingTab(tab).first->first;
-    if (closed_tab_index < GetModelCount())
-      controller_->CloseTab(closed_tab_index, source);
-    return;
-  }
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->CloseTab(model_index, source);
-}
-
-void TabStripImpl::ToggleTabAudioMute(Tab* tab) {
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->ToggleTabAudioMute(model_index);
-}
-
-void TabStripImpl::ShowContextMenuForTab(Tab* tab,
-                                         const gfx::Point& p,
-                                         ui::MenuSourceType source_type) {
-  controller_->ShowContextMenuForTab(tab, p, source_type);
-}
-
-bool TabStripImpl::IsActiveTab(const Tab* tab) const {
-  int model_index = GetModelIndexOfTab(tab);
-  return IsValidModelIndex(model_index) &&
-         controller_->IsActiveTab(model_index);
-}
-
-bool TabStripImpl::IsTabSelected(const Tab* tab) const {
-  int model_index = GetModelIndexOfTab(tab);
-  return IsValidModelIndex(model_index) &&
-         controller_->IsTabSelected(model_index);
-}
-
-bool TabStripImpl::IsTabPinned(const Tab* tab) const {
-  if (tab->closing())
-    return false;
-
-  int model_index = GetModelIndexOfTab(tab);
-  return IsValidModelIndex(model_index) &&
-         controller_->IsTabPinned(model_index);
-}
-
-void TabStripImpl::MaybeStartDrag(
-    Tab* tab,
-    const ui::LocatedEvent& event,
-    const ui::ListSelectionModel& original_selection) {
-  // Don't accidentally start any drag operations during animations if the
-  // mouse is down... during an animation tabs are being resized automatically,
-  // so the View system can misinterpret this easily if the mouse is down that
-  // the user is dragging.
-  if (IsAnimating() || tab->closing() ||
-      controller_->HasAvailableDragActions() == 0) {
-    return;
-  }
-
-  int model_index = GetModelIndexOfTab(tab);
-  if (!IsValidModelIndex(model_index)) {
-    CHECK(false);
-    return;
-  }
-  Tabs tabs;
-  int size_to_selected = 0;
-  int x = tab->GetMirroredXInView(event.x());
-  int y = event.y();
-  // Build the set of selected tabs to drag and calculate the offset from the
-  // first selected tab.
-  for (int i = 0; i < tab_count(); ++i) {
-    Tab* other_tab = tab_at(i);
-    if (IsTabSelected(other_tab)) {
-      tabs.push_back(other_tab);
-      if (other_tab == tab) {
-        size_to_selected = GetSizeNeededForTabs(tabs);
-        x = size_to_selected - tab->width() + x;
-      }
-    }
-  }
-  DCHECK(!tabs.empty());
-  DCHECK(base::ContainsValue(tabs, tab));
-  ui::ListSelectionModel selection_model;
-  if (!original_selection.IsSelected(model_index))
-    selection_model = original_selection;
-  // Delete the existing DragController before creating a new one. We do this as
-  // creating the DragController remembers the WebContents delegates and we need
-  // to make sure the existing DragController isn't still a delegate.
-  drag_controller_.reset();
-  TabDragController::MoveBehavior move_behavior = TabDragController::REORDER;
-  // Use MOVE_VISIBLE_TABS in the following conditions:
-  // . Mouse event generated from touch and the left button is down (the right
-  //   button corresponds to a long press, which we want to reorder).
-  // . Gesture tap down and control key isn't down.
-  // . Real mouse event and control is down. This is mostly for testing.
-  DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
-         event.type() == ui::ET_GESTURE_TAP_DOWN);
-  if (touch_layout_ &&
-      ((event.type() == ui::ET_MOUSE_PRESSED &&
-        (((event.flags() & ui::EF_FROM_TOUCH) &&
-          static_cast<const ui::MouseEvent&>(event).IsLeftMouseButton()) ||
-         (!(event.flags() & ui::EF_FROM_TOUCH) &&
-          static_cast<const ui::MouseEvent&>(event).IsControlDown()))) ||
-       (event.type() == ui::ET_GESTURE_TAP_DOWN && !event.IsControlDown()))) {
-    move_behavior = TabDragController::MOVE_VISIBLE_TABS;
-  }
-
-  drag_controller_.reset(new TabDragController);
-  drag_controller_->Init(this, tab, tabs, gfx::Point(x, y), event.x(),
-                         std::move(selection_model), move_behavior,
-                         EventSourceFromEvent(event));
-}
-
-void TabStripImpl::ContinueDrag(views::View* view,
-                                const ui::LocatedEvent& event) {
-  if (drag_controller_.get() &&
-      drag_controller_->event_source() == EventSourceFromEvent(event)) {
-    gfx::Point screen_location(event.location());
-    views::View::ConvertPointToScreen(view, &screen_location);
-    drag_controller_->Drag(screen_location);
-  }
-}
-
-bool TabStripImpl::EndDrag(EndDragReason reason) {
-  if (!drag_controller_.get())
-    return false;
-  bool started_drag = drag_controller_->started_drag();
-  drag_controller_->EndDrag(reason);
-  return started_drag;
-}
-
-Tab* TabStripImpl::GetTabAt(Tab* tab,
-                            const gfx::Point& tab_in_tab_coordinates) {
-  gfx::Point local_point = tab_in_tab_coordinates;
-  ConvertPointToTarget(tab, this, &local_point);
-
-  views::View* view = GetEventHandlerForPoint(local_point);
-  if (!view)
-    return NULL;  // No tab contains the point.
-
-  // Walk up the view hierarchy until we find a tab, or the TabStrip.
-  while (view && view != this && view->id() != VIEW_ID_TAB)
-    view = view->parent();
-
-  return view && view->id() == VIEW_ID_TAB ? static_cast<Tab*>(view) : NULL;
-}
-
-void TabStripImpl::OnMouseEventInTab(views::View* source,
-                                     const ui::MouseEvent& event) {
-  UpdateStackedLayoutFromMouseEvent(source, event);
-}
-
-bool TabStripImpl::ShouldPaintTab(
-    const Tab* tab,
-    const base::Callback<gfx::Path(const gfx::Size&)>& border_callback,
-    gfx::Path* clip) {
-  if (!MaySetClip())
-    return true;
-
-  int index = GetModelIndexOfTab(tab);
-  if (index == -1)
-    return true;  // Tab is closing, paint it all.
-
-  int active_index = IsStackingDraggedTabs() ? controller_->GetActiveIndex()
-                                             : touch_layout_->active_index();
-  if (active_index == tab_count())
-    active_index--;
-
-  const int current_x = tab_at(index)->x();
-  if (index < active_index) {
-    const int next_x = tab_at(index + 1)->x();
-    if (current_x == next_x)
-      return false;
-
-    if (current_x > next_x)
-      return true;  // Can happen during dragging.
-
-    *clip = border_callback.Run(tab_at(index + 1)->size());
-    clip->offset(SkIntToScalar(next_x - current_x), 0);
-  } else if (index > active_index && index > 0) {
-    const gfx::Rect& previous_bounds(tab_at(index - 1)->bounds());
-    const int previous_x = previous_bounds.x();
-    if (current_x == previous_x)
-      return false;
-
-    if (current_x < previous_x)
-      return true;  // Can happen during dragging.
-
-    if (previous_bounds.right() - Tab::GetOverlap() != current_x) {
-      *clip = border_callback.Run(tab_at(index - 1)->size());
-      clip->offset(SkIntToScalar(previous_x - current_x), 0);
-    }
-  }
-  return true;
-}
-
-bool TabStripImpl::CanPaintThrobberToLayer() const {
-  // Disable layer-painting of throbbers if dragging, if any tab animation is in
-  // progress, or if stacked tabs are enabled. Also disable in fullscreen: when
-  // "immersive" the tab strip could be sliding in or out; for other modes,
-  // there's no tab strip.
-  const bool dragging = drag_controller_ && drag_controller_->started_drag();
-  const views::Widget* widget = GetWidget();
-  return widget && !touch_layout_ && !dragging && !IsAnimating() &&
-         !widget->IsFullscreen();
-}
-
-SkColor TabStripImpl::GetToolbarTopSeparatorColor() const {
-  return controller_->GetToolbarTopSeparatorColor();
-}
-
-// Returns the accessible tab name for the tab.
-base::string16 TabStripImpl::GetAccessibleTabName(const Tab* tab) const {
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    return controller_->GetAccessibleTabName(tab);
-  return base::string16();
-}
-
-int TabStripImpl::GetBackgroundResourceId(bool* custom_image) const {
-  const ui::ThemeProvider* tp = GetThemeProvider();
-
-  if (TitlebarBackgroundIsTransparent()) {
-    const int kBackgroundIdGlass = IDR_THEME_TAB_BACKGROUND_V;
-    *custom_image = tp->HasCustomImage(kBackgroundIdGlass);
-    return kBackgroundIdGlass;
-  }
-
-  // If a custom theme does not provide a replacement tab background, but does
-  // provide a replacement frame image, HasCustomImage() on the tab background
-  // ID will return false, but the theme provider will make a custom image from
-  // the frame image.  Furthermore, since the theme provider will create the
-  // incognito frame image from the normal frame image, in incognito mode we
-  // need to look for a custom incognito _or_ regular frame image.
-  const bool incognito = controller_->IsIncognito();
-  const int id =
-      incognito ? IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
-  *custom_image = tp->HasCustomImage(id) ||
-                  tp->HasCustomImage(IDR_THEME_FRAME) ||
-                  (incognito && tp->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
-  return id;
-}
-
-void TabStripImpl::MouseMovedOutOfHost() {
-  ResizeLayoutTabs();
-  if (reset_to_shrink_on_exit_) {
-    reset_to_shrink_on_exit_ = false;
-    SetStackedLayout(false);
-    controller_->StackedLayoutMaybeChanged();
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// TabStripImpl, views::View overrides:
-
-void TabStripImpl::Layout() {
-  // Only do a layout if our size changed.
-  if (last_layout_size_ == size())
-    return;
-  if (IsDragSessionActive())
-    return;
-  DoLayout();
-}
-
-void TabStripImpl::PaintChildren(const views::PaintInfo& paint_info) {
-  // The view order doesn't match the paint order (tabs_ contains the tab
-  // ordering). Additionally we need to paint the tabs that are closing in
-  // |tabs_closing_map_|.
-  bool is_dragging = false;
-  Tab* active_tab = NULL;
-  Tabs tabs_dragging;
-  Tabs selected_tabs;
-
-  {
-    // We pass false for |lcd_text_requires_opaque_layer| so that background
-    // tab titles will get LCD AA.  These are rendered opaquely on an opaque tab
-    // background before the layer is composited, so this is safe.
-    ui::CompositingRecorder opacity_recorder(paint_info.context(),
-                                             GetInactiveAlpha(false), false);
-
-    PaintClosingTabs(tab_count(), paint_info);
-
-    int active_tab_index = -1;
-    for (int i = tab_count() - 1; i >= 0; --i) {
-      Tab* tab = tab_at(i);
-      if (tab->dragging() && !stacked_layout_) {
-        is_dragging = true;
-        if (tab->IsActive()) {
-          active_tab = tab;
-          active_tab_index = i;
-        } else {
-          tabs_dragging.push_back(tab);
-        }
-      } else if (!tab->IsActive()) {
-        if (!tab->IsSelected()) {
-          if (!stacked_layout_)
-            tab->Paint(paint_info);
-        } else {
-          selected_tabs.push_back(tab);
-        }
-      } else {
-        active_tab = tab;
-        active_tab_index = i;
-      }
-      PaintClosingTabs(i, paint_info);
-    }
-
-    // Draw from the left and then the right if we're in touch mode.
-    if (stacked_layout_ && active_tab_index >= 0) {
-      for (int i = 0; i < active_tab_index; ++i) {
-        Tab* tab = tab_at(i);
-        tab->Paint(paint_info);
-      }
-
-      for (int i = tab_count() - 1; i > active_tab_index; --i) {
-        Tab* tab = tab_at(i);
-        tab->Paint(paint_info);
-      }
-    }
-  }
-
-  // Now selected but not active. We don't want these dimmed if using native
-  // frame, so they're painted after initial pass.
-  for (size_t i = 0; i < selected_tabs.size(); ++i)
-    selected_tabs[i]->Paint(paint_info);
-
-  // Next comes the active tab.
-  if (active_tab && !is_dragging)
-    active_tab->Paint(paint_info);
-
-  // Paint the New Tab button.
-  if (new_tab_button_->state() == views::Button::STATE_PRESSED) {
-    new_tab_button_->Paint(paint_info);
-  } else {
-    // Match the inactive tab opacity for non-pressed states.  See comments in
-    // NewTabButton::PaintFill() for why we don't do this for the pressed state.
-    // This call doesn't need to set |lcd_text_requires_opaque_layer| to false
-    // because no text will be drawn.
-    ui::CompositingRecorder opacity_recorder(paint_info.context(),
-                                             GetInactiveAlpha(true), true);
-    new_tab_button_->Paint(paint_info);
-  }
-
-  // And the dragged tabs.
-  for (size_t i = 0; i < tabs_dragging.size(); ++i)
-    tabs_dragging[i]->Paint(paint_info);
-
-  // If the active tab is being dragged, it goes last.
-  if (active_tab && is_dragging)
-    active_tab->Paint(paint_info);
-
-  // Keep the recording scales consistent for the tab strip and its children.
-  // See crbug/753911
-  ui::PaintRecorder recorder(paint_info.context(),
-                             paint_info.paint_recording_size(),
-                             paint_info.paint_recording_scale_x(),
-                             paint_info.paint_recording_scale_y(), nullptr);
-
-  gfx::Canvas* canvas = recorder.canvas();
-  if (active_tab) {
-    canvas->sk_canvas()->clipRect(
-        gfx::RectToSkRect(active_tab->GetMirroredBounds()),
-        SkClipOp::kDifference);
-  }
-  BrowserView::Paint1pxHorizontalLine(canvas, GetToolbarTopSeparatorColor(),
-                                      GetLocalBounds(), true);
-}
-
-const char* TabStripImpl::GetClassName() const {
-  static const char kViewClassName[] = "TabStrip";
-  return kViewClassName;
-}
-
-gfx::Size TabStripImpl::CalculatePreferredSize() const {
-  int needed_tab_width;
-  if (touch_layout_ || adjust_layout_) {
-    // For stacked tabs the minimum size is calculated as the size needed to
-    // handle showing any number of tabs.
-    needed_tab_width =
-        Tab::GetTouchWidth() + (2 * kStackedPadding * kMaxStackedCount);
-  } else {
-    // Otherwise the minimum width is based on the actual number of tabs.
-    const int pinned_tab_count = GetPinnedTabCount();
-    needed_tab_width = pinned_tab_count * Tab::GetPinnedWidth();
-    const int remaining_tab_count = tab_count() - pinned_tab_count;
-    const int min_selected_width = Tab::GetMinimumActiveSize().width();
-    const int min_unselected_width = Tab::GetMinimumInactiveSize().width();
-    if (remaining_tab_count > 0) {
-      needed_tab_width += kPinnedToNonPinnedOffset + min_selected_width +
-                          ((remaining_tab_count - 1) * min_unselected_width);
-    }
-
-    const int overlap = Tab::GetOverlap();
-    if (tab_count() > 1)
-      needed_tab_width -= (tab_count() - 1) * overlap;
-
-    // Don't let the tabstrip shrink smaller than is necessary to show one tab,
-    // and don't force it to be larger than is necessary to show 20 tabs.
-    const int largest_min_tab_width =
-        min_selected_width + 19 * (min_unselected_width - overlap);
-    needed_tab_width = std::min(std::max(needed_tab_width, min_selected_width),
-                                largest_min_tab_width);
-  }
-  return gfx::Size(needed_tab_width + GetNewTabButtonWidth(),
-                   Tab::GetMinimumInactiveSize().height());
-}
-
-void TabStripImpl::OnDragEntered(const DropTargetEvent& event) {
-  // Force animations to stop, otherwise it makes the index calculation tricky.
-  StopAnimating(true);
-
-  UpdateDropIndex(event);
-
-  GURL url;
-  base::string16 title;
-
-  // Check whether the event data includes supported drop data.
-  if (event.data().GetURLAndTitle(ui::OSExchangeData::CONVERT_FILENAMES, &url,
-                                  &title) &&
-      url.is_valid()) {
-    drop_info_->url = url;
-
-    // For file:// URLs, kick off a MIME type request in case they're dropped.
-    if (url.SchemeIsFile())
-      controller_->CheckFileSupported(url);
-  }
-}
-
-int TabStripImpl::OnDragUpdated(const DropTargetEvent& event) {
-  // Update the drop index even if the file is unsupported, to allow
-  // dragging a file to the contents of another tab.
-  UpdateDropIndex(event);
-
-  if (!drop_info_->file_supported ||
-      drop_info_->url.SchemeIs(url::kJavaScriptScheme))
-    return ui::DragDropTypes::DRAG_NONE;
-
-  return GetDropEffect(event);
-}
-
-void TabStripImpl::OnDragExited() {
-  SetDropIndex(-1, false);
-}
-
-int TabStripImpl::OnPerformDrop(const DropTargetEvent& event) {
-  if (!drop_info_.get())
-    return ui::DragDropTypes::DRAG_NONE;
-
-  const int drop_index = drop_info_->drop_index;
-  const bool drop_before = drop_info_->drop_before;
-  const bool file_supported = drop_info_->file_supported;
-
-  // Hide the drop indicator.
-  SetDropIndex(-1, false);
-
-  // Do nothing if the file was unsupported, the URL is invalid, or this is a
-  // javascript: URL (prevent self-xss). The URL may have been changed after
-  // |drop_info_| was created.
-  GURL url;
-  base::string16 title;
-  if (!file_supported ||
-      !event.data().GetURLAndTitle(ui::OSExchangeData::CONVERT_FILENAMES, &url,
-                                   &title) ||
-      !url.is_valid() || url.SchemeIs(url::kJavaScriptScheme))
-    return ui::DragDropTypes::DRAG_NONE;
-
-  controller_->PerformDrop(drop_before, drop_index, url);
-
-  return GetDropEffect(event);
-}
-
-void TabStripImpl::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->role = ui::AX_ROLE_TAB_LIST;
-}
-
-views::View* TabStripImpl::GetTooltipHandlerForPoint(const gfx::Point& point) {
-  if (!HitTestPoint(point))
-    return NULL;
-
-  if (!touch_layout_) {
-    // Return any view that isn't a Tab or this TabStrip immediately. We don't
-    // want to interfere.
-    views::View* v = View::GetTooltipHandlerForPoint(point);
-    if (v && v != this && strcmp(v->GetClassName(), Tab::kViewClassName))
-      return v;
-
-    views::View* tab = FindTabHitByPoint(point);
-    if (tab)
-      return tab;
-  } else {
-    if (new_tab_button_->visible()) {
-      views::View* view =
-          ConvertPointToViewAndGetTooltipHandler(this, new_tab_button_, point);
-      if (view)
-        return view;
-    }
-    Tab* tab = FindTabForEvent(point);
-    if (tab)
-      return ConvertPointToViewAndGetTooltipHandler(this, tab, point);
-  }
-  return this;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// TabStripImpl, private:
-
-void TabStripImpl::Init() {
-  set_id(VIEW_ID_TAB_STRIP);
-  // So we get enter/exit on children to switch stacked layout on and off.
-  set_notify_enter_exit_on_child(true);
-
-  new_tab_button_bounds_.set_size(GetLayoutSize(NEW_TAB_BUTTON));
-  new_tab_button_bounds_.Inset(0, 0, 0, -NewTabButton::GetTopOffset());
-  new_tab_button_ = new NewTabButton(this, this);
-  new_tab_button_->SetTooltipText(
-      l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB));
-  new_tab_button_->SetAccessibleName(
-      l10n_util::GetStringUTF16(IDS_ACCNAME_NEWTAB));
-  new_tab_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
-                                     views::ImageButton::ALIGN_BOTTOM);
-  new_tab_button_->SetEventTargeter(
-      std::make_unique<views::ViewTargeter>(new_tab_button_));
-  AddChildView(new_tab_button_);
-
-  if (drop_indicator_width == 0) {
-    // Direction doesn't matter, both images are the same size.
-    gfx::ImageSkia* drop_image = GetDropArrowImage(true);
-    drop_indicator_width = drop_image->width();
-    drop_indicator_height = drop_image->height();
-  }
-}
-
-void TabStripImpl::StartInsertTabAnimation(int model_index) {
-  PrepareForAnimation();
-
-  // The TabStrip can now use its entire width to lay out Tabs.
-  in_tab_close_ = false;
-  available_width_for_tabs_ = -1;
-
-  GenerateIdealBounds();
-
-  // Set the current bounds to be the correct place but 0 width.
-  Tab* tab = tab_at(model_index);
-  if (model_index == 0) {
-    tab->SetBounds(0, ideal_bounds(model_index).y(), 0,
-                   ideal_bounds(model_index).height());
-  } else {
-    Tab* prev_tab = tab_at(model_index - 1);
-    tab->SetBounds(prev_tab->bounds().right() - Tab::GetOverlap(),
-                   ideal_bounds(model_index).y(), 0,
-                   ideal_bounds(model_index).height());
-  }
-
-  // Animate in to the full width.
-  AnimateToIdealBounds();
-}
-
-void TabStripImpl::StartMoveTabAnimation() {
-  PrepareForAnimation();
-  GenerateIdealBounds();
-  AnimateToIdealBounds();
-}
-
-void TabStripImpl::StartRemoveTabAnimation(int model_index) {
-  PrepareForAnimation();
-
-  // Mark the tab as closing.
-  Tab* tab = tab_at(model_index);
-  tab->set_closing(true);
-
-  RemoveTabFromViewModel(model_index);
-
-  ScheduleRemoveTabAnimation(tab);
-}
-
-void TabStripImpl::ScheduleRemoveTabAnimation(Tab* tab) {
-  // Start an animation for the tabs.
-  GenerateIdealBounds();
-  AnimateToIdealBounds();
-
-  // Animate the tab being closed to zero width.
-  gfx::Rect tab_bounds = tab->bounds();
-  tab_bounds.set_width(0);
-  bounds_animator_.AnimateViewTo(tab, tab_bounds);
-  bounds_animator_.SetAnimationDelegate(
-      tab, std::make_unique<RemoveTabDelegate>(this, tab));
-
-  // Don't animate the new tab button when dragging tabs. Otherwise it looks
-  // like the new tab button magically appears from beyond the end of the tab
-  // strip.
-  if (TabDragController::IsAttachedTo(this)) {
-    bounds_animator_.StopAnimatingView(new_tab_button_);
-    new_tab_button_->SetBoundsRect(new_tab_button_bounds_);
-  }
-}
-
-void TabStripImpl::AnimateToIdealBounds() {
-  for (int i = 0; i < tab_count(); ++i) {
-    Tab* tab = tab_at(i);
-    if (!tab->dragging()) {
-      bounds_animator_.AnimateViewTo(tab, ideal_bounds(i));
-      bounds_animator_.SetAnimationDelegate(
-          tab, std::make_unique<TabAnimationDelegate>(this, tab));
-    }
-  }
-
-  bounds_animator_.AnimateViewTo(new_tab_button_, new_tab_button_bounds_);
-}
-
-bool TabStripImpl::ShouldHighlightCloseButtonAfterRemove() {
-  return in_tab_close_;
-}
-
-bool TabStripImpl::TitlebarBackgroundIsTransparent() const {
-#if defined(OS_WIN)
-  // Windows 8+ uses transparent window contents (because the titlebar area is
-  // drawn by the system and not Chrome), but the actual titlebar is opaque.
-  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
-    return false;
-#endif
-  return GetWidget()->ShouldWindowContentsBeTransparent();
-}
-
-void TabStripImpl::DoLayout() {
-  last_layout_size_ = size();
-
-  StopAnimating(false);
-
-  SwapLayoutIfNecessary();
-
-  if (touch_layout_)
-    touch_layout_->SetWidth(GetTabAreaWidth());
-
-  GenerateIdealBounds();
-
-  views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_);
-  SetTabVisibility();
-
-  SchedulePaint();
-
-  bounds_animator_.StopAnimatingView(new_tab_button_);
-  new_tab_button_->SetBoundsRect(new_tab_button_bounds_);
-}
-
-void TabStripImpl::SetTabVisibility() {
-  // We could probably be more efficient here by making use of the fact that the
-  // tabstrip will always have any visible tabs, and then any invisible tabs, so
-  // we could e.g. binary-search for the changeover point.  But since we have to
-  // iterate through all the tabs to call SetVisible() anyway, it doesn't seem
-  // worth it.
-  for (int i = 0; i < tab_count(); ++i) {
-    Tab* tab = tab_at(i);
-    tab->SetVisible(ShouldTabBeVisible(tab));
-  }
-  for (const auto& closing_tab : tabs_closing_map_) {
-    for (Tab* tab : closing_tab.second)
-      tab->SetVisible(ShouldTabBeVisible(tab));
-  }
-}
-
-void TabStripImpl::DragActiveTab(const std::vector<int>& initial_positions,
-                                 int delta) {
-  DCHECK_EQ(tab_count(), static_cast<int>(initial_positions.size()));
-  if (!touch_layout_) {
-    StackDraggedTabs(delta);
-    return;
-  }
-  SetIdealBoundsFromPositions(initial_positions);
-  touch_layout_->DragActiveTab(delta);
-  DoLayout();
-}
-
-void TabStripImpl::SetIdealBoundsFromPositions(
-    const std::vector<int>& positions) {
-  if (static_cast<size_t>(tab_count()) != positions.size())
-    return;
-
-  for (int i = 0; i < tab_count(); ++i) {
-    gfx::Rect bounds(ideal_bounds(i));
-    bounds.set_x(positions[i]);
-    tabs_.set_ideal_bounds(i, bounds);
-  }
-}
-
-void TabStripImpl::StackDraggedTabs(int delta) {
-  DCHECK(!touch_layout_);
-  GenerateIdealBounds();
-  const int active_index = controller_->GetActiveIndex();
-  DCHECK_NE(-1, active_index);
-  if (delta < 0) {
-    // Drag the tabs to the left, stacking tabs before the active tab.
-    const int adjusted_delta =
-        std::min(ideal_bounds(active_index).x() -
-                     kStackedPadding * std::min(active_index, kMaxStackedCount),
-                 -delta);
-    for (int i = 0; i <= active_index; ++i) {
-      const int min_x = std::min(i, kMaxStackedCount) * kStackedPadding;
-      gfx::Rect new_bounds(ideal_bounds(i));
-      new_bounds.set_x(std::max(min_x, new_bounds.x() - adjusted_delta));
-      tabs_.set_ideal_bounds(i, new_bounds);
-    }
-    const bool is_active_pinned = tab_at(active_index)->data().pinned;
-    const int active_width = ideal_bounds(active_index).width();
-    for (int i = active_index + 1; i < tab_count(); ++i) {
-      const int max_x =
-          ideal_bounds(active_index).x() +
-          (kStackedPadding * std::min(i - active_index, kMaxStackedCount));
-      gfx::Rect new_bounds(ideal_bounds(i));
-      int new_x = std::max(new_bounds.x() + delta, max_x);
-      if (new_x == max_x && !tab_at(i)->data().pinned && !is_active_pinned &&
-          new_bounds.width() != active_width)
-        new_x += (active_width - new_bounds.width());
-      new_bounds.set_x(new_x);
-      tabs_.set_ideal_bounds(i, new_bounds);
-    }
-  } else {
-    // Drag the tabs to the right, stacking tabs after the active tab.
-    const int last_tab_width = ideal_bounds(tab_count() - 1).width();
-    const int last_tab_x = GetTabAreaWidth() - last_tab_width;
-    if (active_index == tab_count() - 1 &&
-        ideal_bounds(tab_count() - 1).x() == last_tab_x)
-      return;
-    const int adjusted_delta =
-        std::min(last_tab_x -
-                     kStackedPadding * std::min(tab_count() - active_index - 1,
-                                                kMaxStackedCount) -
-                     ideal_bounds(active_index).x(),
-                 delta);
-    for (int last_index = tab_count() - 1, i = last_index; i >= active_index;
-         --i) {
-      const int max_x =
-          last_tab_x -
-          std::min(tab_count() - i - 1, kMaxStackedCount) * kStackedPadding;
-      gfx::Rect new_bounds(ideal_bounds(i));
-      int new_x = std::min(max_x, new_bounds.x() + adjusted_delta);
-      // Because of rounding not all tabs are the same width. Adjust the
-      // position to accommodate this, otherwise the stacking is off.
-      if (new_x == max_x && !tab_at(i)->data().pinned &&
-          new_bounds.width() != last_tab_width)
-        new_x += (last_tab_width - new_bounds.width());
-      new_bounds.set_x(new_x);
-      tabs_.set_ideal_bounds(i, new_bounds);
-    }
-    for (int i = active_index - 1; i >= 0; --i) {
-      const int min_x =
-          ideal_bounds(active_index).x() -
-          std::min(active_index - i, kMaxStackedCount) * kStackedPadding;
-      gfx::Rect new_bounds(ideal_bounds(i));
-      new_bounds.set_x(std::min(min_x, new_bounds.x() + delta));
-      tabs_.set_ideal_bounds(i, new_bounds);
-    }
-    if (ideal_bounds(tab_count() - 1).right() >= new_tab_button_->x())
-      new_tab_button_->SetVisible(false);
-  }
-  views::ViewModelUtils::SetViewBoundsToIdealBounds(tabs_);
-  SchedulePaint();
-}
-
-bool TabStripImpl::IsStackingDraggedTabs() const {
-  return drag_controller_.get() && drag_controller_->started_drag() &&
-         (drag_controller_->move_behavior() ==
-          TabDragController::MOVE_VISIBLE_TABS);
-}
-
-void TabStripImpl::LayoutDraggedTabsAt(const Tabs& tabs,
-                                       Tab* active_tab,
-                                       const gfx::Point& location,
-                                       bool initial_drag) {
-  // Immediately hide the new tab button if the last tab is being dragged.
-  const Tab* last_visible_tab = GetLastVisibleTab();
-  if (last_visible_tab && last_visible_tab->dragging())
-    new_tab_button_->SetVisible(false);
-  std::vector<gfx::Rect> bounds;
-  CalculateBoundsForDraggedTabs(tabs, &bounds);
-  DCHECK_EQ(tabs.size(), bounds.size());
-  int active_tab_model_index = GetModelIndexOfTab(active_tab);
-  int active_tab_index = static_cast<int>(
-      std::find(tabs.begin(), tabs.end(), active_tab) - tabs.begin());
-  for (size_t i = 0; i < tabs.size(); ++i) {
-    Tab* tab = tabs[i];
-    gfx::Rect new_bounds = bounds[i];
-    new_bounds.Offset(location.x(), location.y());
-    int consecutive_index =
-        active_tab_model_index - (active_tab_index - static_cast<int>(i));
-    // If this is the initial layout during a drag and the tabs aren't
-    // consecutive animate the view into position. Do the same if the tab is
-    // already animating (which means we previously caused it to animate).
-    if ((initial_drag && GetModelIndexOfTab(tabs[i]) != consecutive_index) ||
-        bounds_animator_.IsAnimating(tabs[i])) {
-      bounds_animator_.SetTargetBounds(tabs[i], new_bounds);
-    } else {
-      tab->SetBoundsRect(new_bounds);
-    }
-  }
-  SetTabVisibility();
-}
-
-void TabStripImpl::CalculateBoundsForDraggedTabs(
-    const Tabs& tabs,
-    std::vector<gfx::Rect>* bounds) {
-  const int overlap = Tab::GetOverlap();
-  int x = 0;
-  for (size_t i = 0; i < tabs.size(); ++i) {
-    Tab* tab = tabs[i];
-    if (i > 0 && tab->data().pinned != tabs[i - 1]->data().pinned)
-      x += kPinnedToNonPinnedOffset;
-    gfx::Rect new_bounds = tab->bounds();
-    new_bounds.set_origin(gfx::Point(x, 0));
-    bounds->push_back(new_bounds);
-    x += tab->width() - overlap;
-  }
-}
-
-int TabStripImpl::GetSizeNeededForTabs(const Tabs& tabs) {
-  int width = 0;
-  for (size_t i = 0; i < tabs.size(); ++i) {
-    Tab* tab = tabs[i];
-    width += tab->width();
-    if (i > 0 && tab->data().pinned != tabs[i - 1]->data().pinned)
-      width += kPinnedToNonPinnedOffset;
-  }
-  if (!tabs.empty())
-    width -= Tab::GetOverlap() * (tabs.size() - 1);
-  return width;
-}
-
-int TabStripImpl::GetPinnedTabCount() const {
-  int pinned_count = 0;
-  while (pinned_count < tab_count() && tab_at(pinned_count)->data().pinned)
-    pinned_count++;
-  return pinned_count;
-}
-
-const Tab* TabStripImpl::GetLastVisibleTab() const {
-  for (int i = tab_count() - 1; i >= 0; --i) {
-    const Tab* tab = tab_at(i);
-    if (tab->visible())
-      return tab;
-  }
-  // While in normal use the tabstrip should always be wide enough to have at
-  // least one visible tab, it can be zero-width in tests, meaning we get here.
-  return NULL;
-}
-
-void TabStripImpl::RemoveTabFromViewModel(int index) {
-  // We still need to paint the tab until we actually remove it. Put it
-  // in tabs_closing_map_ so we can find it.
-  tabs_closing_map_[index].push_back(tab_at(index));
-  UpdateTabsClosingMap(index + 1, -1);
-  tabs_.Remove(index);
-}
-
-void TabStripImpl::RemoveAndDeleteTab(Tab* tab) {
-  std::unique_ptr<Tab> deleter(tab);
-  FindClosingTabResult res(FindClosingTab(tab));
-  res.first->second.erase(res.second);
-  if (res.first->second.empty())
-    tabs_closing_map_.erase(res.first);
-}
-
-void TabStripImpl::UpdateTabsClosingMap(int index, int delta) {
-  if (tabs_closing_map_.empty())
-    return;
-
-  if (delta == -1 &&
-      tabs_closing_map_.find(index - 1) != tabs_closing_map_.end() &&
-      tabs_closing_map_.find(index) != tabs_closing_map_.end()) {
-    const Tabs& tabs(tabs_closing_map_[index]);
-    tabs_closing_map_[index - 1].insert(tabs_closing_map_[index - 1].end(),
-                                        tabs.begin(), tabs.end());
-  }
-  TabsClosingMap updated_map;
-  for (auto& i : tabs_closing_map_) {
-    if (i.first > index)
-      updated_map[i.first + delta] = i.second;
-    else if (i.first < index)
-      updated_map[i.first] = i.second;
-  }
-  if (delta > 0 && tabs_closing_map_.find(index) != tabs_closing_map_.end())
-    updated_map[index + delta] = tabs_closing_map_[index];
-  tabs_closing_map_.swap(updated_map);
-}
-
-void TabStripImpl::StartedDraggingTabs(const Tabs& tabs) {
-  // Let the controller know that the user started dragging tabs.
-  controller_->OnStartedDraggingTabs();
-
-  // Hide the new tab button immediately if we didn't originate the drag.
-  if (!drag_controller_.get())
-    new_tab_button_->SetVisible(false);
-
-  PrepareForAnimation();
-
-  // Reset dragging state of existing tabs.
-  for (int i = 0; i < tab_count(); ++i)
-    tab_at(i)->set_dragging(false);
-
-  for (size_t i = 0; i < tabs.size(); ++i) {
-    tabs[i]->set_dragging(true);
-    bounds_animator_.StopAnimatingView(tabs[i]);
-  }
-
-  // Move the dragged tabs to their ideal bounds.
-  GenerateIdealBounds();
-
-  // Sets the bounds of the dragged tabs.
-  for (size_t i = 0; i < tabs.size(); ++i) {
-    int tab_data_index = GetModelIndexOfTab(tabs[i]);
-    DCHECK_NE(-1, tab_data_index);
-    tabs[i]->SetBoundsRect(ideal_bounds(tab_data_index));
-  }
-  SetTabVisibility();
-  SchedulePaint();
-}
-
-void TabStripImpl::DraggedTabsDetached() {
-  // Let the controller know that the user is not dragging this tabstrip's tabs
-  // anymore.
-  controller_->OnStoppedDraggingTabs();
-  new_tab_button_->SetVisible(true);
-}
-
-void TabStripImpl::StoppedDraggingTabs(
-    const Tabs& tabs,
-    const std::vector<int>& initial_positions,
-    bool move_only,
-    bool completed) {
-  // Let the controller know that the user stopped dragging tabs.
-  controller_->OnStoppedDraggingTabs();
-
-  new_tab_button_->SetVisible(true);
-  if (move_only && touch_layout_) {
-    if (completed)
-      touch_layout_->SizeToFit();
-    else
-      SetIdealBoundsFromPositions(initial_positions);
-  }
-  bool is_first_tab = true;
-  for (size_t i = 0; i < tabs.size(); ++i)
-    StoppedDraggingTab(tabs[i], &is_first_tab);
-}
-
-void TabStripImpl::StoppedDraggingTab(Tab* tab, bool* is_first_tab) {
-  int tab_data_index = GetModelIndexOfTab(tab);
-  if (tab_data_index == -1) {
-    // The tab was removed before the drag completed. Don't do anything.
-    return;
-  }
-
-  if (*is_first_tab) {
-    *is_first_tab = false;
-    PrepareForAnimation();
-
-    // Animate the view back to its correct position.
-    GenerateIdealBounds();
-    AnimateToIdealBounds();
-  }
-  bounds_animator_.AnimateViewTo(tab, ideal_bounds(tab_data_index));
-  // Install a delegate to reset the dragging state when done. We have to leave
-  // dragging true for the tab otherwise it'll draw beneath the new tab button.
-  bounds_animator_.SetAnimationDelegate(
-      tab, std::make_unique<ResetDraggingStateDelegate>(this, tab));
-}
-
-void TabStripImpl::OwnDragController(TabDragController* controller) {
-  // Typically, ReleaseDragController() and OwnDragController() calls are paired
-  // via corresponding calls to TabDragController::Detach() and
-  // TabDragController::Attach(). There is one exception to that rule: when a
-  // drag might start, we create a TabDragController that is owned by the
-  // potential source tabstrip in MaybeStartDrag(). If a drag actually starts,
-  // we then call Attach() on the source tabstrip, but since the source tabstrip
-  // already owns the TabDragController, so we don't need to do anything.
-  if (controller != drag_controller_.get())
-    drag_controller_.reset(controller);
-}
-
-void TabStripImpl::DestroyDragController() {
-  new_tab_button_->SetVisible(true);
-  drag_controller_.reset();
-}
-
-TabDragController* TabStripImpl::ReleaseDragController() {
-  return drag_controller_.release();
-}
-
-TabStripImpl::FindClosingTabResult TabStripImpl::FindClosingTab(
-    const Tab* tab) {
-  DCHECK(tab->closing());
-  for (auto i = tabs_closing_map_.begin(); i != tabs_closing_map_.end(); ++i) {
-    Tabs::iterator j = std::find(i->second.begin(), i->second.end(), tab);
-    if (j != i->second.end())
-      return FindClosingTabResult(i, j);
-  }
-  NOTREACHED();
-  return FindClosingTabResult(tabs_closing_map_.end(), Tabs::iterator());
-}
-
-void TabStripImpl::PaintClosingTabs(int index,
-                                    const views::PaintInfo& paint_info) {
-  if (tabs_closing_map_.find(index) == tabs_closing_map_.end())
-    return;
-  for (Tab* tab : base::Reversed(tabs_closing_map_[index]))
-    tab->Paint(paint_info);
-}
-
-void TabStripImpl::UpdateStackedLayoutFromMouseEvent(
-    views::View* source,
-    const ui::MouseEvent& event) {
-  if (!adjust_layout_)
-    return;
-
-  // The following code attempts to switch to shrink (not stacked) layout when
-  // the mouse exits the tabstrip (or the mouse is pressed on a stacked tab) and
-  // to stacked layout when a touch device is used. This is made problematic by
-  // windows generating mouse move events that do not clearly indicate the move
-  // is the result of a touch device. This assumes a real mouse is used if
-  // |kMouseMoveCountBeforeConsiderReal| mouse move events are received within
-  // the time window |kMouseMoveTimeMS|.  At the time we get a mouse press we
-  // know whether its from a touch device or not, but we don't layout then else
-  // everything shifts. Instead we wait for the release.
-  //
-  // TODO(sky): revisit this when touch events are really plumbed through.
-
-  switch (event.type()) {
-    case ui::ET_MOUSE_PRESSED:
-      mouse_move_count_ = 0;
-      last_mouse_move_time_ = base::TimeTicks();
-      SetResetToShrinkOnExit((event.flags() & ui::EF_FROM_TOUCH) == 0);
-      if (reset_to_shrink_on_exit_ && touch_layout_) {
-        gfx::Point tab_strip_point(event.location());
-        views::View::ConvertPointToTarget(source, this, &tab_strip_point);
-        Tab* tab = FindTabForEvent(tab_strip_point);
-        if (tab && touch_layout_->IsStacked(GetModelIndexOfTab(tab))) {
-          SetStackedLayout(false);
-          controller_->StackedLayoutMaybeChanged();
-        }
-      }
-      break;
-
-    case ui::ET_MOUSE_MOVED: {
-#if defined(OS_CHROMEOS)
-      // Ash does not synthesize mouse events from touch events.
-      SetResetToShrinkOnExit(true);
-#else
-      gfx::Point location(event.location());
-      ConvertPointToTarget(source, this, &location);
-      if (location == last_mouse_move_location_)
-        return;  // Ignore spurious moves.
-      last_mouse_move_location_ = location;
-      if ((event.flags() & ui::EF_FROM_TOUCH) == 0 &&
-          (event.flags() & ui::EF_IS_SYNTHESIZED) == 0) {
-        if ((base::TimeTicks::Now() - last_mouse_move_time_).InMilliseconds() <
-            kMouseMoveTimeMS) {
-          if (mouse_move_count_++ == kMouseMoveCountBeforeConsiderReal)
-            SetResetToShrinkOnExit(true);
-        } else {
-          mouse_move_count_ = 1;
-          last_mouse_move_time_ = base::TimeTicks::Now();
-        }
-      } else {
-        last_mouse_move_time_ = base::TimeTicks();
-      }
-#endif
-      break;
-    }
-
-    case ui::ET_MOUSE_RELEASED: {
-      gfx::Point location(event.location());
-      ConvertPointToTarget(source, this, &location);
-      last_mouse_move_location_ = location;
-      mouse_move_count_ = 0;
-      last_mouse_move_time_ = base::TimeTicks();
-      if ((event.flags() & ui::EF_FROM_TOUCH) == ui::EF_FROM_TOUCH) {
-        SetStackedLayout(true);
-        controller_->StackedLayoutMaybeChanged();
-      }
-      break;
-    }
-
-    default:
-      break;
-  }
-}
-
-void TabStripImpl::ResizeLayoutTabs() {
-  // We've been called back after the TabStrip has been emptied out (probably
-  // just prior to the window being destroyed). We need to do nothing here or
-  // else GetTabAt below will crash.
-  if (tab_count() == 0)
-    return;
-
-  // It is critically important that this is unhooked here, otherwise we will
-  // keep spying on messages forever.
-  RemoveMessageLoopObserver();
-
-  in_tab_close_ = false;
-  available_width_for_tabs_ = -1;
-  int pinned_tab_count = GetPinnedTabCount();
-  if (pinned_tab_count == tab_count()) {
-    // Only pinned tabs, we know the tab widths won't have changed (all
-    // pinned tabs have the same width), so there is nothing to do.
-    return;
-  }
-  // Don't try and avoid layout based on tab sizes. If tabs are small enough
-  // then the width of the active tab may not change, but other widths may
-  // have. This is particularly important if we've overflowed (all tabs are at
-  // the min).
-  StartResizeLayoutAnimation();
-}
-
-void TabStripImpl::ResizeLayoutTabsFromTouch() {
-  // Don't resize if the user is interacting with the tabstrip.
-  if (!drag_controller_.get())
-    ResizeLayoutTabs();
-  else
-    StartResizeLayoutTabsFromTouchTimer();
-}
-
-void TabStripImpl::StartResizeLayoutTabsFromTouchTimer() {
-  resize_layout_timer_.Stop();
-  resize_layout_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMilliseconds(kTouchResizeLayoutTimeMS),
-      this, &TabStripImpl::ResizeLayoutTabsFromTouch);
-}
-
-void TabStripImpl::SetTabBoundsForDrag(
-    const std::vector<gfx::Rect>& tab_bounds) {
-  StopAnimating(false);
-  DCHECK_EQ(tab_count(), static_cast<int>(tab_bounds.size()));
-  for (int i = 0; i < tab_count(); ++i)
-    tab_at(i)->SetBoundsRect(tab_bounds[i]);
-  // Reset the layout size as we've effectively layed out a different size.
-  // This ensures a layout happens after the drag is done.
-  last_layout_size_ = gfx::Size();
-}
-
-void TabStripImpl::AddMessageLoopObserver() {
-  if (!mouse_watcher_.get()) {
-    mouse_watcher_ = std::make_unique<views::MouseWatcher>(
-        std::make_unique<views::MouseWatcherViewHost>(
-            this, gfx::Insets(0, 0, kTabStripAnimationVSlop, 0)),
-        this);
-  }
-  mouse_watcher_->Start();
-}
-
-void TabStripImpl::RemoveMessageLoopObserver() {
-  mouse_watcher_.reset(NULL);
-}
-
-gfx::Rect TabStripImpl::GetDropBounds(int drop_index,
-                                      bool drop_before,
-                                      bool* is_beneath) {
-  DCHECK_NE(drop_index, -1);
-
-  const int overlap = Tab::GetOverlap();
-  int center_x;
-  if (drop_index < tab_count()) {
-    Tab* tab = tab_at(drop_index);
-    center_x = tab->x() + ((drop_before ? overlap : tab->width()) / 2);
-  } else {
-    Tab* last_tab = tab_at(drop_index - 1);
-    center_x = last_tab->x() + last_tab->width() - (overlap / 2);
-  }
-
-  // Mirror the center point if necessary.
-  center_x = GetMirroredXInView(center_x);
-
-  // Determine the screen bounds.
-  gfx::Point drop_loc(center_x - drop_indicator_width / 2,
-                      -drop_indicator_height);
-  ConvertPointToScreen(this, &drop_loc);
-  gfx::Rect drop_bounds(drop_loc.x(), drop_loc.y(), drop_indicator_width,
-                        drop_indicator_height);
-
-  // If the rect doesn't fit on the monitor, push the arrow to the bottom.
-  display::Screen* screen = display::Screen::GetScreen();
-  display::Display display = screen->GetDisplayMatching(drop_bounds);
-  *is_beneath = !display.bounds().Contains(drop_bounds);
-  if (*is_beneath)
-    drop_bounds.Offset(0, drop_bounds.height() + height());
-
-  return drop_bounds;
-}
-
-void TabStripImpl::UpdateDropIndex(const DropTargetEvent& event) {
-  // If the UI layout is right-to-left, we need to mirror the mouse
-  // coordinates since we calculate the drop index based on the
-  // original (and therefore non-mirrored) positions of the tabs.
-  const int x = GetMirroredXInView(event.x());
-  // We don't allow replacing the urls of pinned tabs.
-  for (int i = GetPinnedTabCount(); i < tab_count(); ++i) {
-    Tab* tab = tab_at(i);
-    const int tab_max_x = tab->x() + tab->width();
-    const int hot_width = tab->width() / kTabEdgeRatioInverse;
-    if (x < tab_max_x) {
-      if (x < tab->x() + hot_width)
-        SetDropIndex(i, true);
-      else if (x >= tab_max_x - hot_width)
-        SetDropIndex(i + 1, true);
-      else
-        SetDropIndex(i, false);
-      return;
-    }
-  }
-
-  // The drop isn't over a tab, add it to the end.
-  SetDropIndex(tab_count(), true);
-}
-
-void TabStripImpl::SetDropIndex(int tab_data_index, bool drop_before) {
-  // Let the controller know of the index update.
-  controller_->OnDropIndexUpdate(tab_data_index, drop_before);
-
-  if (tab_data_index == -1) {
-    if (drop_info_.get())
-      drop_info_.reset(NULL);
-    return;
-  }
-
-  if (drop_info_.get() && drop_info_->drop_index == tab_data_index &&
-      drop_info_->drop_before == drop_before) {
-    return;
-  }
-
-  bool is_beneath;
-  gfx::Rect drop_bounds =
-      GetDropBounds(tab_data_index, drop_before, &is_beneath);
-
-  if (!drop_info_.get()) {
-    drop_info_.reset(
-        new DropInfo(tab_data_index, drop_before, !is_beneath, GetWidget()));
-  } else {
-    drop_info_->drop_index = tab_data_index;
-    drop_info_->drop_before = drop_before;
-    if (is_beneath == drop_info_->point_down) {
-      drop_info_->point_down = !is_beneath;
-      drop_info_->arrow_view->SetImage(
-          GetDropArrowImage(drop_info_->point_down));
-    }
-  }
-
-  // Reposition the window. Need to show it too as the window is initially
-  // hidden.
-  drop_info_->arrow_window->SetBounds(drop_bounds);
-  drop_info_->arrow_window->Show();
-}
-
-int TabStripImpl::GetDropEffect(const ui::DropTargetEvent& event) {
-  const int source_ops = event.source_operations();
-  if (source_ops & ui::DragDropTypes::DRAG_COPY)
-    return ui::DragDropTypes::DRAG_COPY;
-  if (source_ops & ui::DragDropTypes::DRAG_LINK)
-    return ui::DragDropTypes::DRAG_LINK;
-  return ui::DragDropTypes::DRAG_MOVE;
-}
-
-// static
-gfx::ImageSkia* TabStripImpl::GetDropArrowImage(bool is_down) {
-  return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-      is_down ? IDR_TAB_DROP_DOWN : IDR_TAB_DROP_UP);
-}
-
-// TabStripImpl::DropInfo
-// ----------------------------------------------------------
-
-TabStripImpl::DropInfo::DropInfo(int drop_index,
-                                 bool drop_before,
-                                 bool point_down,
-                                 views::Widget* context)
-    : drop_index(drop_index),
-      drop_before(drop_before),
-      point_down(point_down),
-      file_supported(true) {
-  arrow_view = new views::ImageView;
-  arrow_view->SetImage(GetDropArrowImage(point_down));
-
-  arrow_window = new views::Widget;
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
-  params.keep_on_top = true;
-  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-  params.accept_events = false;
-  params.bounds = gfx::Rect(drop_indicator_width, drop_indicator_height);
-  params.context = context->GetNativeWindow();
-  arrow_window->Init(params);
-  arrow_window->SetContentsView(arrow_view);
-}
-
-TabStripImpl::DropInfo::~DropInfo() {
-  // Close eventually deletes the window, which deletes arrow_view too.
-  arrow_window->Close();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void TabStripImpl::PrepareForAnimation() {
-  if (!IsDragSessionActive() && !TabDragController::IsAttachedTo(this)) {
-    for (int i = 0; i < tab_count(); ++i)
-      tab_at(i)->set_dragging(false);
-  }
-}
-
-void TabStripImpl::GenerateIdealBounds() {
-  if (tab_count() == 0)
-    return;  // Should only happen during creation/destruction, ignore.
-
-  if (!touch_layout_) {
-    const int available_width = (available_width_for_tabs_ < 0)
-                                    ? GetTabAreaWidth()
-                                    : available_width_for_tabs_;
-    const std::vector<gfx::Rect> tabs_bounds =
-        CalculateBounds(GetTabSizeInfo(), GetPinnedTabCount(), tab_count(),
-                        controller_->GetActiveIndex(), available_width,
-                        &current_active_width_, &current_inactive_width_);
-    DCHECK_EQ(static_cast<size_t>(tab_count()), tabs_bounds.size());
-
-    for (size_t i = 0; i < tabs_bounds.size(); ++i)
-      tabs_.set_ideal_bounds(i, tabs_bounds[i]);
-  }
-
-  const int max_new_tab_x = width() - new_tab_button_bounds_.width();
-  // For non-stacked tabs the ideal bounds may go outside the bounds of the
-  // tabstrip. Constrain the x-coordinate of the new tab button so that it is
-  // always visible.
-  const int new_tab_x = std::min(
-      max_new_tab_x, tabs_.ideal_bounds(tabs_.view_size() - 1).right() -
-                         GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP));
-  const int old_max_x = new_tab_button_bounds_.right();
-  new_tab_button_bounds_.set_origin(gfx::Point(new_tab_x, 0));
-  if (new_tab_button_bounds_.right() != old_max_x) {
-    for (TabStripObserver& observer : observers())
-      observer.TabStripMaxXChanged(this);
-  }
-}
-
-int TabStripImpl::GenerateIdealBoundsForPinnedTabs(
-    int* first_non_pinned_index) {
-  const int num_pinned_tabs = GetPinnedTabCount();
-
-  if (first_non_pinned_index)
-    *first_non_pinned_index = num_pinned_tabs;
-
-  if (num_pinned_tabs == 0)
-    return 0;
-
-  std::vector<gfx::Rect> tab_bounds(tab_count());
-  CalculateBoundsForPinnedTabs(GetTabSizeInfo(), num_pinned_tabs, tab_count(),
-                               &tab_bounds);
-  for (int i = 0; i < num_pinned_tabs; ++i)
-    tabs_.set_ideal_bounds(i, tab_bounds[i]);
-  return (num_pinned_tabs < tab_count())
-             ? tab_bounds[num_pinned_tabs].x()
-             : tab_bounds[num_pinned_tabs - 1].right() - Tab::GetOverlap();
-}
-
-int TabStripImpl::GetTabAreaWidth() const {
-  return width() - GetNewTabButtonWidth();
-}
-
-void TabStripImpl::StartResizeLayoutAnimation() {
-  PrepareForAnimation();
-  GenerateIdealBounds();
-  AnimateToIdealBounds();
-}
-
-void TabStripImpl::StartPinnedTabAnimation() {
-  in_tab_close_ = false;
-  available_width_for_tabs_ = -1;
-
-  PrepareForAnimation();
-
-  GenerateIdealBounds();
-  AnimateToIdealBounds();
-}
-
-void TabStripImpl::StartMouseInitiatedRemoveTabAnimation(int model_index) {
-  // The user initiated the close. We want to persist the bounds of all the
-  // existing tabs, so we manually shift ideal_bounds then animate.
-  Tab* tab_closing = tab_at(model_index);
-  int delta = tab_closing->width() - Tab::GetOverlap();
-  // If the tab being closed is a pinned tab next to a non-pinned tab, be sure
-  // to add the extra padding.
-  DCHECK_LT(model_index, tab_count() - 1);
-  if (tab_closing->data().pinned && !tab_at(model_index + 1)->data().pinned)
-    delta += kPinnedToNonPinnedOffset;
-
-  // Set the ideal bounds of everything to be moved over to cover for the
-  // removed tab. This does not recompute the ideal bounds so every tab slides
-  // over without expansion until the user moves the mouse away.
-  for (int i = model_index + 1; i < tab_count(); ++i) {
-    gfx::Rect bounds = ideal_bounds(i);
-    bounds.set_x(bounds.x() - delta);
-    tabs_.set_ideal_bounds(i, bounds);
-  }
-
-  // Don't just subtract |delta| from the New Tab x-coordinate, as we might have
-  // overflow tabs that will be able to animate into the strip, in which case
-  // the new tab button should stay where it is.
-  new_tab_button_bounds_.set_x(
-      std::min(width() - new_tab_button_bounds_.width(),
-               ideal_bounds(tab_count() - 1).right() -
-                   GetLayoutConstant(TABSTRIP_NEW_TAB_BUTTON_OVERLAP)));
-
-  PrepareForAnimation();
-
-  tab_closing->set_closing(true);
-
-  // We still need to paint the tab until we actually remove it. Put it in
-  // tabs_closing_map_ so we can find it.
-  RemoveTabFromViewModel(model_index);
-
-  AnimateToIdealBounds();
-
-  gfx::Rect tab_bounds = tab_closing->bounds();
-  tab_bounds.set_width(0);
-  bounds_animator_.AnimateViewTo(tab_closing, tab_bounds);
-
-  // Register delegate to do cleanup when done.
-  bounds_animator_.SetAnimationDelegate(
-      tab_closing, std::make_unique<RemoveTabDelegate>(this, tab_closing));
-}
-
-bool TabStripImpl::IsPointInTab(Tab* tab,
-                                const gfx::Point& point_in_tabstrip_coords) {
-  gfx::Point point_in_tab_coords(point_in_tabstrip_coords);
-  View::ConvertPointToTarget(this, tab, &point_in_tab_coords);
-  return tab->HitTestPoint(point_in_tab_coords);
-}
-
-int TabStripImpl::GetStartXForNormalTabs() const {
-  int pinned_tab_count = GetPinnedTabCount();
-  if (pinned_tab_count == 0)
-    return 0;
-  return pinned_tab_count * (Tab::GetPinnedWidth() - Tab::GetOverlap()) +
-         kPinnedToNonPinnedOffset;
-}
-
-Tab* TabStripImpl::FindTabForEvent(const gfx::Point& point) {
-  DCHECK(touch_layout_);
-  int active_tab_index = touch_layout_->active_index();
-  Tab* tab = FindTabForEventFrom(point, active_tab_index, -1);
-  return tab ? tab : FindTabForEventFrom(point, active_tab_index + 1, 1);
-}
-
-Tab* TabStripImpl::FindTabForEventFrom(const gfx::Point& point,
-                                       int start,
-                                       int delta) {
-  // |start| equals tab_count() when there are only pinned tabs.
-  if (start == tab_count())
-    start += delta;
-  for (int i = start; i >= 0 && i < tab_count(); i += delta) {
-    if (IsPointInTab(tab_at(i), point))
-      return tab_at(i);
-  }
-  return NULL;
-}
-
-Tab* TabStripImpl::FindTabHitByPoint(const gfx::Point& point) {
-  // The display order doesn't necessarily match the child order, so we iterate
-  // in display order.
-  for (int i = 0; i < tab_count(); ++i) {
-    // If we don't first exclude points outside the current tab, the code below
-    // will return the wrong tab if the next tab is selected, the following tab
-    // is active, and |point| is in the overlap region between the two.
-    Tab* tab = tab_at(i);
-    if (!IsPointInTab(tab, point))
-      continue;
-
-    // Selected tabs render atop unselected ones, and active tabs render atop
-    // everything.  Check whether the next tab renders atop this one and |point|
-    // is in the overlap region.
-    Tab* next_tab = i < (tab_count() - 1) ? tab_at(i + 1) : nullptr;
-    if (next_tab &&
-        (next_tab->IsActive() ||
-         (next_tab->IsSelected() && !tab->IsSelected())) &&
-        IsPointInTab(next_tab, point))
-      return next_tab;
-
-    // This is the topmost tab for this point.
-    return tab;
-  }
-
-  return nullptr;
-}
-
-std::vector<int> TabStripImpl::GetTabXCoordinates() {
-  std::vector<int> results;
-  for (int i = 0; i < tab_count(); ++i)
-    results.push_back(ideal_bounds(i).x());
-  return results;
-}
-
-void TabStripImpl::SwapLayoutIfNecessary() {
-  bool needs_touch = NeedsTouchLayout();
-  bool using_touch = touch_layout_ != NULL;
-  if (needs_touch == using_touch)
-    return;
-
-  if (needs_touch) {
-    gfx::Size tab_size(Tab::GetTouchWidth(), GetLayoutConstant(TAB_HEIGHT));
-
-    const int overlap = Tab::GetOverlap();
-    touch_layout_.reset(new StackedTabStripLayout(
-        tab_size, overlap, kStackedPadding, kMaxStackedCount, &tabs_));
-    touch_layout_->SetWidth(GetTabAreaWidth());
-    // This has to be after SetWidth() as SetWidth() is going to reset the
-    // bounds of the pinned tabs (since StackedTabStripLayout doesn't yet know
-    // how many pinned tabs there are).
-    GenerateIdealBoundsForPinnedTabs(NULL);
-    touch_layout_->SetXAndPinnedCount(GetStartXForNormalTabs(),
-                                      GetPinnedTabCount());
-    touch_layout_->SetActiveIndex(controller_->GetActiveIndex());
-
-    base::RecordAction(UserMetricsAction("StackedTab_EnteredStackedLayout"));
-  } else {
-    touch_layout_.reset();
-  }
-  PrepareForAnimation();
-  GenerateIdealBounds();
-  SetTabVisibility();
-  AnimateToIdealBounds();
-}
-
-bool TabStripImpl::NeedsTouchLayout() const {
-  if (!stacked_layout_)
-    return false;
-
-  int pinned_tab_count = GetPinnedTabCount();
-  int normal_count = tab_count() - pinned_tab_count;
-  if (normal_count <= 1 || normal_count == pinned_tab_count)
-    return false;
-  return (Tab::GetTouchWidth() * normal_count -
-          Tab::GetOverlap() * (normal_count - 1)) >
-         GetTabAreaWidth() - GetStartXForNormalTabs();
-}
-
-void TabStripImpl::SetResetToShrinkOnExit(bool value) {
-  if (!adjust_layout_)
-    return;
-
-  if (value && !stacked_layout_)
-    value = false;  // We're already using shrink (not stacked) layout.
-
-  if (value == reset_to_shrink_on_exit_)
-    return;
-
-  reset_to_shrink_on_exit_ = value;
-  // Add an observer so we know when the mouse moves out of the tabstrip.
-  if (reset_to_shrink_on_exit_)
-    AddMessageLoopObserver();
-  else
-    RemoveMessageLoopObserver();
-}
-
-void TabStripImpl::ButtonPressed(views::Button* sender,
-                                 const ui::Event& event) {
-  if (sender == new_tab_button_) {
-    base::RecordAction(UserMetricsAction("NewTab_Button"));
-    UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_BUTTON,
-                              TabStripModel::NEW_TAB_ENUM_COUNT);
-    if (event.IsMouseEvent()) {
-      const ui::MouseEvent& mouse = static_cast<const ui::MouseEvent&>(event);
-      if (mouse.IsOnlyMiddleMouseButton()) {
-        if (ui::Clipboard::IsSupportedClipboardType(
-                ui::CLIPBOARD_TYPE_SELECTION)) {
-          ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
-          CHECK(clipboard);
-          base::string16 clipboard_text;
-          clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &clipboard_text);
-          if (!clipboard_text.empty())
-            controller_->CreateNewTabWithLocation(clipboard_text);
-        }
-        return;
-      }
-    }
-
-    controller_->CreateNewTab();
-    if (event.type() == ui::ET_GESTURE_TAP)
-      TouchUMA::RecordGestureAction(TouchUMA::GESTURE_NEWTAB_TAP);
-  }
-}
-
-// Overridden to support automation. See automation_proxy_uitest.cc.
-const views::View* TabStripImpl::GetViewByID(int view_id) const {
-  if (tab_count() > 0) {
-    if (view_id == VIEW_ID_TAB_LAST)
-      return tab_at(tab_count() - 1);
-    if ((view_id >= VIEW_ID_TAB_0) && (view_id < VIEW_ID_TAB_LAST)) {
-      int index = view_id - VIEW_ID_TAB_0;
-      return (index >= 0 && index < tab_count()) ? tab_at(index) : NULL;
-    }
-  }
-
-  return View::GetViewByID(view_id);
-}
-
-bool TabStripImpl::OnMousePressed(const ui::MouseEvent& event) {
-  UpdateStackedLayoutFromMouseEvent(this, event);
-  // We can't return true here, else clicking in an empty area won't drag the
-  // window.
-  return false;
-}
-
-bool TabStripImpl::OnMouseDragged(const ui::MouseEvent& event) {
-  ContinueDrag(this, event);
-  return true;
-}
-
-void TabStripImpl::OnMouseReleased(const ui::MouseEvent& event) {
-  EndDrag(END_DRAG_COMPLETE);
-  UpdateStackedLayoutFromMouseEvent(this, event);
-}
-
-void TabStripImpl::OnMouseCaptureLost() {
-  EndDrag(END_DRAG_CAPTURE_LOST);
-}
-
-void TabStripImpl::OnMouseMoved(const ui::MouseEvent& event) {
-  UpdateStackedLayoutFromMouseEvent(this, event);
-}
-
-void TabStripImpl::OnMouseEntered(const ui::MouseEvent& event) {
-  SetResetToShrinkOnExit(true);
-}
-
-void TabStripImpl::OnGestureEvent(ui::GestureEvent* event) {
-  SetResetToShrinkOnExit(false);
-  switch (event->type()) {
-    case ui::ET_GESTURE_SCROLL_END:
-    case ui::ET_SCROLL_FLING_START:
-    case ui::ET_GESTURE_END:
-      EndDrag(END_DRAG_COMPLETE);
-      if (adjust_layout_) {
-        SetStackedLayout(true);
-        controller_->StackedLayoutMaybeChanged();
-      }
-      break;
-
-    case ui::ET_GESTURE_LONG_PRESS:
-      if (drag_controller_.get())
-        drag_controller_->SetMoveBehavior(TabDragController::REORDER);
-      break;
-
-    case ui::ET_GESTURE_LONG_TAP: {
-      EndDrag(END_DRAG_CANCEL);
-      gfx::Point local_point = event->location();
-      Tab* tab = touch_layout_ ? FindTabForEvent(local_point)
-                               : FindTabHitByPoint(local_point);
-      if (tab) {
-        ConvertPointToScreen(this, &local_point);
-        ShowContextMenuForTab(tab, local_point, ui::MENU_SOURCE_TOUCH);
-      }
-      break;
-    }
-
-    case ui::ET_GESTURE_SCROLL_UPDATE:
-      ContinueDrag(this, *event);
-      break;
-
-    case ui::ET_GESTURE_TAP_DOWN:
-      EndDrag(END_DRAG_CANCEL);
-      break;
-
-    case ui::ET_GESTURE_TAP: {
-      const int active_index = controller_->GetActiveIndex();
-      DCHECK_NE(-1, active_index);
-      Tab* active_tab = tab_at(active_index);
-      TouchUMA::GestureActionType action = TouchUMA::GESTURE_TABNOSWITCH_TAP;
-      if (active_tab->tab_activated_with_last_tap_down())
-        action = TouchUMA::GESTURE_TABSWITCH_TAP;
-      TouchUMA::RecordGestureAction(action);
-      break;
-    }
-
-    default:
-      break;
-  }
-  event->SetHandled();
-}
-
-views::View* TabStripImpl::TargetForRect(views::View* root,
-                                         const gfx::Rect& rect) {
-  CHECK_EQ(root, this);
-
-  if (!views::UsePointBasedTargeting(rect))
-    return views::ViewTargeterDelegate::TargetForRect(root, rect);
-  const gfx::Point point(rect.CenterPoint());
-
-  if (!touch_layout_) {
-    // Return any view that isn't a Tab or this TabStrip immediately. We don't
-    // want to interfere.
-    views::View* v = views::ViewTargeterDelegate::TargetForRect(root, rect);
-    if (v && v != this && strcmp(v->GetClassName(), Tab::kViewClassName))
-      return v;
-
-    views::View* tab = FindTabHitByPoint(point);
-    if (tab)
-      return tab;
-  } else {
-    if (new_tab_button_->visible()) {
-      views::View* view =
-          ConvertPointToViewAndGetEventHandler(this, new_tab_button_, point);
-      if (view)
-        return view;
-    }
-    Tab* tab = FindTabForEvent(point);
-    if (tab)
-      return ConvertPointToViewAndGetEventHandler(this, tab, point);
-  }
-  return this;
-}
diff --git a/chrome/browser/ui/views/tabs/tab_strip_impl.h b/chrome/browser/ui/views/tabs/tab_strip_impl.h
deleted file mode 100644
index 81f3fd4..0000000
--- a/chrome/browser/ui/views/tabs/tab_strip_impl.h
+++ /dev/null
@@ -1,637 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_IMPL_H_
-#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_IMPL_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/ui/views/tabs/tab.h"
-#include "chrome/browser/ui/views/tabs/tab_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip.h"
-#include "ui/gfx/animation/animation_container.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/animation/bounds_animator.h"
-#include "ui/views/controls/button/image_button.h"
-#include "ui/views/mouse_watcher.h"
-#include "ui/views/view.h"
-#include "ui/views/view_model.h"
-#include "ui/views/view_targeter_delegate.h"
-
-class NewTabButton;
-class StackedTabStripLayout;
-class Tab;
-class TabDragController;
-class TabStripController;
-
-namespace ui {
-class ListSelectionModel;
-}
-
-namespace views {
-class ImageView;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// TabStrip
-//
-//  A View that represents the TabStripModel. The TabStrip has the
-//  following responsibilities:
-//    - It implements the TabStripModelObserver interface, and acts as a
-//      container for Tabs, and is also responsible for creating them.
-//    - It takes part in Tab Drag & Drop with Tab, TabDragHelper and
-//      DraggedTab, focusing on tasks that require reshuffling other tabs
-//      in response to dragged tabs.
-//
-///////////////////////////////////////////////////////////////////////////////
-class TabStripImpl : public TabStrip,
-                     public views::ButtonListener,
-                     public views::MouseWatcherListener,
-                     public views::ViewTargeterDelegate,
-                     public TabController {
- public:
-  explicit TabStripImpl(std::unique_ptr<TabStripController> controller);
-  ~TabStripImpl() override;
-
-  // TabStrip implementation:
-  TabStripImpl* AsTabStripImpl() override;
-  int GetMaxX() const override;
-  void SetBackgroundOffset(const gfx::Point& offset) override;
-  bool IsRectInWindowCaption(const gfx::Rect& rect) override;
-  bool IsPositionInWindowCaption(const gfx::Point& point) override;
-  bool IsTabStripCloseable() const override;
-  bool IsTabStripEditable() const override;
-  bool IsTabCrashed(int tab_index) const override;
-  bool TabHasNetworkError(int tab_index) const override;
-  TabAlertState GetTabAlertState(int tab_index) const override;
-  void UpdateLoadingAnimations() override;
-
-  // If |adjust_layout| is true the stacked layout changes based on whether the
-  // user uses a mouse or a touch device with the tabstrip.
-  void set_adjust_layout(bool adjust_layout) { adjust_layout_ = adjust_layout; }
-
-  // |stacked_layout_| defines what should happen when the tabs won't fit at
-  // their ideal size. When |stacked_layout_| is true the tabs are always sized
-  // to their ideal size and stacked on top of each other so that only a certain
-  // set of tabs are visible. This is used when the user uses a touch device.
-  // When |stacked_layout_| is false the tabs shrink to accommodate the
-  // available space. This is the default.
-  bool stacked_layout() const { return stacked_layout_; }
-
-  // Sets |stacked_layout_| and animates if necessary.
-  void SetStackedLayout(bool stacked_layout);
-
-  // Returns the bounds of the new tab button.
-  gfx::Rect GetNewTabButtonBounds();
-
-  // Returns true if the new tab button should be sized to the top of the tab
-  // strip.
-  bool SizeTabButtonToTopOfTabStrip();
-
-  // Starts highlighting the tab at the specified index.
-  void StartHighlight(int model_index);
-
-  // Stops all tab higlighting.
-  void StopAllHighlighting();
-
-  // Adds a tab at the specified index.
-  void AddTabAt(int model_index, TabRendererData data, bool is_active);
-
-  // Moves a tab.
-  void MoveTab(int from_model_index, int to_model_index, TabRendererData data);
-
-  // Removes a tab at the specified index. If the tab with |contents| is being
-  // dragged then the drag is completed.
-  void RemoveTabAt(content::WebContents* contents, int model_index);
-
-  // Sets the tab data at the specified model index.
-  void SetTabData(int model_index, TabRendererData data);
-
-  // Returns true if the tab is not partly or fully clipped (due to overflow),
-  // and the tab couldn't become partly clipped due to changing the selected tab
-  // (for example, if currently the strip has the last tab selected, and
-  // changing that to the first tab would cause |tab| to be pushed over enough
-  // to clip).
-  bool ShouldTabBeVisible(const Tab* tab) const;
-
-  // Invoked from the controller when the close initiates from the TabController
-  // (the user clicked the tab close button or middle clicked the tab). This is
-  // invoked from Close. Because of unload handlers Close is not always
-  // immediately followed by RemoveTabAt.
-  void PrepareForCloseAt(int model_index, CloseTabSource source);
-
-  // Invoked when the selection changes from |old_selection| to
-  // |new_selection|.
-  void SetSelection(const ui::ListSelectionModel& old_selection,
-                    const ui::ListSelectionModel& new_selection);
-
-  // Invoked when the title of a tab changes and the tab isn't loading. This is
-  // used by pinned tabs to indicate they need attention.
-  void TabTitleChangedNotLoading(int model_index);
-
-  // Invoked when a tab needs to show UI that it needs the user's attention.
-  void SetTabNeedsAttention(int model_index, bool attention);
-
-  // Retrieves the ideal bounds for the Tab at the specified index.
-  const gfx::Rect& ideal_bounds(int tab_data_index) {
-    return tabs_.ideal_bounds(tab_data_index);
-  }
-
-  // Returns the Tab at |index|.
-  Tab* tab_at(int index) const { return tabs_.view_at(index); }
-
-  // Returns the NewTabButton.
-  NewTabButton* new_tab_button() { return new_tab_button_; }
-
-  // Returns the index of the specified tab in the model coordinate system, or
-  // -1 if tab is closing or not valid.
-  int GetModelIndexOfTab(const Tab* tab) const;
-
-  // Gets the number of Tabs in the tab strip.
-  int tab_count() const { return tabs_.view_size(); }
-
-  // Cover method for TabStripController::GetCount.
-  int GetModelCount() const;
-
-  // Cover method for TabStripController::IsValidIndex.
-  bool IsValidModelIndex(int model_index) const;
-
-  TabStripController* controller() const { return controller_.get(); }
-
-  // Returns true if a drag session is currently active.
-  bool IsDragSessionActive() const;
-
-  // Returns true if a tab is being dragged into this tab strip.
-  bool IsActiveDropTarget() const;
-
-  // Returns the alpha that inactive tabs and the new tab button should use to
-  // blend against the frame background.  Inactive tabs and the new tab button
-  // differ in whether they change alpha when tab multiselection is occurring;
-  // |for_new_tab_button| toggles between the two calculations.
-  SkAlpha GetInactiveAlpha(bool for_new_tab_button) const;
-
-  // Returns true if Tabs in this TabStrip are currently changing size or
-  // position.
-  bool IsAnimating() const;
-
-  // Stops any ongoing animations. If |layout| is true and an animation is
-  // ongoing this does a layout.
-  void StopAnimating(bool layout);
-
-  // Called to indicate whether the given URL is a supported file.
-  void FileSupported(const GURL& url, bool supported);
-
-  // TabController overrides:
-  const ui::ListSelectionModel& GetSelectionModel() const override;
-  bool SupportsMultipleSelection() override;
-  bool ShouldHideCloseButtonForInactiveTabs() override;
-  bool MaySetClip() override;
-  void SelectTab(Tab* tab) override;
-  void ExtendSelectionTo(Tab* tab) override;
-  void ToggleSelected(Tab* tab) override;
-  void AddSelectionFromAnchorTo(Tab* tab) override;
-  void CloseTab(Tab* tab, CloseTabSource source) override;
-  void ToggleTabAudioMute(Tab* tab) override;
-  void ShowContextMenuForTab(Tab* tab,
-                             const gfx::Point& p,
-                             ui::MenuSourceType source_type) override;
-  bool IsActiveTab(const Tab* tab) const override;
-  bool IsTabSelected(const Tab* tab) const override;
-  bool IsTabPinned(const Tab* tab) const override;
-  void MaybeStartDrag(
-      Tab* tab,
-      const ui::LocatedEvent& event,
-      const ui::ListSelectionModel& original_selection) override;
-  void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override;
-  bool EndDrag(EndDragReason reason) override;
-  Tab* GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) override;
-  void OnMouseEventInTab(views::View* source,
-                         const ui::MouseEvent& event) override;
-  bool ShouldPaintTab(
-      const Tab* tab,
-      const base::Callback<gfx::Path(const gfx::Size&)>& border_callback,
-      gfx::Path* clip) override;
-  bool CanPaintThrobberToLayer() const override;
-  SkColor GetToolbarTopSeparatorColor() const override;
-  base::string16 GetAccessibleTabName(const Tab* tab) const override;
-  int GetBackgroundResourceId(bool* custom_image) const override;
-
-  // MouseWatcherListener overrides:
-  void MouseMovedOutOfHost() override;
-
-  // views::View overrides:
-  void Layout() override;
-  void PaintChildren(const views::PaintInfo& paint_info) override;
-  const char* GetClassName() const override;
-  gfx::Size CalculatePreferredSize() const override;
-  // NOTE: the drag and drop methods are invoked from FrameView. This is done
-  // to allow for a drop region that extends outside the bounds of the TabStrip.
-  void OnDragEntered(const ui::DropTargetEvent& event) override;
-  int OnDragUpdated(const ui::DropTargetEvent& event) override;
-  void OnDragExited() override;
-  int OnPerformDrop(const ui::DropTargetEvent& event) override;
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
-
- private:
-  using Tabs = std::vector<Tab*>;
-  using TabsClosingMap = std::map<int, Tabs>;
-  using FindClosingTabResult =
-      std::pair<TabsClosingMap::iterator, Tabs::iterator>;
-
-  class RemoveTabDelegate;
-
-  friend class TabDragController;
-  friend class TabDragControllerTest;
-  friend class TabStripTest;
-  FRIEND_TEST_ALL_PREFIXES(TabDragControllerTest, GestureEndShouldEndDragTest);
-  FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabForEventWhenStacked);
-  FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabCloseButtonVisibilityWhenStacked);
-
-  // Used during a drop session of a url. Tracks the position of the drop as
-  // well as a window used to highlight where the drop occurs.
-  struct DropInfo {
-    DropInfo(int drop_index,
-             bool drop_before,
-             bool point_down,
-             views::Widget* context);
-    ~DropInfo();
-
-    // Index of the tab to drop on. If drop_before is true, the drop should
-    // occur between the tab at drop_index - 1 and drop_index.
-    // WARNING: if drop_before is true it is possible this will == tab_count,
-    // which indicates the drop should create a new tab at the end of the tabs.
-    int drop_index;
-    bool drop_before;
-
-    // Direction the arrow should point in. If true, the arrow is displayed
-    // above the tab and points down. If false, the arrow is displayed beneath
-    // the tab and points up.
-    bool point_down;
-
-    // Renders the drop indicator.
-    views::Widget* arrow_window;
-    views::ImageView* arrow_view;
-
-    // The URL for the drop event.
-    GURL url;
-
-    // Whether the MIME type of the file pointed to by |url| is supported.
-    bool file_supported;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(DropInfo);
-  };
-
-  void Init();
-
-  // Invoked from |AddTabAt| after the newly created tab has been inserted.
-  void StartInsertTabAnimation(int model_index);
-
-  // Invoked from |MoveTab| after |tab_data_| has been updated to animate the
-  // move.
-  void StartMoveTabAnimation();
-
-  // Starts the remove tab animation.
-  void StartRemoveTabAnimation(int model_index);
-
-  // Schedules the animations and bounds changes necessary for a remove tab
-  // animation.
-  void ScheduleRemoveTabAnimation(Tab* tab);
-
-  // Animates all the views to their ideal bounds.
-  // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds
-  // currently set in ideal_bounds.
-  void AnimateToIdealBounds();
-
-  // Returns whether the highlight button should be highlighted after a remove.
-  bool ShouldHighlightCloseButtonAfterRemove();
-
-  // Returns whether the window background behind the tabstrip is transparent.
-  bool TitlebarBackgroundIsTransparent() const;
-
-  // Invoked from Layout if the size changes or layout is really needed.
-  void DoLayout();
-
-  // Sets the visibility state of all tabs based on ShouldTabBeVisible().
-  void SetTabVisibility();
-
-  // Drags the active tab by |delta|. |initial_positions| is the x-coordinates
-  // of the tabs when the drag started.
-  void DragActiveTab(const std::vector<int>& initial_positions, int delta);
-
-  // Sets the ideal bounds x-coordinates to |positions|.
-  void SetIdealBoundsFromPositions(const std::vector<int>& positions);
-
-  // Stacks the dragged tabs. This is used if the drag operation is
-  // MOVE_VISIBLE_TABS and the tabs don't fill the tabstrip. When this happens
-  // the active tab follows the mouse and the other tabs stack around it.
-  void StackDraggedTabs(int delta);
-
-  // Returns true if dragging has resulted in temporarily stacking the tabs.
-  bool IsStackingDraggedTabs() const;
-
-  // Invoked during drag to layout the tabs being dragged in |tabs| at
-  // |location|. If |initial_drag| is true, this is the initial layout after the
-  // user moved the mouse far enough to trigger a drag.
-  void LayoutDraggedTabsAt(const Tabs& tabs,
-                           Tab* active_tab,
-                           const gfx::Point& location,
-                           bool initial_drag);
-
-  // Calculates the bounds needed for each of the tabs, placing the result in
-  // |bounds|.
-  void CalculateBoundsForDraggedTabs(const Tabs& tabs,
-                                     std::vector<gfx::Rect>* bounds);
-
-  // Returns the size needed for the specified tabs. This is invoked during drag
-  // and drop to calculate offsets and positioning.
-  int GetSizeNeededForTabs(const Tabs& tabs);
-
-  // Returns the number of pinned tabs.
-  int GetPinnedTabCount() const;
-
-  // Returns the last tab in the strip that's actually visible.  This will be
-  // the actual last tab unless the strip is in the overflow node_data.
-  const Tab* GetLastVisibleTab() const;
-
-  // Adds the tab at |index| to |tabs_closing_map_| and removes the tab from
-  // |tabs_|.
-  void RemoveTabFromViewModel(int index);
-
-  // Cleans up the Tab from the TabStrip. This is called from the tab animation
-  // code and is not a general-purpose method.
-  void RemoveAndDeleteTab(Tab* tab);
-
-  // Adjusts the indices of all tabs in |tabs_closing_map_| whose index is
-  // >= |index| to have a new index of |index + delta|.
-  void UpdateTabsClosingMap(int index, int delta);
-
-  // Used by TabDragController when the user starts or stops dragging tabs.
-  void StartedDraggingTabs(const Tabs& tabs);
-
-  // Invoked when TabDragController detaches a set of tabs.
-  void DraggedTabsDetached();
-
-  // Used by TabDragController when the user stops dragging tabs. |move_only| is
-  // true if the move behavior is TabDragController::MOVE_VISIBLE_TABS.
-  // |completed| is true if the drag operation completed successfully, false if
-  // it was reverted.
-  void StoppedDraggingTabs(const Tabs& tabs,
-                           const std::vector<int>& initial_positions,
-                           bool move_only,
-                           bool completed);
-
-  // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
-  // |is_first_tab| is set to true.
-  void StoppedDraggingTab(Tab* tab, bool* is_first_tab);
-
-  // Takes ownership of |controller|.
-  void OwnDragController(TabDragController* controller);
-
-  // Destroys the current TabDragController. This cancel the existing drag
-  // operation.
-  void DestroyDragController();
-
-  // Releases ownership of the current TabDragController.
-  TabDragController* ReleaseDragController();
-
-  // Finds |tab| in the |tab_closing_map_| and returns a pair of iterators
-  // indicating precisely where it is.
-  FindClosingTabResult FindClosingTab(const Tab* tab);
-
-  // Paints all the tabs in |tabs_closing_map_[index]|.
-  void PaintClosingTabs(int index, const views::PaintInfo& paint_info);
-
-  // Invoked when a mouse event occurs over |source|. Potentially switches the
-  // |stacked_layout_|.
-  void UpdateStackedLayoutFromMouseEvent(views::View* source,
-                                         const ui::MouseEvent& event);
-
-  // -- Tab Resize Layout -----------------------------------------------------
-
-  // Returns the current width of each tab. If the space for tabs is not evenly
-  // divisible into these widths, the initial tabs in the strip will be 1 px
-  // larger.
-  int current_inactive_width() const { return current_inactive_width_; }
-  int current_active_width() const { return current_active_width_; }
-
-  // Perform an animated resize-relayout of the TabStrip immediately.
-  void ResizeLayoutTabs();
-
-  // Invokes ResizeLayoutTabs() as long as we're not in a drag session. If we
-  // are in a drag session this restarts the timer.
-  void ResizeLayoutTabsFromTouch();
-
-  // Restarts |resize_layout_timer_|.
-  void StartResizeLayoutTabsFromTouchTimer();
-
-  // Sets the bounds of the tabs to |tab_bounds|.
-  void SetTabBoundsForDrag(const std::vector<gfx::Rect>& tab_bounds);
-
-  // Ensure that the message loop observer used for event spying is added and
-  // removed appropriately so we can tell when to resize layout the tab strip.
-  void AddMessageLoopObserver();
-  void RemoveMessageLoopObserver();
-
-  // -- Link Drag & Drop ------------------------------------------------------
-
-  // Returns the bounds to render the drop at, in screen coordinates. Sets
-  // |is_beneath| to indicate whether the arrow is beneath the tab, or above
-  // it.
-  gfx::Rect GetDropBounds(int drop_index, bool drop_before, bool* is_beneath);
-
-  // Updates the location of the drop based on the event.
-  void UpdateDropIndex(const ui::DropTargetEvent& event);
-
-  // Sets the location of the drop, repainting as necessary.
-  void SetDropIndex(int tab_data_index, bool drop_before);
-
-  // Returns the drop effect for dropping a URL on the tab strip. This does
-  // not query the data in anyway, it only looks at the source operations.
-  int GetDropEffect(const ui::DropTargetEvent& event);
-
-  // Returns the image to use for indicating a drop on a tab. If is_down is
-  // true, this returns an arrow pointing down.
-  static gfx::ImageSkia* GetDropArrowImage(bool is_down);
-
-  // -- Animations ------------------------------------------------------------
-
-  // Invoked prior to starting a new animation.
-  void PrepareForAnimation();
-
-  // Generates the ideal bounds for each of the tabs as well as the new tab
-  // button.
-  void GenerateIdealBounds();
-
-  // Generates the ideal bounds for the pinned tabs. Returns the index to
-  // position the first non-pinned tab and sets |first_non_pinned_index| to the
-  // index of the first non-pinned tab.
-  int GenerateIdealBoundsForPinnedTabs(int* first_non_pinned_index);
-
-  // Returns the width of the area that contains tabs. This does not include
-  // the width of the new tab button.
-  int GetTabAreaWidth() const;
-
-  // Starts various types of TabStrip animations.
-  void StartResizeLayoutAnimation();
-  void StartPinnedTabAnimation();
-  void StartMouseInitiatedRemoveTabAnimation(int model_index);
-
-  // Returns true if the specified point in TabStrip coords is within the
-  // hit-test region of the specified Tab.
-  bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords);
-
-  // -- Touch Layout ----------------------------------------------------------
-
-  // Returns the position normal tabs start at.
-  int GetStartXForNormalTabs() const;
-
-  // Returns the tab to use for event handling. This uses FindTabForEventFrom()
-  // to do the actual searching.  This method should be called when
-  // |touch_layout_| is set.
-  Tab* FindTabForEvent(const gfx::Point& point);
-
-  // Helper for FindTabForEvent().  Returns the tab to use for event handling
-  // starting at index |start| and iterating by |delta|.
-  Tab* FindTabForEventFrom(const gfx::Point& point, int start, int delta);
-
-  // For a given point, finds a tab that is hit by the point. If the point hits
-  // an area on which two tabs are overlapping, the tab is selected as follows:
-  // - If one of the tabs is active, select it.
-  // - Select the left one.
-  // If no tabs are hit, returns null.  This method should be called when
-  // |touch_layout_| is not set.
-  Tab* FindTabHitByPoint(const gfx::Point& point);
-
-  // Returns the x-coordinates of the tabs.
-  std::vector<int> GetTabXCoordinates();
-
-  // Creates/Destroys |touch_layout_| as necessary.
-  void SwapLayoutIfNecessary();
-
-  // Returns true if |touch_layout_| is needed.
-  bool NeedsTouchLayout() const;
-
-  // Sets the value of |reset_to_shrink_on_exit_|. If true |mouse_watcher_| is
-  // used to track when the mouse truly exits the tabstrip and the stacked
-  // layout is reset.
-  void SetResetToShrinkOnExit(bool value);
-
-  // views::ButtonListener implementation:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
-  // View overrides.
-  const views::View* GetViewByID(int id) const override;
-  bool OnMousePressed(const ui::MouseEvent& event) override;
-  bool OnMouseDragged(const ui::MouseEvent& event) override;
-  void OnMouseReleased(const ui::MouseEvent& event) override;
-  void OnMouseCaptureLost() override;
-  void OnMouseMoved(const ui::MouseEvent& event) override;
-  void OnMouseEntered(const ui::MouseEvent& event) override;
-
-  // ui::EventHandler overrides.
-  void OnGestureEvent(ui::GestureEvent* event) override;
-
-  // views::ViewTargeterDelegate:
-  views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
-
-  // -- Member Variables ------------------------------------------------------
-
-  // There is a one-to-one mapping between each of the tabs in the
-  // TabStripController (TabStripModel) and |tabs_|. Because we animate tab
-  // removal there exists a period of time where a tab is displayed but not in
-  // the model. When this occurs the tab is removed from |tabs_| and placed in
-  // |tabs_closing_map_|. When the animation completes the tab is removed from
-  // |tabs_closing_map_|. The painting code ensures both sets of tabs are
-  // painted, and the event handling code ensures only tabs in |tabs_| are used.
-  views::ViewModelT<Tab> tabs_;
-  TabsClosingMap tabs_closing_map_;
-
-  std::unique_ptr<TabStripController> controller_;
-
-  // The "New Tab" button.
-  NewTabButton* new_tab_button_ = nullptr;
-
-  // Ideal bounds of the new tab button.
-  gfx::Rect new_tab_button_bounds_;
-
-  // Returns the current widths of each type of tab.  If the tabstrip width is
-  // not evenly divisible into these widths, the initial tabs in the strip will
-  // be 1 px larger.
-  int current_inactive_width_;
-  int current_active_width_;
-
-  // If this value is nonnegative, it is used as the width to lay out tabs
-  // (instead of tab_area_width()). Most of the time this will be -1, but while
-  // we're handling closing a tab via the mouse, we'll set this to the edge of
-  // the last tab before closing, so that if we are closing the last tab and
-  // need to resize immediately, we'll resize only back to this width, thus
-  // once again placing the last tab under the mouse cursor.
-  int available_width_for_tabs_ = -1;
-
-  // True if PrepareForCloseAt has been invoked. When true remove animations
-  // preserve current tab bounds.
-  bool in_tab_close_ = false;
-
-  // Valid for the lifetime of a drag over us.
-  std::unique_ptr<DropInfo> drop_info_;
-
-  // To ensure all tabs pulse at the same time they share the same animation
-  // container. This is that animation container.
-  scoped_refptr<gfx::AnimationContainer> animation_container_;
-
-  // MouseWatcher is used for two things:
-  // . When a tab is closed to reset the layout.
-  // . When a mouse is used and the layout dynamically adjusts and is currently
-  //   stacked (|stacked_layout_| is true).
-  std::unique_ptr<views::MouseWatcher> mouse_watcher_;
-
-  // The controller for a drag initiated from a Tab. Valid for the lifetime of
-  // the drag session.
-  std::unique_ptr<TabDragController> drag_controller_;
-
-  views::BoundsAnimator bounds_animator_;
-
-  // Size we last layed out at.
-  gfx::Size last_layout_size_;
-
-  // See description above stacked_layout().
-  bool stacked_layout_ = false;
-
-  // Should the layout dynamically adjust?
-  bool adjust_layout_ = false;
-
-  // Only used while in touch mode.
-  std::unique_ptr<StackedTabStripLayout> touch_layout_;
-
-  // If true the |stacked_layout_| is set to false when the mouse exits the
-  // tabstrip (as determined using MouseWatcher).
-  bool reset_to_shrink_on_exit_ = false;
-
-  // Location of the mouse at the time of the last move.
-  gfx::Point last_mouse_move_location_;
-
-  // Time of the last mouse move event.
-  base::TimeTicks last_mouse_move_time_;
-
-  // Number of mouse moves.
-  int mouse_move_count_ = 0;
-
-  // Timer used when a tab is closed and we need to relayout. Only used when a
-  // tab close comes from a touch device.
-  base::OneShotTimer resize_layout_timer_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabStripImpl);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STRIP_IMPL_H_
diff --git a/chrome/browser/ui/views/tabs/tab_strip_impl_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_impl_unittest.cc
index f60a17db..b663b8d 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_impl_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_impl_unittest.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_icon.h"
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
+#include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
-#include "chrome/browser/ui/views/tabs/tab_strip_impl.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -99,8 +99,7 @@
     views::ViewsTestBase::SetUp();
 
     controller_ = new FakeBaseTabStripController;
-    tab_strip_ =
-        new TabStripImpl(std::unique_ptr<TabStripController>(controller_));
+    tab_strip_ = new TabStrip(std::unique_ptr<TabStripController>(controller_));
     controller_->set_tab_strip(tab_strip_);
     // Do this to force TabStrip to create the buttons.
     parent_.AddChildView(tab_strip_);
@@ -140,7 +139,7 @@
   FakeBaseTabStripController* controller_ = nullptr;
   // Owns |tab_strip_|.
   views::View parent_;
-  TabStripImpl* tab_strip_ = nullptr;
+  TabStrip* tab_strip_ = nullptr;
   std::unique_ptr<views::Widget> widget_;
 
  private:
@@ -171,8 +170,8 @@
 // Confirms that TabStripObserver::TabStripDeleted() is sent.
 TEST_F(TabStripTest, TabStripDeleted) {
   FakeBaseTabStripController* controller = new FakeBaseTabStripController;
-  std::unique_ptr<TabStripImpl> tab_strip(
-      new TabStripImpl(std::unique_ptr<TabStripController>(controller)));
+  std::unique_ptr<TabStrip> tab_strip(
+      new TabStrip(std::unique_ptr<TabStripController>(controller)));
   controller->set_tab_strip(tab_strip.get());
   TestTabStripObserver observer(tab_strip.get());
   tab_strip.reset();
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index becd94fe..0064fc02 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -663,7 +663,7 @@
     "cache_stats_recorder.mojom",
     "chrome_render_frame.mojom",
     "constants.mojom",
-    "insecure_content_renderer.mojom",
+    "content_settings_renderer.mojom",
     "navigation_corrector.mojom",
     "net_benchmarking.mojom",
     "network_diagnostics.mojom",
diff --git a/chrome/common/content_settings_renderer.mojom b/chrome/common/content_settings_renderer.mojom
new file mode 100644
index 0000000..a8f7704
--- /dev/null
+++ b/chrome/common/content_settings_renderer.mojom
@@ -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.
+
+module chrome.mojom;
+
+// Tells the renderer that it is displaying an interstitial page.
+interface ContentSettingsRenderer {
+  // Sent to allow the running of insecure mixed-content. If received by the
+  // main frame, it will also reload the frame afterwards.
+  SetAllowRunningInsecureContent();
+
+  // Message sent from the browser to the render to inform the renderer
+  // that it is displaying interstitial page.
+  SetAsInterstitial();
+};
diff --git a/chrome/common/insecure_content_renderer.mojom b/chrome/common/insecure_content_renderer.mojom
deleted file mode 100644
index 6f1efee..0000000
--- a/chrome/common/insecure_content_renderer.mojom
+++ /dev/null
@@ -1,12 +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.
-
-module chrome.mojom;
-
-// Renderers of possibly insecure mixed-content.
-interface InsecureContentRenderer {
-  // Sent to allow the running of insecure mixed-content. If received by the
-  // main frame, it will also reload the frame afterwards.
-  SetAllowRunningInsecureContent();
-};
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index b8b1279..770ac69 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -68,9 +68,6 @@
 
 // JavaScript related messages -----------------------------------------------
 
-// Tells the frame it is displaying an interstitial page.
-IPC_MESSAGE_ROUTED0(ChromeViewMsg_SetAsInterstitial)
-
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 // Message sent from the renderer to the browser to schedule to download the
 // page at a later time.
diff --git a/chrome/installer/zucchini/address_translator_unittest.cc b/chrome/installer/zucchini/address_translator_unittest.cc
index baacf347..53e19ed 100644
--- a/chrome/installer/zucchini/address_translator_unittest.cc
+++ b/chrome/installer/zucchini/address_translator_unittest.cc
@@ -5,10 +5,11 @@
 #include "chrome/installer/zucchini/address_translator.h"
 
 #include <algorithm>
-#include <sstream>
 #include <string>
 #include <utility>
 
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace zucchini {
@@ -93,11 +94,11 @@
     for (size_t i = 0; i < test_cases.size(); ++i) {
       const auto& test_case = test_cases[i];
       const std::string& unit_str2 = test_case.unit_str;
-      std::ostringstream oss;
-      oss << "Case #" << i << ": " << unit_str2;
-      SimpleTest({unit_str1, unit_str2}, test_case.expected, oss.str());
+      const std::string str =
+          base::StringPrintf("Case #%" PRIuS ": %s", i, unit_str2.c_str());
+      SimpleTest({unit_str1, unit_str2}, test_case.expected, str);
       // Switch order. Expect same results.
-      SimpleTest({unit_str2, unit_str1}, test_case.expected, oss.str());
+      SimpleTest({unit_str2, unit_str1}, test_case.expected, str);
     }
   }
 };
@@ -377,9 +378,8 @@
         std::string(test_case.offset_str) + "|" + test_case.rva_str;
     std::string unit_str1 = to_period(to_period(base_str, 'S'), 's');
     std::string unit_str2 = to_period(to_period(base_str, 'F'), 'f');
-    std::ostringstream oss;
-    oss << "Case #" << idx;
-    SimpleTest({unit_str1, unit_str2}, test_case.expected, oss.str());
+    SimpleTest({unit_str1, unit_str2}, test_case.expected,
+               base::StringPrintf("Case #%" PRIuS, idx));
     ++idx;
   }
 }
diff --git a/chrome/installer/zucchini/encoded_view.cc b/chrome/installer/zucchini/encoded_view.cc
index 5c2ea224..8dfc9573 100644
--- a/chrome/installer/zucchini/encoded_view.cc
+++ b/chrome/installer/zucchini/encoded_view.cc
@@ -5,13 +5,14 @@
 #include "chrome/installer/zucchini/encoded_view.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/logging.h"
 
 namespace zucchini {
 
 EncodedView::EncodedView(const ImageIndex& image_index)
-    : image_index_(image_index) {}
+    : image_index_(image_index), pool_infos_(image_index.PoolCount()) {}
 EncodedView::~EncodedView() = default;
 
 EncodedView::value_type EncodedView::Projection(offset_t location) const {
@@ -38,17 +39,16 @@
     return kReferencePaddingProjection;
   }
 
-  const TargetPool& target_pool = ref_set.target_pool();
+  PoolTag pool_tag = ref_set.pool_tag();
 
   // Targets with an associated Label will use its Label index in projection.
-  // Otherwise, LabelBound() is used for all targets with no Label.
-  offset_t offset = target_pool.OffsetForKey(ref.target_key);
-  value_type target =
-      IsMarked(offset) ? UnmarkIndex(offset) : target_pool.label_bound();
+  DCHECK_EQ(image_index_.pool(pool_tag).size(),
+            pool_infos_[pool_tag.value()].labels.size());
+  uint32_t label = pool_infos_[pool_tag.value()].labels[ref.target_key];
 
   // Projection is done on (|target|, |type|), shifted by
   // kBaseReferenceProjection to avoid collisions with raw content.
-  value_type projection = target;
+  value_type projection = label;
   projection *= image_index_.TypeCount();
   projection += type.value();
   return projection + kBaseReferenceProjection;
@@ -56,12 +56,22 @@
 
 size_t EncodedView::Cardinality() const {
   size_t max_width = 0;
-  for (const auto& target_pool : image_index_.target_pools()) {
-    // TODO(etiennep): Remove "+ 1" after refactoring.
-    // label_bound() + 1 for the extra case of references with no Label.
-    max_width = std::max(target_pool.second.label_bound() + 1, max_width);
-  }
+  for (const auto& pool_info : pool_infos_)
+    max_width = std::max(max_width, pool_info.bound);
   return max_width * image_index_.TypeCount() + kBaseReferenceProjection;
 }
 
+void EncodedView::SetLabels(PoolTag pool,
+                            std::vector<uint32_t>&& labels,
+                            size_t bound) {
+  DCHECK_EQ(labels.size(), image_index_.pool(pool).size());
+  DCHECK(labels.empty() || *max_element(labels.begin(), labels.end()) < bound);
+  pool_infos_[pool.value()].labels = std::move(labels);
+  pool_infos_[pool.value()].bound = bound;
+}
+
+EncodedView::PoolInfo::PoolInfo() = default;
+EncodedView::PoolInfo::PoolInfo(PoolInfo&&) = default;
+EncodedView::PoolInfo::~PoolInfo() = default;
+
 }  // namespace zucchini
diff --git a/chrome/installer/zucchini/encoded_view.h b/chrome/installer/zucchini/encoded_view.h
index 25726469..de0a3cf 100644
--- a/chrome/installer/zucchini/encoded_view.h
+++ b/chrome/installer/zucchini/encoded_view.h
@@ -9,6 +9,7 @@
 #include <stdint.h>
 
 #include <iterator>
+#include <vector>
 
 #include "base/macros.h"
 #include "chrome/installer/zucchini/image_index.h"
@@ -145,6 +146,9 @@
   // values returned by Projection().
   value_type Cardinality() const;
 
+  // Associates |labels| to targets for a given |pool|, replacing previous
+  // association. Values in |labels| must be smaller than |bound|.
+  void SetLabels(PoolTag pool, std::vector<uint32_t>&& labels, size_t bound);
   const ImageIndex& image_index() const { return image_index_; }
 
   // Range functions.
@@ -157,7 +161,18 @@
   }
 
  private:
+  struct PoolInfo {
+    PoolInfo();
+    PoolInfo(PoolInfo&&);
+    ~PoolInfo();
+
+    // |labels| translates IndirectReference target_key to label.
+    std::vector<uint32_t> labels;
+    size_t bound = 0;
+  };
+
   const ImageIndex& image_index_;
+  std::vector<PoolInfo> pool_infos_;
 
   DISALLOW_COPY_AND_ASSIGN(EncodedView);
 };
diff --git a/chrome/installer/zucchini/encoded_view_unittest.cc b/chrome/installer/zucchini/encoded_view_unittest.cc
index 4717010..6255da753 100644
--- a/chrome/installer/zucchini/encoded_view_unittest.cc
+++ b/chrome/installer/zucchini/encoded_view_unittest.cc
@@ -139,6 +139,9 @@
 TEST_F(EncodedViewTest, Unlabeled) {
   EncodedView encoded_view(image_index_);
 
+  encoded_view.SetLabels(PoolTag(0), {0, 0, 0, 0}, 1);
+  encoded_view.SetLabels(PoolTag(1), {0, 0}, 1);
+
   std::vector<size_t> expected = {
       0,                                     // raw
       kBaseReferenceProjection + 0 + 0 * 3,  // ref 0
@@ -168,9 +171,8 @@
 TEST_F(EncodedViewTest, Labeled) {
   EncodedView encoded_view(image_index_);
 
-  OrderedLabelManager label_manager0;
-  label_manager0.InsertOffsets({0, 2});
-  image_index_.LabelTargets(PoolTag(0), label_manager0);
+  encoded_view.SetLabels(PoolTag(0), {0, 2, 1, 2}, 3);
+  encoded_view.SetLabels(PoolTag(1), {0, 0}, 1);
 
   std::vector<size_t> expected = {
       0,                                     // raw
diff --git a/chrome/installer/zucchini/equivalence_map.cc b/chrome/installer/zucchini/equivalence_map.cc
index fb9ad26..da585ea4 100644
--- a/chrome/installer/zucchini/equivalence_map.cc
+++ b/chrome/installer/zucchini/equivalence_map.cc
@@ -14,10 +14,12 @@
 
 /******** Utility Functions ********/
 
-double GetTokenSimilarity(const ImageIndex& old_image_index,
-                          const ImageIndex& new_image_index,
-                          offset_t src,
-                          offset_t dst) {
+double GetTokenSimilarity(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    offset_t src,
+    offset_t dst) {
   DCHECK(old_image_index.IsToken(src));
   DCHECK(new_image_index.IsToken(dst));
 
@@ -37,23 +39,24 @@
   const ReferenceSet& new_ref_set = new_image_index.refs(new_type);
   IndirectReference old_reference = old_ref_set.at(src);
   IndirectReference new_reference = new_ref_set.at(dst);
+  PoolTag pool_tag = old_ref_set.pool_tag();
 
-  offset_t old_target =
-      old_ref_set.target_pool().OffsetForKey(old_reference.target_key);
-  offset_t new_target =
-      new_ref_set.target_pool().OffsetForKey(new_reference.target_key);
+  double affinity = targets_affinities[pool_tag.value()].AffinityBetween(
+      old_reference.target_key, new_reference.target_key);
 
   // Both targets are not associated, which implies a weak match.
-  if (!IsMarked(old_target) && !IsMarked(new_target))
+  if (affinity == 0.0)
     return 0.5 * old_ref_set.width();
 
   // At least one target is associated, so values are compared.
-  return old_target == new_target ? old_ref_set.width() : -2.0;
+  return affinity > 0.0 ? old_ref_set.width() : -2.0;
 }
 
-double GetEquivalenceSimilarity(const ImageIndex& old_image_index,
-                                const ImageIndex& new_image_index,
-                                const Equivalence& equivalence) {
+double GetEquivalenceSimilarity(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    const Equivalence& equivalence) {
   double similarity = 0.0;
   for (offset_t k = 0; k < equivalence.length; ++k) {
     // Non-tokens are joined with the nearest previous token: skip until we
@@ -61,9 +64,9 @@
     if (!new_image_index.IsToken(equivalence.dst_offset + k))
       continue;
 
-    similarity += GetTokenSimilarity(old_image_index, new_image_index,
-                                     equivalence.src_offset + k,
-                                     equivalence.dst_offset + k);
+    similarity += GetTokenSimilarity(
+        old_image_index, new_image_index, targets_affinities,
+        equivalence.src_offset + k, equivalence.dst_offset + k);
     if (similarity == kMismatchFatal)
       return kMismatchFatal;
   }
@@ -73,6 +76,7 @@
 EquivalenceCandidate ExtendEquivalenceForward(
     const ImageIndex& old_image_index,
     const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
     const EquivalenceCandidate& candidate,
     double min_similarity) {
   Equivalence equivalence = candidate.eq;
@@ -98,9 +102,9 @@
       continue;
     }
 
-    double similarity = GetTokenSimilarity(old_image_index, new_image_index,
-                                           equivalence.src_offset + k,
-                                           equivalence.dst_offset + k);
+    double similarity = GetTokenSimilarity(
+        old_image_index, new_image_index, targets_affinities,
+        equivalence.src_offset + k, equivalence.dst_offset + k);
     current_similarity += similarity;
     current_penalty = std::max(0.0, current_penalty) - similarity;
 
@@ -118,6 +122,7 @@
 EquivalenceCandidate ExtendEquivalenceBackward(
     const ImageIndex& old_image_index,
     const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
     const EquivalenceCandidate& candidate,
     double min_similarity) {
   Equivalence equivalence = candidate.eq;
@@ -141,9 +146,10 @@
     DCHECK_EQ(old_image_index.LookupType(equivalence.src_offset - k),
               new_image_index.LookupType(equivalence.dst_offset -
                                          k));  // Sanity check.
-    double similarity = GetTokenSimilarity(old_image_index, new_image_index,
-                                           equivalence.src_offset - k,
-                                           equivalence.dst_offset - k);
+    double similarity = GetTokenSimilarity(
+        old_image_index, new_image_index, targets_affinities,
+        equivalence.src_offset - k, equivalence.dst_offset - k);
+
     current_similarity += similarity;
     current_penalty = std::max(0.0, current_penalty) - similarity;
 
@@ -161,17 +167,23 @@
   return {equivalence, best_similarity};
 }
 
-EquivalenceCandidate VisitEquivalenceSeed(const ImageIndex& old_image_index,
-                                          const ImageIndex& new_image_index,
-                                          offset_t src,
-                                          offset_t dst,
-                                          double min_similarity) {
+EquivalenceCandidate VisitEquivalenceSeed(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    offset_t src,
+    offset_t dst,
+    double min_similarity) {
   EquivalenceCandidate candidate{{src, dst, 0}, 0.0};  // Empty.
-  candidate = ExtendEquivalenceForward(old_image_index, new_image_index,
-                                       candidate, min_similarity);
+  if (!old_image_index.IsToken(src))
+    return candidate;
+  candidate =
+      ExtendEquivalenceForward(old_image_index, new_image_index,
+                               targets_affinities, candidate, min_similarity);
   if (candidate.similarity < min_similarity)
     return candidate;  // Not worth exploring any more.
-  return ExtendEquivalenceBackward(old_image_index, new_image_index, candidate,
+  return ExtendEquivalenceBackward(old_image_index, new_image_index,
+                                   targets_affinities, candidate,
                                    min_similarity);
 }
 
@@ -189,15 +201,18 @@
 
 EquivalenceMap::~EquivalenceMap() = default;
 
-void EquivalenceMap::Build(const std::vector<offset_t>& old_sa,
-                           const EncodedView& old_view,
-                           const EncodedView& new_view,
-                           double min_similarity) {
+void EquivalenceMap::Build(
+    const std::vector<offset_t>& old_sa,
+    const EncodedView& old_view,
+    const EncodedView& new_view,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    double min_similarity) {
   DCHECK_EQ(old_sa.size(), old_view.size());
 
-  CreateCandidates(old_sa, old_view, new_view, min_similarity);
+  CreateCandidates(old_sa, old_view, new_view, targets_affinities,
+                   min_similarity);
   SortByDestination();
-  Prune(old_view, new_view, min_similarity);
+  Prune(old_view, new_view, targets_affinities, min_similarity);
 
   offset_t coverage = 0;
   offset_t current_offset = 0;
@@ -222,10 +237,12 @@
   return equivalences;
 }
 
-void EquivalenceMap::CreateCandidates(const std::vector<offset_t>& old_sa,
-                                      const EncodedView& old_view,
-                                      const EncodedView& new_view,
-                                      double min_similarity) {
+void EquivalenceMap::CreateCandidates(
+    const std::vector<offset_t>& old_sa,
+    const EncodedView& old_view,
+    const EncodedView& new_view,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    double min_similarity) {
   candidates_.clear();
 
   // This is an heuristic to find 'good' equivalences on encoded views.
@@ -247,7 +264,7 @@
     EquivalenceCandidate best_candidate = {{0, 0, 0}, 0.0};
     for (auto it = match; it != old_sa.end(); ++it) {
       EquivalenceCandidate candidate = VisitEquivalenceSeed(
-          old_view.image_index(), new_view.image_index(),
+          old_view.image_index(), new_view.image_index(), targets_affinities,
           static_cast<offset_t>(*it), dst_offset, min_similarity);
       if (candidate.similarity > best_similarity) {
         best_candidate = candidate;
@@ -259,7 +276,7 @@
     }
     for (auto it = match; it != old_sa.begin(); --it) {
       EquivalenceCandidate candidate = VisitEquivalenceSeed(
-          old_view.image_index(), new_view.image_index(),
+          old_view.image_index(), new_view.image_index(), targets_affinities,
           static_cast<offset_t>(it[-1]), dst_offset, min_similarity);
       if (candidate.similarity > best_similarity) {
         best_candidate = candidate;
@@ -284,9 +301,11 @@
             });
 }
 
-void EquivalenceMap::Prune(const EncodedView& old_view,
-                           const EncodedView& new_view,
-                           double min_similarity) {
+void EquivalenceMap::Prune(
+    const EncodedView& old_view,
+    const EncodedView& new_view,
+    const std::vector<TargetsAffinity>& target_affinities,
+    double min_similarity) {
   for (auto current = candidates_.begin(); current != candidates_.end();
        ++current) {
     if (current->similarity < min_similarity)
@@ -304,7 +323,8 @@
       if (current->similarity < next->similarity) {
         current->eq.length -= delta;
         current->similarity = GetEquivalenceSimilarity(
-            old_view.image_index(), new_view.image_index(), current->eq);
+            old_view.image_index(), new_view.image_index(), target_affinities,
+            current->eq);
         break;
       }
     }
@@ -318,8 +338,9 @@
       next->eq.length = next->eq.length > delta ? next->eq.length - delta : 0;
       next->eq.src_offset += delta;
       next->eq.dst_offset += delta;
-      next->similarity = GetEquivalenceSimilarity(
-          old_view.image_index(), new_view.image_index(), next->eq);
+      next->similarity = GetEquivalenceSimilarity(old_view.image_index(),
+                                                  new_view.image_index(),
+                                                  target_affinities, next->eq);
       DCHECK_EQ(next->eq.dst_offset, current->eq.dst_end());
     }
   }
diff --git a/chrome/installer/zucchini/equivalence_map.h b/chrome/installer/zucchini/equivalence_map.h
index cec21e5..f6c97e14 100644
--- a/chrome/installer/zucchini/equivalence_map.h
+++ b/chrome/installer/zucchini/equivalence_map.h
@@ -12,6 +12,7 @@
 
 #include "chrome/installer/zucchini/image_index.h"
 #include "chrome/installer/zucchini/image_utils.h"
+#include "chrome/installer/zucchini/targets_affinity.h"
 
 namespace zucchini {
 
@@ -19,25 +20,35 @@
 
 class EncodedView;
 
-// Returns a similarity score between content in |old_image_index| and
-// |new_image_index| at offsets |src| and |dst|, respectively. Both |src| and
-// |dst| must refer to tokens in |old_image_index| and |new_image_index|.
-double GetTokenSimilarity(const ImageIndex& old_image_index,
-                          const ImageIndex& new_image_index,
-                          offset_t src,
-                          offset_t dst);
+// Returns similarity score between a token (raw byte or first byte of a
+// reference) in |old_image_index| at |src| and a token in |new_image_index|
+// at |dst|. |targets_affinities| describes affinities for each target pool and
+// is used to evaluate similarity between references, hence it's size must be
+// equal to the number of pools in both |old_image_index| and |new_image_index|.
+// Both |src| and |dst| must refer to tokens in |old_image_index| and
+// |new_image_index|.
+double GetTokenSimilarity(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    offset_t src,
+    offset_t dst);
 
 // Returns a similarity score between content in |old_image_index| and
-// |new_image_index| at regions described by |equivalence|.
-double GetEquivalenceSimilarity(const ImageIndex& old_image_index,
-                                const ImageIndex& new_image_index,
-                                const Equivalence& equivalence);
+// |new_image_index| at regions described by |equivalence|, using
+// |targets_affinities| to evaluate similarity between references.
+double GetEquivalenceSimilarity(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    const Equivalence& equivalence);
 
 // Extends |equivalence| forward and returns the result. This is related to
 // VisitEquivalenceSeed().
 EquivalenceCandidate ExtendEquivalenceForward(
     const ImageIndex& old_image_index,
     const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
     const EquivalenceCandidate& equivalence,
     double min_similarity);
 
@@ -46,19 +57,23 @@
 EquivalenceCandidate ExtendEquivalenceBackward(
     const ImageIndex& old_image_index,
     const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
     const EquivalenceCandidate& equivalence,
     double min_similarity);
 
 // Creates an equivalence, starting with |src| and |dst| as offset hint, and
 // extends it both forward and backward, trying to maximise similarity between
 // |old_image_index| and |new_image_index|, and returns the result.
+// |targets_affinities| is used to evaluate similarity between references.
 // |min_similarity| describes the minimum acceptable similarity score and is
 // used as threshold to discard bad equivalences.
-EquivalenceCandidate VisitEquivalenceSeed(const ImageIndex& old_image_index,
-                                          const ImageIndex& new_image_index,
-                                          offset_t src,
-                                          offset_t dst,
-                                          double min_similarity);
+EquivalenceCandidate VisitEquivalenceSeed(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    offset_t src,
+    offset_t dst,
+    double min_similarity);
 
 // Container of equivalences between |old_image_index| and |new_image_index|,
 // sorted by |Equivalence::dst_offset|, only used during patch generation.
@@ -74,15 +89,17 @@
   EquivalenceMap(const EquivalenceMap&) = delete;
   ~EquivalenceMap();
 
-  // Finds relevant equivalences between |old_view| and |new_view|, using suffix
-  // array |old_sa| computed from |old_view|. This function is not symmetric.
-  // Equivalences might overlap in |old_view|, but not in |new_view|. It tries
-  // to maximize accumulated similarity within each equivalence, while
-  // maximizing |new_view| coverage. The minimum similarity of an equivalence is
-  // given by |min_similarity|.
+  // Finds relevant equivalences between |old_view| and |new_view|, using
+  // suffix array |old_sa| computed from |old_view| and using
+  // |targets_affinities| to evaluate similarity between references. This
+  // function is not symmetric. Equivalences might overlap in |old_view|, but
+  // not in |new_view|. It tries to maximize accumulated similarity within each
+  // equivalence, while maximizing |new_view| coverage. The minimum similarity
+  // of an equivalence is given by |min_similarity|.
   void Build(const std::vector<offset_t>& old_sa,
              const EncodedView& old_view,
              const EncodedView& new_view,
+             const std::vector<TargetsAffinity>& targets_affinities,
              double min_similarity);
 
   size_t size() const { return candidates_.size(); }
@@ -100,6 +117,7 @@
   void CreateCandidates(const std::vector<offset_t>& old_sa,
                         const EncodedView& old_view,
                         const EncodedView& new_view,
+                        const std::vector<TargetsAffinity>& targets_affinities,
                         double min_similarity);
   // Sorts candidates by their offset in new image.
   void SortByDestination();
@@ -108,6 +126,7 @@
   // shrunken. Unfit candidates may be removed.
   void Prune(const EncodedView& old_view,
              const EncodedView& new_view,
+             const std::vector<TargetsAffinity>& targets_affinities,
              double min_similarity);
 
   std::vector<EquivalenceCandidate> candidates_;
diff --git a/chrome/installer/zucchini/equivalence_map_unittest.cc b/chrome/installer/zucchini/equivalence_map_unittest.cc
index 2a84a03..e61f0dc 100644
--- a/chrome/installer/zucchini/equivalence_map_unittest.cc
+++ b/chrome/installer/zucchini/equivalence_map_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/installer/zucchini/encoded_view.h"
 #include "chrome/installer/zucchini/image_index.h"
 #include "chrome/installer/zucchini/suffix_array.h"
+#include "chrome/installer/zucchini/targets_affinity.h"
 #include "chrome/installer/zucchini/test_disassembler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -39,68 +40,100 @@
   return image_index;
 }
 
+std::vector<TargetsAffinity> MakeTargetsAffinitiesForTesting(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const EquivalenceMap& equivalence_map) {
+  std::vector<TargetsAffinity> target_affinities(old_image_index.PoolCount());
+  for (const auto& old_pool_tag_and_targets : old_image_index.target_pools()) {
+    PoolTag pool_tag = old_pool_tag_and_targets.first;
+    target_affinities[pool_tag.value()].InferFromSimilarities(
+        equivalence_map, old_pool_tag_and_targets.second.targets(),
+        new_image_index.pool(pool_tag).targets());
+  }
+  return target_affinities;
+}
+
 }  // namespace
 
 TEST(EquivalenceMapTest, GetTokenSimilarity) {
   ImageIndex old_index = MakeImageIndexForTesting(
-      "ab1122334455", {{2, MarkIndex(0)}, {4, MarkIndex(1)}, {6, 2}, {8, 2}},
-      {{10, 3}});
+      "ab1122334455", {{2, 0}, {4, 1}, {6, 2}, {8, 2}}, {{10, 3}});
+  // Note: {4, 1} -> {6, 3} and {6, 2} -> {4, 1}, then result is sorted.
   ImageIndex new_index = MakeImageIndexForTesting(
-      "ab1122334455",
-      {{2, MarkIndex(0)}, {4, 1}, {6, MarkIndex(1)}, {8, MarkIndex(1)}},
-      {{10, 3}});
+      "a11b33224455", {{1, 0}, {4, 1}, {6, 3}, {8, 1}}, {{10, 2}});
+  std::vector<TargetsAffinity> affinities = MakeTargetsAffinitiesForTesting(
+      old_index, new_index,
+      EquivalenceMap({{{0, 0, 1}, 1.0}, {{1, 3, 1}, 1.0}}));
 
   // Raw match.
-  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, 0, 0));
+  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 0, 0));
   // Raw mismatch.
-  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, 0, 1));
-  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, 1, 0));
+  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 0, 1));
+  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 1, 0));
 
   // Type mismatch.
-  EXPECT_EQ(kMismatchFatal, GetTokenSimilarity(old_index, new_index, 0, 2));
-  EXPECT_EQ(kMismatchFatal, GetTokenSimilarity(old_index, new_index, 2, 0));
-  EXPECT_EQ(kMismatchFatal, GetTokenSimilarity(old_index, new_index, 2, 10));
-  EXPECT_EQ(kMismatchFatal, GetTokenSimilarity(old_index, new_index, 10, 2));
+  EXPECT_EQ(kMismatchFatal,
+            GetTokenSimilarity(old_index, new_index, affinities, 0, 1));
+  EXPECT_EQ(kMismatchFatal,
+            GetTokenSimilarity(old_index, new_index, affinities, 2, 0));
+  EXPECT_EQ(kMismatchFatal,
+            GetTokenSimilarity(old_index, new_index, affinities, 2, 10));
+  EXPECT_EQ(kMismatchFatal,
+            GetTokenSimilarity(old_index, new_index, affinities, 10, 1));
 
   // Reference strong match.
-  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, 2, 2));
-  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, 4, 6));
+  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 2, 1));
+  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 4, 6));
 
   // Reference weak match.
-  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, 6, 4));
-  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, 4, 8));
-  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, 8, 4));
+  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 6, 4));
+  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 6, 8));
+  EXPECT_LT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 8, 4));
 
   // Weak match is not greater than strong match.
-  EXPECT_LE(GetTokenSimilarity(old_index, new_index, 6, 4),
-            GetTokenSimilarity(old_index, new_index, 2, 2));
+  EXPECT_LE(GetTokenSimilarity(old_index, new_index, affinities, 6, 4),
+            GetTokenSimilarity(old_index, new_index, affinities, 2, 1));
 
   // Reference mismatch.
-  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, 2, 4));
-  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, 2, 6));
+  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 2, 4));
+  EXPECT_GT(0.0, GetTokenSimilarity(old_index, new_index, affinities, 2, 6));
 }
 
 TEST(EquivalenceMapTest, GetEquivalenceSimilarity) {
   ImageIndex image_index =
       MakeImageIndexForTesting("abcdef1122", {{6, 0}}, {{8, 1}});
+  std::vector<TargetsAffinity> affinities =
+      MakeTargetsAffinitiesForTesting(image_index, image_index, {});
 
-  EXPECT_EQ(0.0, GetEquivalenceSimilarity(image_index, image_index, {0, 0, 0}));
-  EXPECT_EQ(0.0, GetEquivalenceSimilarity(image_index, image_index, {0, 3, 0}));
-  EXPECT_EQ(0.0, GetEquivalenceSimilarity(image_index, image_index, {3, 0, 0}));
+  // Sanity check. These are no-op with length-0 equivalences.
+  EXPECT_EQ(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {0, 0, 0}));
+  EXPECT_EQ(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {0, 3, 0}));
+  EXPECT_EQ(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {3, 0, 0}));
 
-  EXPECT_LT(0.0, GetEquivalenceSimilarity(image_index, image_index, {0, 0, 3}));
-  EXPECT_GE(0.0, GetEquivalenceSimilarity(image_index, image_index, {0, 3, 3}));
-  EXPECT_GE(0.0, GetEquivalenceSimilarity(image_index, image_index, {3, 0, 3}));
+  // Now examine larger equivalences.
+  EXPECT_LT(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {0, 0, 3}));
+  EXPECT_GE(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {0, 3, 3}));
+  EXPECT_GE(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {3, 0, 3}));
 
-  EXPECT_LT(0.0, GetEquivalenceSimilarity(image_index, image_index, {6, 6, 4}));
+  EXPECT_LT(0.0, GetEquivalenceSimilarity(image_index, image_index, affinities,
+                                          {6, 6, 4}));
 }
 
 TEST(EquivalenceMapTest, ExtendEquivalenceForward) {
   auto test_extend_forward =
       [](const ImageIndex old_index, const ImageIndex new_index,
          const EquivalenceCandidate& equivalence, double base_similarity) {
-        return ExtendEquivalenceForward(old_index, new_index, equivalence,
-                                        base_similarity)
+        return ExtendEquivalenceForward(
+                   old_index, new_index,
+                   MakeTargetsAffinitiesForTesting(old_index, new_index, {}),
+                   equivalence, base_similarity)
             .eq;
       };
 
@@ -159,8 +192,10 @@
   auto test_extend_backward =
       [](const ImageIndex old_index, const ImageIndex new_index,
          const EquivalenceCandidate& equivalence, double base_similarity) {
-        return ExtendEquivalenceBackward(old_index, new_index, equivalence,
-                                         base_similarity)
+        return ExtendEquivalenceBackward(
+                   old_index, new_index,
+                   MakeTargetsAffinitiesForTesting(old_index, new_index, {}),
+                   equivalence, base_similarity)
             .eq;
       };
 
@@ -214,14 +249,27 @@
   auto test_build_equivalence = [](const ImageIndex old_index,
                                    const ImageIndex new_index,
                                    double minimum_similarity) {
+    auto affinities = MakeTargetsAffinitiesForTesting(old_index, new_index, {});
+
     EncodedView old_view(old_index);
     EncodedView new_view(new_index);
 
+    for (const auto& old_pool_tag_and_targets : old_index.target_pools()) {
+      PoolTag pool_tag = old_pool_tag_and_targets.first;
+      std::vector<uint32_t> old_labels;
+      std::vector<uint32_t> new_labels;
+      size_t label_bound = affinities[pool_tag.value()].AssignLabels(
+          1.0, &old_labels, &new_labels);
+      old_view.SetLabels(pool_tag, std::move(old_labels), label_bound);
+      new_view.SetLabels(pool_tag, std::move(new_labels), label_bound);
+    }
+
     std::vector<offset_t> old_sa =
         MakeSuffixArray<InducedSuffixSort>(old_view, old_view.Cardinality());
 
     EquivalenceMap equivalence_map;
-    equivalence_map.Build(old_sa, old_view, new_view, minimum_similarity);
+    equivalence_map.Build(old_sa, old_view, new_view, affinities,
+                          minimum_similarity);
 
     offset_t current_dst_offset = 0;
     offset_t coverage = 0;
diff --git a/chrome/installer/zucchini/image_index.cc b/chrome/installer/zucchini/image_index.cc
index cb3c4c86..fb0d6c5fe 100644
--- a/chrome/installer/zucchini/image_index.cc
+++ b/chrome/installer/zucchini/image_index.cc
@@ -15,7 +15,7 @@
 ImageIndex::ImageIndex(ConstBufferView image)
     : image_(image), type_tags_(image.size(), kNoTypeTag) {}
 
-ImageIndex::ImageIndex(ImageIndex&& that) = default;
+ImageIndex::ImageIndex(ImageIndex&&) = default;
 
 ImageIndex::~ImageIndex() = default;
 
diff --git a/chrome/installer/zucchini/image_index.h b/chrome/installer/zucchini/image_index.h
index 921390e..7ae1ebb 100644
--- a/chrome/installer/zucchini/image_index.h
+++ b/chrome/installer/zucchini/image_index.h
@@ -14,7 +14,6 @@
 #include "base/logging.h"
 #include "chrome/installer/zucchini/buffer_view.h"
 #include "chrome/installer/zucchini/image_utils.h"
-#include "chrome/installer/zucchini/label_manager.h"
 #include "chrome/installer/zucchini/reference_set.h"
 #include "chrome/installer/zucchini/target_pool.h"
 
@@ -29,7 +28,7 @@
  public:
   explicit ImageIndex(ConstBufferView image);
   ImageIndex(const ImageIndex&) = delete;
-  ImageIndex(ImageIndex&& that);
+  ImageIndex(ImageIndex&&);
   ~ImageIndex();
 
   // Inserts all references read from |disasm|. This should be called exactly
@@ -86,34 +85,6 @@
   // Returns the size of the image.
   size_t size() const { return image_.size(); }
 
-  // Replaces every target represented as offset whose Label is in
-  // |label_manager| by the index of this Label, and updates the Label bound
-  // associated with |pool|.
-  void LabelTargets(PoolTag pool, const BaseLabelManager& label_manager) {
-    target_pools_.at(pool).LabelTargets(label_manager);
-  }
-
-  // Replaces every associated target represented as offset whose Label is in
-  // |label_manager| by the index of this Label, and updates the Label bound
-  // associated with |pool|. A target is associated iff its Label index is also
-  // used in |reference_label_manager|. All targets must have a Label in
-  // |label_manager|, and must be represented as offset when calling this
-  // function, implying it can only be called once for each |pool|, until
-  // UnlabelTargets() (below) is called.
-  void LabelAssociatedTargets(PoolTag pool,
-                              const BaseLabelManager& label_manager,
-                              const BaseLabelManager& reference_label_manager) {
-    target_pools_.at(pool).LabelAssociatedTargets(label_manager,
-                                                  reference_label_manager);
-  }
-
-  // Replaces every target represented as a Label index by its original offset,
-  // assuming that |label_manager| still holds the same Labels referered to by
-  // target indices. Resets Label bound associated with |pool| to 0.
-  void UnlabelTargets(PoolTag pool, const BaseLabelManager& label_manager) {
-    target_pools_.at(pool).UnlabelTargets(label_manager);
-  }
-
  private:
   // Inserts to |*this| index, all references described by |traits| read from
   // |ref_reader|, which gets consumed. This should be called exactly once for
diff --git a/chrome/installer/zucchini/label_manager.cc b/chrome/installer/zucchini/label_manager.cc
index db73954..0759588 100644
--- a/chrome/installer/zucchini/label_manager.cc
+++ b/chrome/installer/zucchini/label_manager.cc
@@ -18,16 +18,6 @@
 BaseLabelManager::BaseLabelManager(const BaseLabelManager&) = default;
 BaseLabelManager::~BaseLabelManager() = default;
 
-offset_t BaseLabelManager::OffsetFromMarkedIndex(
-    offset_t offset_or_marked_index) const {
-  if (IsMarkedIndex(offset_or_marked_index)) {
-    offset_t offset = OffsetOfIndex(UnmarkIndex(offset_or_marked_index));
-    if (offset != kUnusedIndex)
-      return offset;
-  }
-  return offset_or_marked_index;
-}
-
 /******** OrderedLabelManager ********/
 
 OrderedLabelManager::OrderedLabelManager() = default;
@@ -41,17 +31,6 @@
   return kUnusedIndex;
 }
 
-offset_t OrderedLabelManager::MarkedIndexFromOffset(
-    offset_t offset_or_marked_index) const {
-  if (IsOffset(offset_or_marked_index)) {
-    auto it = std::lower_bound(labels_.begin(), labels_.end(),
-                               offset_or_marked_index);
-    if (it != labels_.end() && *it == offset_or_marked_index)
-      return MarkIndex(static_cast<offset_t>(it - labels_.begin()));
-  }
-  return offset_or_marked_index;
-}
-
 void OrderedLabelManager::InsertOffsets(const std::vector<offset_t>& offsets) {
   labels_.insert(labels_.end(), offsets.begin(), offsets.end());
   SortAndUniquify(&labels_);
@@ -75,16 +54,6 @@
   return it != labels_map_.end() ? it->second : kUnusedIndex;
 }
 
-offset_t UnorderedLabelManager::MarkedIndexFromOffset(
-    offset_t offset_or_marked_index) const {
-  if (IsOffset(offset_or_marked_index)) {
-    auto it = labels_map_.find(offset_or_marked_index);
-    if (it != labels_map_.end())
-      return MarkIndex(it->second);
-  }
-  return offset_or_marked_index;
-}
-
 void UnorderedLabelManager::Init(std::vector<offset_t>&& labels) {
   labels_ = std::move(labels);
   labels_map_.clear();
diff --git a/chrome/installer/zucchini/label_manager.h b/chrome/installer/zucchini/label_manager.h
index 79d34c36..ccb43966 100644
--- a/chrome/installer/zucchini/label_manager.h
+++ b/chrome/installer/zucchini/label_manager.h
@@ -20,17 +20,6 @@
 // - Get the offset of a stored index.
 // - Get the index of a stored offset.
 // - Create new Labels.
-// A LabelManager allows to have a bijection between offsets and indices.
-// Since not all targets have associated labels from LabelManager, targets
-// represented both as offset or indices are mixed. Hence, indices are
-// represented as "marked" values (implemented by setting the MSB), and offsets
-// are "unmarked". So when working with stored targets:
-// - IsMarked() distinguishes offsets (false) from indexes (true).
-// - MarkIndex() is used to encode indexes to their stored value.
-// - UnmarkIndex() is used to decode stored indexes to their actual value.
-// - Target offsets are stored verbatim, but they must not be marked. This
-//   affects reference parsing, where we reject all references whose offsets
-//   happen to be marked.
 
 // Base class for OrderedLabelManager and UnorderedLabelManager.
 class BaseLabelManager {
@@ -39,43 +28,16 @@
   BaseLabelManager(const BaseLabelManager&);
   virtual ~BaseLabelManager();
 
-  // Returns whether |offset_or_marked_index| is a valid offset.
-  static constexpr bool IsOffset(offset_t offset_or_marked_index) {
-    return !IsMarked(offset_or_marked_index);
-  }
-
-  // Returns whether |offset_or_marked_index| is a valid marked index.
-  static constexpr bool IsMarkedIndex(offset_t offset_or_marked_index) {
-    return IsMarked(offset_or_marked_index) &&
-           offset_or_marked_index != kUnusedIndex;
-  }
-
-  // Returns whether a given (unmarked) |index| is used by a stored Label.
-  bool IsIndexStored(offset_t index) const {
-    DCHECK(!IsMarked(index));
-    return index < labels_.size() && labels_[index] != kUnusedIndex;
-  }
-
-  // Returns the offset of a given (unmarked) |index| if it is associated with a
+  // Returns the offset of a given |index| if it is associated with a
   // stored Label, or |kUnusedIndex| otherwise.
   offset_t OffsetOfIndex(offset_t index) const {
     return index < labels_.size() ? labels_[index] : kUnusedIndex;
   }
 
-  // Returns the offset corresponding to |offset_or_marked_index|, which is a
-  // target that is stored either as a marked index, or as an (unmarked) offset.
-  offset_t OffsetFromMarkedIndex(offset_t offset_or_marked_index) const;
-
   // If |offset| has an associated stored Label, returns its index. Otherwise
   // returns |kUnusedIndex|.
   virtual offset_t IndexOfOffset(offset_t offset) const = 0;
 
-  // Returns the marked index corresponding to |offset_or_marked_index|, which
-  // is a target that is stored either as a marked index, or as an (unmarked)
-  // offset.
-  virtual offset_t MarkedIndexFromOffset(
-      offset_t offset_or_marked_index) const = 0;
-
   size_t size() const { return labels_.size(); }
 
  protected:
@@ -97,8 +59,6 @@
 
   // BaseLabelManager:
   offset_t IndexOfOffset(offset_t offset) const override;
-  offset_t MarkedIndexFromOffset(
-      offset_t offset_or_marked_index) const override;
 
   // Creates and stores a new Label for each unique offset in |offsets|. This
   // invalidates all previous Label lookups.
@@ -125,8 +85,6 @@
 
   // BaseLabelManager:
   offset_t IndexOfOffset(offset_t offset) const override;
-  offset_t MarkedIndexFromOffset(
-      offset_t offset_or_marked_index) const override;
 
   // Clears and reinitializes all stored data. Requires that |labels| consists
   // of unique offsets, but it may have "gaps" in the form of |kUnusedIndex|.
diff --git a/chrome/installer/zucchini/label_manager_unittest.cc b/chrome/installer/zucchini/label_manager_unittest.cc
index 23a4220..4a20a19 100644
--- a/chrome/installer/zucchini/label_manager_unittest.cc
+++ b/chrome/installer/zucchini/label_manager_unittest.cc
@@ -134,48 +134,4 @@
   EXPECT_EQ(5U, label_manager.IndexOfOffset(0x77));
 }
 
-TEST(LabelManagerTest, OrderedBatch) {
-  // Initialize Label Manager.
-  OrderedLabelManager label_manager;
-  label_manager.InsertOffsets({0x33, 0x11, 0x11, 0x55, 0x00, 0x55});
-  EXPECT_EQ(OffsetVector({0x00, 0x11, 0x33, 0x55}), label_manager.Labels());
-
-  // Test data for array conversions.
-  OffsetVector values = {0x22, 0x33, 0x44, MarkIndex(3), 0x11};
-
-  // Convert all stored offsets for marked index.
-  for (auto& v : values)
-    v = label_manager.MarkedIndexFromOffset(v);
-  EXPECT_EQ(
-      OffsetVector({0x22, MarkIndex(2), 0x44, MarkIndex(3), MarkIndex(1)}),
-      values);
-
-  // Convert all marked index (assumed to be all stored) to offsets.
-  for (auto& v : values)
-    v = label_manager.OffsetFromMarkedIndex(v);
-  EXPECT_EQ(OffsetVector({0x22, 0x33, 0x44, 0x55, 0x11}), values);
-}
-
-TEST(LabelManagerTest, UnorderedBatch) {
-  // Initialize Label Manager.
-  UnorderedLabelManager label_manager;
-  OffsetVector labels = {0x00, BAD, 0x33, BAD, 0x11, BAD, 0x55};
-  label_manager.Init(std::move(labels));
-
-  // Test data for array conversions.
-  OffsetVector values = {0x22, 0x33, 0x44, MarkIndex(6), 0x11};
-
-  // Convert all stored offsets for marked index.
-  for (auto& v : values)
-    v = label_manager.MarkedIndexFromOffset(v);
-  EXPECT_EQ(
-      OffsetVector({0x22, MarkIndex(2), 0x44, MarkIndex(6), MarkIndex(4)}),
-      values);
-
-  // Convert all marked index (assumed to be all stored) to offsets.
-  for (auto& v : values)
-    v = label_manager.OffsetFromMarkedIndex(v);
-  EXPECT_EQ(OffsetVector({0x22, 0x33, 0x44, 0x55, 0x11}), values);
-}
-
 }  // namespace zucchini
diff --git a/chrome/installer/zucchini/rel32_finder_unittest.cc b/chrome/installer/zucchini/rel32_finder_unittest.cc
index 49ff6269..ad58e51 100644
--- a/chrome/installer/zucchini/rel32_finder_unittest.cc
+++ b/chrome/installer/zucchini/rel32_finder_unittest.cc
@@ -9,12 +9,13 @@
 
 #include <algorithm>
 #include <iterator>
-#include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "chrome/installer/zucchini/buffer_view.h"
 #include "chrome/installer/zucchini/image_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,13 +39,13 @@
         ConstBufferView::FromRange(image.begin() + rlo, image.begin() + rhi);
     Abs32GapFinder gap_finder(image, region, abs32_locations, abs32_width);
 
-    std::ostringstream oss;
+    std::string out_str;
     for (auto gap = gap_finder.GetNext(); gap; gap = gap_finder.GetNext()) {
-      std::ptrdiff_t lo = gap->begin() - image.begin();
-      std::ptrdiff_t hi = gap->end() - image.begin();
-      oss << "[" << lo << "," << hi << ")";
+      size_t lo = static_cast<size_t>(gap->begin() - image.begin());
+      size_t hi = static_cast<size_t>(gap->end() - image.begin());
+      out_str.append(base::StringPrintf("[%" PRIuS ",%" PRIuS ")", lo, hi));
     }
-    return oss.str();
+    return out_str;
   };
 
   // Empty regions yield empty segments.
diff --git a/chrome/installer/zucchini/target_pool.cc b/chrome/installer/zucchini/target_pool.cc
index 3ed9f41..9c1d17a89 100644
--- a/chrome/installer/zucchini/target_pool.cc
+++ b/chrome/installer/zucchini/target_pool.cc
@@ -10,7 +10,6 @@
 
 #include "base/logging.h"
 #include "chrome/installer/zucchini/algorithm.h"
-#include "chrome/installer/zucchini/label_manager.h"
 
 namespace zucchini {
 
@@ -48,34 +47,4 @@
   return static_cast<offset_t>(pos - targets_.begin());
 }
 
-void TargetPool::LabelTargets(const BaseLabelManager& label_manager) {
-  for (auto& target : targets_)
-    target = label_manager.MarkedIndexFromOffset(target);
-  label_bound_ = label_manager.size();
-}
-
-void TargetPool::UnlabelTargets(const BaseLabelManager& label_manager) {
-  for (auto& target : targets_) {
-    target = label_manager.OffsetFromMarkedIndex(target);
-    DCHECK(!IsMarked(target));  // Expected to be represented as offset.
-  }
-  label_bound_ = 0;
-}
-
-void TargetPool::LabelAssociatedTargets(
-    const BaseLabelManager& label_manager,
-    const BaseLabelManager& reference_label_manager) {
-  // Convert to marked indexes.
-  for (auto& target : targets_) {
-    // Represent Label as marked index iff the index is also in
-    // |reference_label_manager|.
-    DCHECK(!IsMarked(target));  // Expected to be represented as offset.
-    offset_t index = label_manager.IndexOfOffset(target);
-    DCHECK_NE(kUnusedIndex, index);  // Target is expected to have a label.
-    if (reference_label_manager.IsIndexStored(index))
-      target = MarkIndex(index);
-  }
-  label_bound_ = label_manager.size();
-}
-
 }  // namespace zucchini
diff --git a/chrome/installer/zucchini/target_pool.h b/chrome/installer/zucchini/target_pool.h
index ebc87ad..4195a3a 100644
--- a/chrome/installer/zucchini/target_pool.h
+++ b/chrome/installer/zucchini/target_pool.h
@@ -13,8 +13,6 @@
 
 namespace zucchini {
 
-class BaseLabelManager;
-
 // Ordered container of distinct targets that have the same semantics, along
 // with a list of associated reference types, only used during patch generation.
 class TargetPool {
@@ -43,8 +41,6 @@
   // this class.
   offset_t OffsetForKey(key_t key) const { return targets_[key]; }
 
-  size_t label_bound() const { return label_bound_; }
-
   // Accessors for testing.
   const std::vector<offset_t>& targets() const { return targets_; }
   const std::vector<TypeTag>& types() const { return types_; }
@@ -54,33 +50,9 @@
   const_iterator begin() const;
   const_iterator end() const;
 
-  // The three functions below are transition hacks that mark targets, which
-  // will disappear.
-
-  // Replaces every target represented as offset whose Label is in
-  // |label_manager| by the index of this Label, and updates the Label bound
-  // associated with |pool|.
-  void LabelTargets(const BaseLabelManager& label_manager);
-
-  // Replaces every associated target represented as offset whose Label is in
-  // |label_manager| by the index of this Label, and updates the Label bound
-  // associated with |pool|. A target is associated iff its Label index is also
-  // used in |reference_label_manager|. All targets must have a Label in
-  // |label_manager|, and must be represented as offset when calling this
-  // function, implying it can only be called once for each |pool|, until
-  // UnlabelTargets() (below) is called.
-  void LabelAssociatedTargets(const BaseLabelManager& label_manager,
-                              const BaseLabelManager& reference_label_manager);
-
-  // Replaces every target represented as a Label index by its original offset,
-  // assuming that |label_manager| still holds the same Labels referered to by
-  // target indices. Resets Label bound associated with |pool| to 0.
-  void UnlabelTargets(const BaseLabelManager& label_manager);
-
  private:
   std::vector<TypeTag> types_;     // Enumerates type_tag for this pool.
   std::vector<offset_t> targets_;  // Targets for pool in ascending order.
-  size_t label_bound_ = 0;
 };
 
 }  // namespace zucchini
diff --git a/chrome/installer/zucchini/target_pool_unittest.cc b/chrome/installer/zucchini/target_pool_unittest.cc
index 0b8f626..330bae4 100644
--- a/chrome/installer/zucchini/target_pool_unittest.cc
+++ b/chrome/installer/zucchini/target_pool_unittest.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "chrome/installer/zucchini/image_utils.h"
-#include "chrome/installer/zucchini/label_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace zucchini {
@@ -53,38 +52,4 @@
   test_key_offset({1, 3, 7, 9, 13});
 }
 
-TEST(TargetPoolTest, LabelTargets) {
-  TargetPool target_pool;
-  target_pool.InsertTargets({{1, 0}, {8, 1}, {10, 2}});
-
-  OrderedLabelManager label_manager;
-  label_manager.InsertOffsets({0, 2, 3, 4});
-  target_pool.LabelTargets(label_manager);
-  EXPECT_EQ(4U, target_pool.label_bound());
-
-  EXPECT_EQ(std::vector<offset_t>({MarkIndex(0), 1, MarkIndex(1)}),
-            target_pool.targets());
-
-  target_pool.UnlabelTargets(label_manager);
-  EXPECT_EQ(0U, target_pool.label_bound());
-
-  EXPECT_EQ(std::vector<offset_t>({0, 1, 2}), target_pool.targets());
-}
-
-TEST(TargetPoolTest, LabelAssociatedTargets) {
-  TargetPool target_pool;
-  target_pool.InsertTargets({{1, 0}, {8, 1}, {10, 2}});
-
-  OrderedLabelManager label_manager;
-  label_manager.InsertOffsets({0, 1, 2, 3, 4});
-
-  UnorderedLabelManager reference_label_manager;
-  reference_label_manager.Init({0, kUnusedIndex, 2});
-
-  target_pool.LabelAssociatedTargets(label_manager, reference_label_manager);
-  EXPECT_EQ(5U, target_pool.label_bound());
-  EXPECT_EQ(std::vector<offset_t>({MarkIndex(0), 1, MarkIndex(2)}),
-            target_pool.targets());
-}
-
 }  // namespace zucchini
diff --git a/chrome/installer/zucchini/zucchini_gen.cc b/chrome/installer/zucchini/zucchini_gen.cc
index 159935da..954f39b 100644
--- a/chrome/installer/zucchini/zucchini_gen.cc
+++ b/chrome/installer/zucchini/zucchini_gen.cc
@@ -20,6 +20,7 @@
 #include "chrome/installer/zucchini/label_manager.h"
 #include "chrome/installer/zucchini/patch_writer.h"
 #include "chrome/installer/zucchini/suffix_array.h"
+#include "chrome/installer/zucchini/targets_affinity.h"
 
 namespace zucchini {
 
@@ -27,15 +28,8 @@
 
 // Parameters for patch generation.
 constexpr double kMinEquivalenceSimilarity = 12.0;
-constexpr double kLargeEquivalenceSimilarity = 64.0;
-
-// Helper functions wrapping around MakeSuffixArray().
-// TODO(etiennep): Figure out if this should be a member function of ImageIndex.
-std::vector<offset_t> MakeSuffixArrayFromImageIndex(
-    const ImageIndex& image_index) {
-  EncodedView view(image_index);
-  return MakeSuffixArray<InducedSuffixSort>(view, view.Cardinality());
-}
+constexpr double kMinLabelAffinity = 64.0;
+constexpr size_t kNumIterations = 2;
 
 }  // namespace
 
@@ -101,62 +95,47 @@
   return targets;
 }
 
-EquivalenceMap CreateEquivalenceMap(
-    const std::vector<OrderedLabelManager>& old_label_managers,
-    ImageIndex* old_image_index,
-    ImageIndex* new_image_index) {
+EquivalenceMap CreateEquivalenceMap(const ImageIndex& old_image_index,
+                                    const ImageIndex& new_image_index) {
   // Label matching (between "old" and "new") can guide EquivalenceMap
   // construction; but EquivalenceMap induces Label matching. This apparent
-  // "chick and egg" problem is solved by bootstrapping a "coarse"
-  // EquivalenceMap using reference type data in |*image_index|.
-  size_t pool_count = old_image_index->PoolCount();
-  std::vector<UnorderedLabelManager> new_label_managers(pool_count);
+  // "chick and egg" problem is solved by multiple iterations alternating 2
+  // steps:
+  // - Association of targets based on previous EquivalenceMap. Note that the
+  //   EquivalenceMap is empty on first iteration, so this is a no-op.
+  // - Construction of refined EquivalenceMap based on new targets associations.
+  size_t pool_count = old_image_index.PoolCount();
+  // |target_affinities| is outside the loop to reduce allocation.
+  std::vector<TargetsAffinity> target_affinities(pool_count);
+
   EquivalenceMap equivalence_map;
+  for (size_t i = 0; i < kNumIterations; ++i) {
+    EncodedView old_view(old_image_index);
+    EncodedView new_view(new_image_index);
 
-  // Build coarse equivalence map, where references with same types are
-  // considered equivalent.
-  equivalence_map.Build(MakeSuffixArrayFromImageIndex(*old_image_index),
-                        EncodedView(*old_image_index),
-                        EncodedView(*new_image_index),
-                        kLargeEquivalenceSimilarity);
+    // Associate targets from "old" to "new" image based on |equivalence_map|
+    // for each reference pool.
+    for (const auto& old_pool_tag_and_targets :
+         old_image_index.target_pools()) {
+      PoolTag pool_tag = old_pool_tag_and_targets.first;
+      target_affinities[pool_tag.value()].InferFromSimilarities(
+          equivalence_map, old_pool_tag_and_targets.second.targets(),
+          new_image_index.pool(pool_tag).targets());
 
-  // Associate targets from "old" to "new" image based on coarse
-  // |equivalence_map| and label references accordingly.
-  for (const auto& old_pool_tag_and_targets : old_image_index->target_pools()) {
-    PoolTag pool_tag = old_pool_tag_and_targets.first;
-    const auto& old_label_manager = old_label_managers[pool_tag.value()];
-    auto& new_label_manager = new_label_managers[pool_tag.value()];
-
-    // Project "old" targets to "new". |new_label_manager| stores all "new"
-    // targets (for |pool|) that are successfully and exclusively matched to an
-    // "old" target.
-    std::vector<offset_t> new_labels = MakeNewTargetsFromEquivalenceMap(
-        old_label_manager.Labels(), equivalence_map.MakeForwardEquivalences());
-    new_label_manager.Init(std::move(new_labels));
-
-    // Encode matching into |*_image_index|: Matched "old" and "new" targets are
-    // assigned a common index to indicate that they share common semantics.
-    old_image_index->LabelAssociatedTargets(pool_tag, old_label_manager,
-                                            new_label_manager);
-    new_image_index->LabelTargets(pool_tag, new_label_manager);
-  }
-
-  // Build refined equivalence map, where references in "old" and "new" that
-  // share common semantics (i.e., their respective targets were matched earlier
-  // on) are considered equivalent. Note that a different |min_similarity| is
-  // used.
-  equivalence_map.Build(MakeSuffixArrayFromImageIndex(*old_image_index),
-                        EncodedView(*old_image_index),
-                        EncodedView(*new_image_index),
-                        kMinEquivalenceSimilarity);
-
-  // Restore |old_image_index| and |new_image_index| to offsets.
-  for (const auto& old_pool_tag_and_targets : old_image_index->target_pools()) {
-    PoolTag pool_tag = old_pool_tag_and_targets.first;
-    old_image_index->UnlabelTargets(pool_tag,
-                                    old_label_managers[pool_tag.value()]);
-    new_image_index->UnlabelTargets(pool_tag,
-                                    new_label_managers[pool_tag.value()]);
+      // Creates labels for strongly associated targets.
+      std::vector<uint32_t> old_labels;
+      std::vector<uint32_t> new_labels;
+      size_t label_bound = target_affinities[pool_tag.value()].AssignLabels(
+          kMinLabelAffinity, &old_labels, &new_labels);
+      old_view.SetLabels(pool_tag, std::move(old_labels), label_bound);
+      new_view.SetLabels(pool_tag, std::move(new_labels), label_bound);
+    }
+    // Build equivalence map, where references in "old" and "new" that share
+    // common semantics (i.e., their respective targets were associated earlier
+    // on) are considered equivalent.
+    equivalence_map.Build(
+        MakeSuffixArray<InducedSuffixSort>(old_view, old_view.Cardinality()),
+        old_view, new_view, target_affinities, kMinEquivalenceSimilarity);
   }
 
   return equivalence_map;
@@ -286,7 +265,8 @@
 
   EquivalenceMap equivalences;
   equivalences.Build(old_sa, EncodedView(old_image_index),
-                     EncodedView(new_image_index), kMinEquivalenceSimilarity);
+                     EncodedView(new_image_index), {},
+                     kMinEquivalenceSimilarity);
 
   patch_writer->SetReferenceDeltaSink({});
   return GenerateEquivalencesAndExtraData(new_image, equivalences,
@@ -321,16 +301,8 @@
   DCHECK_EQ(old_image_index.PoolCount(), new_image_index.PoolCount());
   size_t pool_count = old_image_index.PoolCount();
 
-  // Initialize old LabelManagers.
-  std::vector<OrderedLabelManager> old_label_managers(pool_count);
-  for (const auto& old_pool_tag_and_targets : old_image_index.target_pools()) {
-    PoolTag pool_tag = old_pool_tag_and_targets.first;
-    old_label_managers[pool_tag.value()].InsertOffsets(
-        old_pool_tag_and_targets.second.targets());
-  }
-
-  EquivalenceMap equivalences = CreateEquivalenceMap(
-      old_label_managers, &old_image_index, &new_image_index);
+  EquivalenceMap equivalences =
+      CreateEquivalenceMap(old_image_index, new_image_index);
   std::vector<Equivalence> forward_equivalences =
       equivalences.MakeForwardEquivalences();
 
diff --git a/chrome/installer/zucchini/zucchini_gen.h b/chrome/installer/zucchini/zucchini_gen.h
index edd4e1ba..a6909c5 100644
--- a/chrome/installer/zucchini/zucchini_gen.h
+++ b/chrome/installer/zucchini/zucchini_gen.h
@@ -16,7 +16,6 @@
 
 class EquivalenceMap;
 class ImageIndex;
-class OrderedLabelManager;
 class PatchElementWriter;
 class ReferenceDeltaSink;
 class ReferenceSet;
@@ -45,14 +44,8 @@
 // - Provide "old" and "new" raw image data and references.
 // - Mediate Label matching, which links references between "old" and "new", and
 //   guides EquivalenceMap construction.
-// |*_image_index| is assumed to hold targets as *unmarked* offsets. These are
-// also temporarily modified during Label matching -- that's why they're passed
-// by pointer. Meanwhile, |old_label_manager| contains labels for
-// |old_image_index|.
-EquivalenceMap CreateEquivalenceMap(
-    const std::vector<OrderedLabelManager>& old_label_managers,
-    ImageIndex* old_image_index,
-    ImageIndex* new_image_index);
+EquivalenceMap CreateEquivalenceMap(const ImageIndex& old_image_index,
+                                    const ImageIndex& new_image_index);
 
 // Writes equivalences from |equivalence_map|, and extra data from |new_image|
 // found in gaps between equivalences to |patch_writer|.
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index 61709b76..f3947e4 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -24,6 +24,7 @@
 #include "content/public/renderer/render_view.h"
 #include "extensions/features/features.h"
 #include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/WebKit/common/associated_interfaces/associated_interface_registry.h"
 #include "third_party/WebKit/public/platform/URLConversion.h"
 #include "third_party/WebKit/public/platform/WebClientHintsType.h"
 #include "third_party/WebKit/public/platform/WebContentSettingCallbacks.h"
@@ -126,8 +127,8 @@
   ClearBlockedContentSettings();
   render_frame->GetWebFrame()->SetContentSettingsClient(this);
 
-  registry->AddInterface(
-      base::Bind(&ContentSettingsObserver::OnInsecureContentRendererRequest,
+  render_frame->GetAssociatedInterfaceRegistry()->AddInterface(
+      base::Bind(&ContentSettingsObserver::OnContentSettingsRendererRequest,
                  base::Unretained(this)));
 
   content::RenderFrame* main_frame =
@@ -182,7 +183,6 @@
 bool ContentSettingsObserver::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserver, message)
-    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetAsInterstitial, OnSetAsInterstitial)
     IPC_MESSAGE_HANDLER(ChromeViewMsg_RequestFileSystemAccessAsyncResponse,
                         OnRequestFileSystemAccessAsyncResponse)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -236,9 +236,13 @@
     frame->Reload(blink::WebFrameLoadType::kReload);
 }
 
-void ContentSettingsObserver::OnInsecureContentRendererRequest(
-    chrome::mojom::InsecureContentRendererRequest request) {
-  insecure_content_renderer_bindings_.AddBinding(this, std::move(request));
+void ContentSettingsObserver::SetAsInterstitial() {
+  is_interstitial_page_ = true;
+}
+
+void ContentSettingsObserver::OnContentSettingsRendererRequest(
+    chrome::mojom::ContentSettingsRendererAssociatedRequest request) {
+  bindings_.AddBinding(this, std::move(request));
 }
 
 bool ContentSettingsObserver::AllowDatabase(const WebString& name,
@@ -523,10 +527,6 @@
   temporarily_allowed_plugins_.insert(identifier);
 }
 
-void ContentSettingsObserver::OnSetAsInterstitial() {
-  is_interstitial_page_ = true;
-}
-
 void ContentSettingsObserver::OnRequestFileSystemAccessAsyncResponse(
     int request_id,
     bool allowed) {
diff --git a/chrome/renderer/content_settings_observer.h b/chrome/renderer/content_settings_observer.h
index 24e53b0..8030dcd9 100644
--- a/chrome/renderer/content_settings_observer.h
+++ b/chrome/renderer/content_settings_observer.h
@@ -12,13 +12,13 @@
 #include "base/containers/flat_set.h"
 #include "base/gtest_prod_util.h"
 #include "base/time/time.h"
-#include "chrome/common/insecure_content_renderer.mojom.h"
+#include "chrome/common/content_settings_renderer.mojom.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/public/renderer/render_frame_observer_tracker.h"
 #include "extensions/features/features.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/associated_binding_set.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "third_party/WebKit/public/platform/WebContentSettingsClient.h"
 #include "url/gurl.h"
@@ -40,7 +40,7 @@
     : public content::RenderFrameObserver,
       public content::RenderFrameObserverTracker<ContentSettingsObserver>,
       public blink::WebContentSettingsClient,
-      public chrome::mojom::InsecureContentRenderer {
+      public chrome::mojom::ContentSettingsRenderer {
  public:
   // Set |should_whitelist| to true if |render_frame()| contains content that
   // should be whitelisted for content settings.
@@ -115,15 +115,15 @@
                                 bool is_same_document_navigation) override;
   void OnDestruct() override;
 
-  // chrome::mojom::InsecureContentRenderer:
+  // chrome::mojom::ContentSettingsRenderer:
   void SetAllowRunningInsecureContent() override;
+  void SetAsInterstitial() override;
 
-  void OnInsecureContentRendererRequest(
-      chrome::mojom::InsecureContentRendererRequest request);
+  void OnContentSettingsRendererRequest(
+      chrome::mojom::ContentSettingsRendererAssociatedRequest request);
 
   // Message handlers.
   void OnLoadBlockedPlugins(const std::string& identifier);
-  void OnSetAsInterstitial();
   void OnRequestFileSystemAccessAsyncResponse(int request_id, bool allowed);
 
   // Resets the |content_blocked_| array.
@@ -182,8 +182,7 @@
   // If true, IsWhitelistedForContentSettings will always return true.
   const bool should_whitelist_;
 
-  mojo::BindingSet<chrome::mojom::InsecureContentRenderer>
-      insecure_content_renderer_bindings_;
+  mojo::AssociatedBindingSet<chrome::mojom::ContentSettingsRenderer> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentSettingsObserver);
 };
diff --git a/chrome/renderer/content_settings_observer_browsertest.cc b/chrome/renderer/content_settings_observer_browsertest.cc
index b7a7b1e..9e4a86de 100644
--- a/chrome/renderer/content_settings_observer_browsertest.cc
+++ b/chrome/renderer/content_settings_observer_browsertest.cc
@@ -14,11 +14,13 @@
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_utils.h"
+#include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_test_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/common/associated_interfaces/associated_interface_registry.h"
 #include "third_party/WebKit/public/web/WebFrameContentDumper.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -110,7 +112,16 @@
 
 }  // namespace
 
-using ContentSettingsObserverBrowserTest = ChromeRenderViewTest;
+class ContentSettingsObserverBrowserTest : public ChromeRenderViewTest {
+  void SetUp() override {
+    ChromeRenderViewTest::SetUp();
+    // Unbind the ContentSettingsRenderer interface that would be registered by
+    // the ContentSettingsObserver created when the render frame is created.
+    view_->GetMainRenderFrame()
+        ->GetAssociatedInterfaceRegistry()
+        ->RemoveInterface(chrome::mojom::ContentSettingsRenderer::Name_);
+  }
+};
 
 TEST_F(ContentSettingsObserverBrowserTest, DidBlockContentType) {
   MockContentSettingsObserver observer(view_->GetMainRenderFrame(),
@@ -468,7 +479,7 @@
   ContentSettingsObserver* observer =
       ContentSettingsObserver::Get(view_->GetMainRenderFrame());
   observer->SetContentSettingRules(&content_setting_rules);
-  observer->OnSetAsInterstitial();
+  observer->SetAsInterstitial();
 
   // Load a page which contains a script.
   LoadHTML(kScriptHtml);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 0ece164..2993e56 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2897,8 +2897,10 @@
       "../browser/ui/tabs/tab_activity_watcher_unittest.cc",
       "../browser/ui/tabs/tab_menu_model_unittest.cc",
       "../browser/ui/tabs/tab_metrics_logger_impl_unittest.cc",
-      "../browser/ui/tabs/tab_strip_model_impl_unittest.cc",
       "../browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc",
+      "../browser/ui/tabs/tab_strip_model_unittest.cc",
+      "../browser/ui/tabs/tab_ukm_test_helper.cc",
+      "../browser/ui/tabs/tab_ukm_test_helper.h",
       "../browser/ui/tabs/test_tab_strip_model_delegate.cc",
       "../browser/ui/tabs/test_tab_strip_model_delegate.h",
       "../browser/ui/tabs/window_activity_watcher_unittest.cc",
diff --git a/chrome/test/data/webui/md_bookmarks/command_manager_test.js b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
index 1efee2a..6907578 100644
--- a/chrome/test/data/webui/md_bookmarks/command_manager_test.js
+++ b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
@@ -58,7 +58,8 @@
               [
                 createFolder('21', []),
               ]),
-          createFolder('3', bulkChildren)),
+          createFolder('3', bulkChildren),
+          createFolder('4', [], {unmodifiable: 'managed'})),
       selectedFolder: '1',
     });
     store.replaceSingleton();
@@ -81,7 +82,7 @@
     store.data.selection.items = new Set(['11', '13']);
     store.notifyObservers();
 
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     Polymer.dom.flush();
 
     var commandHidden = {};
@@ -177,7 +178,7 @@
     store.data.selection.items = new Set(['12']);
     store.notifyObservers();
 
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     Polymer.dom.flush();
 
     var showInFolderItem = commandManager.root.querySelector(
@@ -191,7 +192,7 @@
     store.data.search.results = ['12', '13'];
     store.notifyObservers();
     commandManager.closeCommandMenu();
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     assertFalse(showInFolderItem.hidden);
 
     // Show in Folder hidden when menu is opened from the sidebar.
@@ -203,7 +204,7 @@
     store.data.selection.items = new Set(['12', '13']);
     store.notifyObservers();
     commandManager.closeCommandMenu();
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     assertTrue(showInFolderItem.hidden);
 
     // Executing the command selects the parent folder.
@@ -294,7 +295,7 @@
 
     store.data.selection.items = items;
 
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     Polymer.dom.flush();
 
     var commandItem = {};
@@ -325,7 +326,7 @@
     assertFalse(commandManager.canExecute(Command.REDO, items));
 
     // No divider line should be visible when only 'Open' commands are enabled.
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     commandManager.root.querySelectorAll('hr').forEach(element => {
       assertTrue(element.hidden);
     });
@@ -338,14 +339,11 @@
     assertFalse(commandManager.canExecute(Command.EDIT, items));
     assertFalse(commandManager.canExecute(Command.DELETE, items));
 
-    store.data.nodes['12'].unmodifiable = 'managed';
-    store.notifyObservers();
-
-    items = new Set(['12']);
+    items = new Set(['4']);
     assertFalse(commandManager.canExecute(Command.EDIT, items));
     assertFalse(commandManager.canExecute(Command.DELETE, items));
 
-    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.LIST);
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.ITEM);
     var commandItem = {};
     commandManager.root.querySelectorAll('.dropdown-item').forEach(element => {
       commandItem[element.getAttribute('command')] = element;
@@ -368,6 +366,67 @@
     MockInteractions.pressAndReleaseKeyOn(document.body, '', '', 'Delete');
     commandManager.assertLastCommand(null);
   });
+
+  test('toolbar menu options are disabled when appropriate', function() {
+    store.data.selectedFolder = '1';
+    store.data.prefs.canEdit = true;
+    store.notifyObservers();
+
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.TOOLBAR);
+    assertTrue(commandManager.canExecute(Command.SORT, new Set()));
+    assertTrue(commandManager.canExecute(Command.ADD_BOOKMARK, new Set()));
+    assertTrue(commandManager.canExecute(Command.ADD_FOLDER, new Set()));
+
+    store.data.selectedFolder = '4';
+    store.notifyObservers();
+
+    assertFalse(commandManager.canExecute(Command.SORT, new Set()));
+    assertFalse(commandManager.canExecute(Command.ADD_BOOKMARK, new Set()));
+    assertFalse(commandManager.canExecute(Command.ADD_FOLDER, new Set()));
+    assertTrue(commandManager.canExecute(Command.IMPORT, new Set()));
+
+    store.data.selectedFolder = '1';
+    store.data.prefs.canEdit = false;
+    store.notifyObservers();
+
+    assertFalse(commandManager.canExecute(Command.SORT, new Set()));
+    assertFalse(commandManager.canExecute(Command.IMPORT, new Set()));
+    assertFalse(commandManager.canExecute(Command.ADD_BOOKMARK, new Set()));
+    assertFalse(commandManager.canExecute(Command.ADD_FOLDER, new Set()));
+  });
+
+  test('sort button is disabled when folder is empty', function() {
+    store.data.selectedFolder = '3';
+    store.notifyObservers();
+
+    commandManager.openCommandMenuAtPosition(0, 0, MenuSource.TOOLBAR);
+    assertTrue(commandManager.canExecute(Command.SORT, new Set()));
+
+    store.data.selectedFolder = '21';
+    store.notifyObservers();
+
+    assertFalse(commandManager.canExecute(Command.SORT, new Set()));
+
+    // Adding 2 bookmarks should enable sorting.
+    store.setReducersEnabled(true);
+    var item1 = {
+      id: '211',
+      parentId: '21',
+      index: 0,
+      url: 'https://www.example.com',
+    };
+    store.dispatch(bookmarks.actions.createBookmark(item1.id, item1));
+    assertFalse(commandManager.canExecute(Command.SORT, new Set()));
+
+    var item2 = {
+      id: '212',
+      parentId: '21',
+      index: 1,
+      url: 'https://www.example.com',
+    };
+    store.dispatch(bookmarks.actions.createBookmark(item2.id, item2));
+    assertTrue(commandManager.canExecute(Command.SORT, new Set()));
+  });
 });
 
 suite('<bookmarks-item> CommandManager integration', function() {
diff --git a/chrome/test/data/webui/md_bookmarks/toolbar_test.js b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
index f7c4788..095036a 100644
--- a/chrome/test/data/webui/md_bookmarks/toolbar_test.js
+++ b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
@@ -93,64 +93,4 @@
     assertTrue(
         toolbar.$$('cr-toolbar-selection-overlay').deleteButton.disabled);
   });
-
-  test('overflow menu options are disabled when appropriate', function() {
-    MockInteractions.tap(toolbar.$.menuButton);
-    Polymer.dom.flush();
-
-    store.data.selectedFolder = '1';
-    store.notifyObservers();
-
-    assertFalse(toolbar.$$('#addBookmarkButton').disabled);
-
-    store.data.selectedFolder = '4';
-    store.notifyObservers();
-
-    assertTrue(toolbar.$$('#addBookmarkButton').disabled);
-    assertFalse(toolbar.$$('#importBookmarkButton').disabled);
-
-    store.data.prefs.canEdit = false;
-    store.notifyObservers();
-
-    assertTrue(toolbar.$$('#addBookmarkButton').disabled);
-    assertTrue(toolbar.$$('#importBookmarkButton').disabled);
-  });
-
-  test('sort button is disabled when folder is empty', function() {
-    MockInteractions.tap(toolbar.$.menuButton);
-
-    store.data.selectedFolder = '6';
-    store.notifyObservers();
-    assertTrue(toolbar.canSortFolder_);
-
-    store.data.selectedFolder = '5';
-    store.notifyObservers();
-
-    assertFalse(toolbar.canSortFolder_);
-    assertTrue(toolbar.$$('#sortButton').disabled);
-
-    // Adding 2 bookmarks should enable sorting.
-    store.setReducersEnabled(true);
-    var item1 = {
-      id: '51',
-      parentId: '5',
-      index: 0,
-      url: 'https://www.example.com',
-    };
-    store.dispatch(bookmarks.actions.createBookmark(
-        item1.id, item1));
-    assertFalse(toolbar.canSortFolder_);
-    assertTrue(toolbar.$$('#sortButton').disabled);
-
-    var item2 = {
-      id: '52',
-      parentId: '5',
-      index: 1,
-      url: 'https://www.example.com',
-    };
-    store.dispatch(bookmarks.actions.createBookmark(
-        item2.id, item2));
-    assertTrue(toolbar.canSortFolder_);
-    assertFalse(toolbar.$$('#sortButton').disabled);
-  });
 });
diff --git a/chromecast/graphics/cast_screen.cc b/chromecast/graphics/cast_screen.cc
index 917afa8f..d620179 100644
--- a/chromecast/graphics/cast_screen.cc
+++ b/chromecast/graphics/cast_screen.cc
@@ -21,6 +21,7 @@
 namespace {
 
 const int64_t kDisplayId = 1;
+constexpr char kDisplayRotation[] = "display-rotation";
 
 // Helper to return the screen resolution (device pixels)
 // to use.
@@ -36,6 +37,20 @@
   }
 }
 
+display::Display::Rotation GetRotationFromCommandLine() {
+  std::string rotation =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+          kDisplayRotation);
+  if (rotation == "90")
+    return display::Display::ROTATE_90;
+  else if (rotation == "180")
+    return display::Display::ROTATE_180;
+  else if (rotation == "270")
+    return display::Display::ROTATE_270;
+  else
+    return display::Display::ROTATE_0;
+}
+
 }  // namespace
 
 CastScreen::~CastScreen() {
@@ -71,6 +86,7 @@
           << " bounds=" << bounds.ToString();
   display::Display display(kDisplayId);
   display.SetScaleAndBounds(device_scale_factor, bounds);
+  display.set_rotation(GetRotationFromCommandLine());
   ProcessDisplayChanged(display, true /* is_primary */);
 }
 
diff --git a/chromecast/graphics/cast_window_manager_aura.cc b/chromecast/graphics/cast_window_manager_aura.cc
index 31d804a..6d3deb9 100644
--- a/chromecast/graphics/cast_window_manager_aura.cc
+++ b/chromecast/graphics/cast_window_manager_aura.cc
@@ -18,6 +18,32 @@
 #include "ui/display/screen.h"
 
 namespace chromecast {
+namespace {
+
+gfx::Transform GetPrimaryDisplayRotationTransform() {
+  gfx::Transform rotation;
+  display::Display display(display::Screen::GetScreen()->GetPrimaryDisplay());
+  switch (display.rotation()) {
+    case display::Display::ROTATE_0:
+      break;
+    case display::Display::ROTATE_90:
+      rotation.Translate(display.bounds().height(), 0);
+      rotation.Rotate(90);
+      break;
+    case display::Display::ROTATE_180:
+      rotation.Translate(display.bounds().width(), display.bounds().height());
+      rotation.Rotate(180);
+      break;
+    case display::Display::ROTATE_270:
+      rotation.Translate(0, display.bounds().width());
+      rotation.Rotate(270);
+      break;
+  }
+
+  return rotation;
+}
+
+}  // namespace
 
 // An ui::EventTarget that ignores events.
 class CastEventIgnorer : public ui::EventTargeter {
@@ -191,6 +217,7 @@
       new CastWindowTreeHost(enable_input_, gfx::Rect(display_size)));
   window_tree_host_->InitHost();
   window_tree_host_->window()->SetLayoutManager(new CastLayoutManager());
+  window_tree_host_->SetRootTransform(GetPrimaryDisplayRotationTransform());
 
   // Allow seeing through to the hardware video plane:
   window_tree_host_->compositor()->SetBackgroundColor(SK_ColorTRANSPARENT);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 07f0f12..b871a6a 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10289.0.0
\ No newline at end of file
+10292.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index d712533e..8b93ff5 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -360,6 +360,9 @@
 // Enables zip archiver - packer.
 const char kEnableZipArchiverPacker[] = "enable-zip-archiver-packer";
 
+// Disables zip archiver - packer.
+const char kDisableZipArchiverPacker[] = "disable-zip-archiver-packer";
+
 // Enables zip archiver - unpacker.
 const char kEnableZipArchiverUnpacker[] = "enable-zip-archiver-unpacker";
 
@@ -649,6 +652,12 @@
       kDisableZipArchiverUnpacker);
 }
 
+bool IsZipArchiverPackerEnabled() {
+  // Enabled by default.
+  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+      kDisableZipArchiverPacker);
+}
+
 bool IsSigninFrameClientCertsEnabled() {
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(
       kDisableSigninFrameClientCerts);
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 4e555ed..ceabdba 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -108,6 +108,7 @@
 CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[];
 CHROMEOS_EXPORT extern const char kEnableVoiceInteraction[];
 CHROMEOS_EXPORT extern const char kEnableZipArchiverPacker[];
+CHROMEOS_EXPORT extern const char kDisableZipArchiverPacker[];
 CHROMEOS_EXPORT extern const char kEnableZipArchiverUnpacker[];
 CHROMEOS_EXPORT extern const char kEnterpriseDisableArc[];
 CHROMEOS_EXPORT extern const char kEnterpriseDisableLicenseTypeSelection[];
@@ -186,6 +187,9 @@
 // Returns true if Zip Archiver is enabled for unpacking files.
 CHROMEOS_EXPORT bool IsZipArchiverUnpackerEnabled();
 
+// Returns true if Zip Archiver is enabled for packing files.
+CHROMEOS_EXPORT bool IsZipArchiverPackerEnabled();
+
 // Returns true if client certificate authentication for the sign-in frame on
 // the Chrome OS sign-in screen is enabled.
 CHROMEOS_EXPORT bool IsSigninFrameClientCertsEnabled();
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index 3ce91e5..daff6597 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -17,6 +17,11 @@
     "ArcNativeBridgeExperiment", base::FEATURE_ENABLED_BY_DEFAULT
 };
 
+// Controls ARC USB host integration.
+// When enabled, Android apps will be able to use usb host features.
+const base::Feature kUsbHostFeature{"ArcUsbHost",
+                                    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls ARC VPN integration.
 // When enabled, Chrome traffic will be routed through VPNs connected in
 // Android apps.
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index bf3108e..dcf16b4 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -14,6 +14,7 @@
 // Please keep alphabetized.
 extern const base::Feature kBootCompletedBroadcastFeature;
 extern const base::Feature kNativeBridgeExperimentFeature;
+extern const base::Feature kUsbHostFeature;
 extern const base::Feature kVpnFeature;
 
 }  // namespace arc
diff --git a/components/arc/usb/usb_host_bridge.cc b/components/arc/usb/usb_host_bridge.cc
index 5da8a8f..52d3b55 100644
--- a/components/arc/usb/usb_host_bridge.cc
+++ b/components/arc/usb/usb_host_bridge.cc
@@ -11,6 +11,7 @@
 #include "chromeos/dbus/permission_broker_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_features.h"
 #include "device/base/device_client.h"
 #include "device/usb/mojo/type_converters.h"
 #include "device/usb/usb_device_handle.h"
@@ -229,6 +230,11 @@
 }
 
 void ArcUsbHostBridge::OnDeviceChecked(const std::string& guid, bool allowed) {
+  if (!base::FeatureList::IsEnabled(arc::kUsbHostFeature)) {
+    VLOG(1) << "AndroidUSBHost: feature is disabled; ignoring";
+    return;
+  }
+
   if (!allowed)
     return;
 
diff --git a/components/cronet/android/test/javaperftests/run.py b/components/cronet/android/test/javaperftests/run.py
index cce6d7e..9b433eb 100755
--- a/components/cronet/android/test/javaperftests/run.py
+++ b/components/cronet/android/test/javaperftests/run.py
@@ -206,6 +206,11 @@
       results.AddValue(scalar.ScalarValue(results.current_page, test,
           'ms', jsonResults[test]))
 
+  def DidRunStory(self, platform, results):
+    # Skip parent implementation which calls into tracing_controller which this
+    # doesn't have.
+    pass
+
 
 class CronetPerfTestBenchmark(benchmark.Benchmark):
   # Benchmark implementation spawning off Cronet perf test measurement and
diff --git a/components/history/core/browser/expire_history_backend.cc b/components/history/core/browser/expire_history_backend.cc
index fbad60c..c0c17ea 100644
--- a/components/history/core/browser/expire_history_backend.cc
+++ b/components/history/core/browser/expire_history_backend.cc
@@ -12,11 +12,13 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/containers/flat_set.h"
 #include "base/feature_list.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/sequenced_task_runner.h"
 #include "components/history/core/browser/history_backend_client.h"
 #include "components/history/core/browser/history_backend_notifier.h"
@@ -262,18 +264,31 @@
   if (visits.empty())
     return;
 
+  base::TimeTicks start = base::TimeTicks::Now();
+
+  const VisitVector visits_and_redirects = GetVisitsAndRedirectParents(visits);
+  base::TimeDelta get_redirects_time = base::TimeTicks::Now() - start;
+
   DeleteEffects effects;
-  DeleteVisitRelatedInfo(visits, &effects);
+  DeleteVisitRelatedInfo(visits_and_redirects, &effects);
 
   // Delete or update the URLs affected. We want to update the visit counts
   // since this is called by the user who wants to delete their recent history,
   // and we don't want to leave any evidence.
-  ExpireURLsForVisits(visits, &effects);
+  ExpireURLsForVisits(visits_and_redirects, &effects);
   DeleteFaviconsIfPossible(&effects);
   BroadcastNotifications(&effects, DELETION_USER_INITIATED);
 
   // Pick up any bits possibly left over.
   ParanoidExpireHistory();
+
+  base::TimeDelta expire_visits_time = base::TimeTicks::Now() - start;
+  UMA_HISTOGRAM_TIMES("History.ExpireVisits.TotalDuration", expire_visits_time);
+  if (!expire_visits_time.is_zero()) {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "History.ExpireVisits.GetRedirectsDurationPercentage",
+        get_redirects_time * 100 / expire_visits_time);
+  }
 }
 
 void ExpireHistoryBackend::ExpireHistoryBefore(base::Time end_time) {
@@ -357,6 +372,24 @@
   }
 }
 
+VisitVector ExpireHistoryBackend::GetVisitsAndRedirectParents(
+    const VisitVector& visits) {
+  base::flat_set<VisitID> seen_visits;
+  VisitVector visits_and_redirects;
+  for (const auto v : visits) {
+    VisitRow current_visit = v;
+    do {
+      if (!seen_visits.insert(current_visit.visit_id).second)
+        break;
+
+      visits_and_redirects.push_back(current_visit);
+    } while (current_visit.referring_visit &&
+             main_db_->GetRowForVisit(current_visit.referring_visit,
+                                      &current_visit));
+  }
+  return visits_and_redirects;
+}
+
 void ExpireHistoryBackend::DeleteVisitRelatedInfo(const VisitVector& visits,
                                                   DeleteEffects* effects) {
   for (size_t i = 0; i < visits.size(); i++) {
diff --git a/components/history/core/browser/expire_history_backend.h b/components/history/core/browser/expire_history_backend.h
index 35785ae..24510db 100644
--- a/components/history/core/browser/expire_history_backend.h
+++ b/components/history/core/browser/expire_history_backend.h
@@ -149,6 +149,9 @@
     std::set<GURL> deleted_favicons;
   };
 
+  // Returns a vector with all visits that eventually redirect to |visits|.
+  VisitVector GetVisitsAndRedirectParents(const VisitVector& visits);
+
   // Deletes the visit-related stuff for all the visits in the given list, and
   // adds the rows for unique URLs affected to the affected_urls list in
   // the dependencies structure.
diff --git a/components/history/core/browser/expire_history_backend_unittest.cc b/components/history/core/browser/expire_history_backend_unittest.cc
index f478a9e..9854a29 100644
--- a/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/components/history/core/browser/expire_history_backend_unittest.cc
@@ -46,13 +46,31 @@
 namespace history {
 
 namespace {
+
+base::Time PretendNow() {
+  base::Time::Exploded exploded_reference_time;
+  exploded_reference_time.year = 2015;
+  exploded_reference_time.month = 1;
+  exploded_reference_time.day_of_month = 2;
+  exploded_reference_time.day_of_week = 5;
+  exploded_reference_time.hour = 11;
+  exploded_reference_time.minute = 0;
+  exploded_reference_time.second = 0;
+  exploded_reference_time.millisecond = 0;
+
+  base::Time out_time;
+  EXPECT_TRUE(
+      base::Time::FromLocalExploded(exploded_reference_time, &out_time));
+  return out_time;
+}
+
 // Returns whether |url| can be added to history.
 bool MockCanAddURLToHistory(const GURL& url) {
   return url.is_valid();
 }
 
 base::Time GetOldFaviconThreshold() {
-  return base::Time::Now() -
+  return PretendNow() -
          base::TimeDelta::FromDays(internal::kOnDemandFaviconIsOldAfterDays);
 }
 
@@ -67,7 +85,7 @@
         expirer_(this,
                  backend_client_.get(),
                  scoped_task_environment_.GetMainThreadTaskRunner()),
-        now_(base::Time::Now()) {}
+        now_(PretendNow()) {}
 
  protected:
   // Called by individual tests when they want data populated.
@@ -209,7 +227,7 @@
     return;
 
   // Four times for each visit.
-  visit_times[3] = base::Time::Now();
+  visit_times[3] = PretendNow();
   visit_times[2] = visit_times[3] - base::TimeDelta::FromDays(1);
   visit_times[1] = visit_times[3] - base::TimeDelta::FromDays(2);
   visit_times[0] = visit_times[3] - base::TimeDelta::FromDays(3);
@@ -243,7 +261,7 @@
 
   // Thumbnails for each URL.
   gfx::Image thumbnail = CreateGoogleThumbnailForTest();
-  ThumbnailScore score(0.25, true, true, base::Time::Now());
+  ThumbnailScore score(0.25, true, true, PretendNow());
 
   base::Time time;
   GURL gurl;
@@ -278,7 +296,7 @@
   if (!main_db_)
     return;
 
-  base::Time last_visit_time = base::Time::Now();
+  base::Time last_visit_time = PretendNow();
   // Add one URL.
   URLRow url_row1(url);
   url_row1.set_last_visit(last_visit_time);
@@ -1025,7 +1043,7 @@
       expirer_.GetAutoSubframeVisitsReader();
 
   VisitVector visits;
-  base::Time now = base::Time::Now();
+  base::Time now = PretendNow();
 
   // Verify that the early expiration threshold, stored in the meta table is
   // initialized.
@@ -1189,6 +1207,89 @@
   EXPECT_EQ(icon_id, icon_mapping[1].icon_id);
 }
 
+// Test that all visits that are redirect parents of specified visits are also
+// removed. See crbug.com/786878.
+TEST_F(ExpireHistoryTest, DeleteVisitAndRedirects) {
+  // Set up the example data.
+  base::Time now = PretendNow();
+  URLRow url_row1(GURL("http://google.com/1"));
+  url_row1.set_last_visit(now - base::TimeDelta::FromDays(1));
+  url_row1.set_visit_count(1);
+  URLID url1 = main_db_->AddURL(url_row1);
+
+  URLRow url_row2(GURL("http://www.google.com/1"));
+  url_row2.set_last_visit(now);
+  url_row2.set_visit_count(1);
+  URLID url2 = main_db_->AddURL(url_row2);
+
+  // Add a visit to "http://google.com/1" that is redirected to
+  // "http://www.google.com/1".
+  VisitRow visit_row1;
+  visit_row1.url_id = url1;
+  visit_row1.visit_time = now - base::TimeDelta::FromDays(1);
+  main_db_->AddVisit(&visit_row1, SOURCE_BROWSED);
+
+  VisitRow visit_row2;
+  visit_row2.url_id = url2;
+  visit_row2.visit_time = now;
+  visit_row2.referring_visit = visit_row1.visit_id;
+  main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
+
+  // Expiring visit_row2 should also expire visit_row1 which is its redirect
+  // parent.
+  expirer_.ExpireVisits({visit_row2});
+
+  VisitRow v;
+  EXPECT_FALSE(main_db_->GetRowForVisit(visit_row1.visit_id, &v));
+  EXPECT_FALSE(main_db_->GetRowForVisit(visit_row2.visit_id, &v));
+  URLRow u;
+  EXPECT_FALSE(main_db_->GetURLRow(url1, &u));
+  EXPECT_FALSE(main_db_->GetURLRow(url2, &u));
+}
+
+// Test that loops in redirect parents are handled. See crbug.com/798234.
+TEST_F(ExpireHistoryTest, DeleteVisitAndRedirectsWithLoop) {
+  // Set up the example data.
+  base::Time now = PretendNow();
+  URLRow url_row1(GURL("http://google.com/1"));
+  url_row1.set_last_visit(now - base::TimeDelta::FromDays(1));
+  url_row1.set_visit_count(1);
+  URLID url1 = main_db_->AddURL(url_row1);
+
+  URLRow url_row2(GURL("http://www.google.com/1"));
+  url_row2.set_last_visit(now);
+  url_row2.set_visit_count(1);
+  URLID url2 = main_db_->AddURL(url_row2);
+
+  // Add a visit to "http://google.com/1" that is redirected to
+  // "http://www.google.com/1".
+  VisitRow visit_row1;
+  visit_row1.url_id = url1;
+  visit_row1.visit_time = now - base::TimeDelta::FromDays(1);
+  main_db_->AddVisit(&visit_row1, SOURCE_BROWSED);
+
+  VisitRow visit_row2;
+  visit_row2.url_id = url2;
+  visit_row2.visit_time = now;
+  visit_row2.referring_visit = visit_row1.visit_id;
+  main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
+
+  // Set the first visit to be redirect parented to the second visit.
+  visit_row1.referring_visit = visit_row2.visit_id;
+  main_db_->UpdateVisitRow(visit_row1);
+
+  // Expiring visit_row2 should also expire visit_row1 which is its redirect
+  // parent, without infinite looping.
+  expirer_.ExpireVisits({visit_row2});
+
+  VisitRow v;
+  EXPECT_FALSE(main_db_->GetRowForVisit(visit_row1.visit_id, &v));
+  EXPECT_FALSE(main_db_->GetRowForVisit(visit_row2.visit_id, &v));
+  URLRow u;
+  EXPECT_FALSE(main_db_->GetURLRow(url1, &u));
+  EXPECT_FALSE(main_db_->GetURLRow(url2, &u));
+}
+
 // TODO(brettw) add some visits with no URL to make sure everything is updated
 // properly. Have the visits also refer to nonexistent FTS rows.
 //
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
index 31e63dc9..49a84fa 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
@@ -132,11 +132,12 @@
   }
 
   OAuth2TokenService::ScopeSet scopes = {kContentSuggestionsApiScope};
-  access_token_fetcher_ =
-      std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
-          "ntp_snippets", signin_manager_, access_token_service_, scopes,
-          base::BindOnce(&SubscriptionManagerImpl::AccessTokenFetchFinished,
-                         base::Unretained(this), subscription_token));
+  access_token_fetcher_ = std::make_unique<
+      identity::PrimaryAccountAccessTokenFetcher>(
+      "ntp_snippets", signin_manager_, access_token_service_, scopes,
+      base::BindOnce(&SubscriptionManagerImpl::AccessTokenFetchFinished,
+                     base::Unretained(this), subscription_token),
+      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 }
 
 void SubscriptionManagerImpl::AccessTokenFetchFinished(
diff --git a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
index 4dc5768..cd45f38 100644
--- a/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
@@ -174,7 +174,8 @@
       "ntp_snippets", signin_manager_, token_service_, scopes,
       base::BindOnce(
           &ContextualSuggestionsFetcherImpl::AccessTokenFetchFinished,
-          base::Unretained(this)));
+          base::Unretained(this)),
+      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 }
 
 void ContextualSuggestionsFetcherImpl::AccessTokenFetchFinished(
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
index 1d5a62f9..1a83031e 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
@@ -237,7 +237,8 @@
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "ntp_snippets", signin_manager_, token_service_, scopes,
       base::BindOnce(&RemoteSuggestionsFetcherImpl::AccessTokenFetchFinished,
-                     base::Unretained(this)));
+                     base::Unretained(this)),
+      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 }
 
 void RemoteSuggestionsFetcherImpl::AccessTokenFetchFinished(
diff --git a/components/ntp_snippets_strings.grdp b/components/ntp_snippets_strings.grdp
index 672811e..ab1517ce 100644
--- a/components/ntp_snippets_strings.grdp
+++ b/components/ntp_snippets_strings.grdp
@@ -1,14 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <grit-part>
 
-  <if expr="is_android">
-    <message name="IDS_SNIPPETS_DISABLED_SIGNED_OUT_INSTRUCTIONS" desc="Body of the card explaining the status of the content suggestions on the New Tab Page, when the user is signed out." formatter_data="android_java">
-      To get personalized content suggested by Google, sign in to Chrome.
-    </message>
-    <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get personalized content suggestions on the New Tab Page." formatter_data="android_java">
-      Get personalized content
-    </message>
-  </if>
   <if expr="is_android or is_ios">
     <message name="IDS_NTP_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title text explaining there is no content." formatter_data="android_java">
       That’s all for now
diff --git a/components/offline_pages/core/model/delete_page_task.cc b/components/offline_pages/core/model/delete_page_task.cc
index 6c50521..36a487c 100644
--- a/components/offline_pages/core/model/delete_page_task.cc
+++ b/components/offline_pages/core/model/delete_page_task.cc
@@ -81,12 +81,12 @@
   base::Time delete_time = base::Time::Now();
   for (const auto& info_wrapper : info_wrappers) {
     base::UmaHistogramCustomCounts(
-        model_utils::AddHistogramSuffix(info_wrapper.client_id,
+        model_utils::AddHistogramSuffix(info_wrapper.client_id.name_space,
                                         "OfflinePages.PageLifetime"),
         (delete_time - info_wrapper.creation_time).InMinutes(), 1, max_minutes,
         100);
     base::UmaHistogramCustomCounts(
-        model_utils::AddHistogramSuffix(info_wrapper.client_id,
+        model_utils::AddHistogramSuffix(info_wrapper.client_id.name_space,
                                         "OfflinePages.AccessCount"),
         info_wrapper.access_count, 1, 1000000, 50);
   }
diff --git a/components/offline_pages/core/model/delete_page_task_unittest.cc b/components/offline_pages/core/model/delete_page_task_unittest.cc
index 75974ae5..b357d6f 100644
--- a/components/offline_pages/core/model/delete_page_task_unittest.cc
+++ b/components/offline_pages/core/model/delete_page_task_unittest.cc
@@ -170,19 +170,19 @@
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_TRUE(CheckPageDeleted(page3));
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       2);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       2);
   histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0, 1);
   histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       200, 1);
 }
@@ -215,11 +215,11 @@
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_FALSE(CheckPageDeleted(page3));
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0);
 }
@@ -252,19 +252,19 @@
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_TRUE(CheckPageDeleted(page3));
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       2);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       2);
   histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0, 1);
   histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       200, 1);
 }
@@ -293,11 +293,11 @@
   EXPECT_EQ(0UL, last_deleted_page_infos().size());
   EXPECT_EQ(3LL, store_test_util()->GetPageCount());
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0);
 }
@@ -336,19 +336,19 @@
   EXPECT_EQ(predicate.Run(page2.url), CheckPageDeleted(page2));
   EXPECT_EQ(predicate.Run(page3.url), CheckPageDeleted(page3));
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       2);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       2);
   histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0, 1);
   histogram_tester()->ExpectBucketCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       200, 1);
 }
@@ -385,11 +385,11 @@
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_FALSE(CheckPageDeleted(page3));
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0);
 }
@@ -427,11 +427,11 @@
   EXPECT_FALSE(CheckPageDeleted(page2));
   EXPECT_FALSE(CheckPageDeleted(page3));
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0, 1);
 }
@@ -464,11 +464,11 @@
   EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
   EXPECT_EQ(0UL, last_deleted_page_infos().size());
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       0);
 }
diff --git a/components/offline_pages/core/model/mark_page_accessed_task.cc b/components/offline_pages/core/model/mark_page_accessed_task.cc
index d807145..a82afd6c 100644
--- a/components/offline_pages/core/model/mark_page_accessed_task.cc
+++ b/components/offline_pages/core/model/mark_page_accessed_task.cc
@@ -5,6 +5,7 @@
 #include "components/offline_pages/core/model/mark_page_accessed_task.h"
 
 #include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/offline_pages/core/client_namespace_constants.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
@@ -20,20 +21,35 @@
 
 #define OFFLINE_PAGES_TABLE_NAME "offlinepages_v1"
 
-void ReportAccessHistogram(int64_t offline_id, sql::Connection* db) {
-  const char kSql[] = "SELECT client_namespace FROM " OFFLINE_PAGES_TABLE_NAME
-                      " WHERE offline_id = ?";
+void ReportAccessHistogram(int64_t offline_id,
+                           base::Time access_time,
+                           sql::Connection* db) {
+  // Used as upper bound of PageAccessInterval histogram which is used for
+  // evaluating how good the expiration period is. The expiration period of a
+  // page will be longer than one year in extreme cases so it's good enough.
+  const int kMinutesPerYear = base::TimeDelta::FromDays(365).InMinutes();
+
+  const char kSql[] =
+      "SELECT client_namespace, last_access_time FROM " OFFLINE_PAGES_TABLE_NAME
+      " WHERE offline_id = ?";
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt64(0, offline_id);
   if (statement.Step()) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "OfflinePages.AccessPageCount",
-        model_utils::ToNamespaceEnum(statement.ColumnString(0)),
-        OfflinePagesNamespaceEnumeration::RESULT_COUNT);
+    std::string name_space = statement.ColumnString(0);
+    UMA_HISTOGRAM_ENUMERATION("OfflinePages.AccessPageCount",
+                              model_utils::ToNamespaceEnum(name_space),
+                              OfflinePagesNamespaceEnumeration::RESULT_COUNT);
+
+    base::Time last_access_time =
+        store_utils::FromDatabaseTime(statement.ColumnInt64(1));
+    base::UmaHistogramCustomCounts(
+        model_utils::AddHistogramSuffix(name_space,
+                                        "OfflinePages.PageAccessInterval"),
+        (access_time - last_access_time).InMinutes(), 1, kMinutesPerYear, 100);
   }
 }
 
-bool MarkPageAccessedSync(const base::Time& last_access_time,
+bool MarkPageAccessedSync(const base::Time& access_time,
                           int64_t offline_id,
                           sql::Connection* db) {
   if (!db)
@@ -43,14 +59,14 @@
   if (!transaction.Begin())
     return false;
 
-  ReportAccessHistogram(offline_id, db);
+  ReportAccessHistogram(offline_id, access_time, db);
 
   const char kSql[] =
       "UPDATE OR IGNORE " OFFLINE_PAGES_TABLE_NAME
       " SET last_access_time = ?, access_count = access_count + 1"
       " WHERE offline_id = ?";
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
-  statement.BindInt64(0, store_utils::ToDatabaseTime(last_access_time));
+  statement.BindInt64(0, store_utils::ToDatabaseTime(access_time));
   statement.BindInt64(1, offline_id);
   if (!statement.Run())
     return false;
diff --git a/components/offline_pages/core/model/mark_page_accessed_task_unittest.cc b/components/offline_pages/core/model/mark_page_accessed_task_unittest.cc
index d307c75b..8caa7ff9 100644
--- a/components/offline_pages/core/model/mark_page_accessed_task_unittest.cc
+++ b/components/offline_pages/core/model/mark_page_accessed_task_unittest.cc
@@ -88,6 +88,10 @@
       "OfflinePages.AccessPageCount",
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId.name_space)),
       1);
+  histogram_tester()->ExpectUniqueSample(
+      model_utils::AddHistogramSuffix(kTestClientId.name_space,
+                                      "OfflinePages.PageAccessInterval"),
+      (current_time - page.last_access_time).InMinutes(), 1);
 }
 
 TEST_F(MarkPageAccessedTaskTest, MarkPageAccessedTwice) {
@@ -111,19 +115,28 @@
       "OfflinePages.AccessPageCount",
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId.name_space)),
       1);
+  histogram_tester()->ExpectUniqueSample(
+      model_utils::AddHistogramSuffix(kTestClientId.name_space,
+                                      "OfflinePages.PageAccessInterval"),
+      (current_time - page.last_access_time).InMinutes(), 1);
 
+  base::Time second_time = base::Time::Now();
   task = std::make_unique<MarkPageAccessedTask>(store(), kTestOfflineId,
-                                                base::Time::Now());
+                                                second_time);
   runner()->RunTask(std::move(task));
 
   offline_page = store_test_util()->GetPageByOfflineId(kTestOfflineId);
   EXPECT_EQ(kTestOfflineId, offline_page->offline_id);
   EXPECT_EQ(2, offline_page->access_count);
-  EXPECT_LT(current_time, offline_page->last_access_time);
+  EXPECT_EQ(second_time, offline_page->last_access_time);
   histogram_tester()->ExpectUniqueSample(
       "OfflinePages.AccessPageCount",
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId.name_space)),
       2);
+  histogram_tester()->ExpectBucketCount(
+      model_utils::AddHistogramSuffix(kTestClientId.name_space,
+                                      "OfflinePages.PageAccessInterval"),
+      (second_time - current_time).InMinutes(), 1);
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index adcb2f054..1537af06 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -93,14 +93,14 @@
     const OfflinePageItem& offline_page,
     const base::Time& save_time) {
   base::UmaHistogramCustomTimes(
-      model_utils::AddHistogramSuffix(offline_page.client_id,
+      model_utils::AddHistogramSuffix(offline_page.client_id.name_space,
                                       "OfflinePages.SavePageTime"),
       save_time - offline_page.creation_time,
       base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(10),
       50);
 
   base::UmaHistogramCustomCounts(
-      model_utils::AddHistogramSuffix(offline_page.client_id,
+      model_utils::AddHistogramSuffix(offline_page.client_id.name_space,
                                       "OfflinePages.PageSize"),
       offline_page.file_size / 1024, 1, 10000, 50);
 }
@@ -342,7 +342,8 @@
                             model_utils::ToNamespaceEnum(client_id.name_space),
                             OfflinePagesNamespaceEnumeration::RESULT_COUNT);
   base::UmaHistogramEnumeration(
-      model_utils::AddHistogramSuffix(client_id, "OfflinePages.SavePageResult"),
+      model_utils::AddHistogramSuffix(client_id.name_space,
+                                      "OfflinePages.SavePageResult"),
       result, SavePageResult::RESULT_COUNT);
 
   if (result == SavePageResult::ARCHIVE_CREATION_FAILED)
@@ -503,6 +504,12 @@
     base::Time start_time,
     size_t deleted_page_count,
     ClearStorageResult result) {
+  UMA_HISTOGRAM_ENUMERATION("OfflinePages.ClearTemporaryPages.Result", result,
+                            ClearStorageResult::RESULT_COUNT);
+  if (deleted_page_count > 0) {
+    UMA_HISTOGRAM_COUNTS("OfflinePages.ClearTemporaryPages.BatchSize",
+                         deleted_page_count);
+  }
   last_clear_cached_pages_time_ = start_time;
 }
 
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index b2eb51b..02f382b 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/offline_pages/core/client_namespace_constants.h"
+#include "components/offline_pages/core/model/clear_storage_task.h"
 #include "components/offline_pages/core/model/offline_page_item_generator.h"
 #include "components/offline_pages/core/model/offline_page_model_utils.h"
 #include "components/offline_pages/core/model/offline_page_test_utils.h"
@@ -45,6 +46,7 @@
 namespace offline_pages {
 
 using ArchiverResult = OfflinePageArchiver::ArchiverResult;
+using ClearStorageResult = ClearStorageTask::ClearStorageResult;
 
 namespace {
 const GURL kTestUrl("http://example.com");
@@ -116,9 +118,6 @@
   std::unique_ptr<OfflinePageTestArchiver> BuildArchiver(const GURL& url,
                                                          ArchiverResult result);
   void CheckTaskQueueIdle();
-  void SetTestingClock(std::unique_ptr<base::Clock> clock) {
-    model_->clock_ = std::move(clock);
-  }
 
   // Getters for private fields.
   base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
@@ -335,14 +334,15 @@
           model_utils::ToNamespaceEnum(saved_page_ptr->client_id.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::SUCCESS), 1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       kTestFileSize / 1024, 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       1);
 }
@@ -370,14 +370,15 @@
           model_utils::ToNamespaceEnum(saved_page_ptr->client_id.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::SUCCESS), 1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       kTestFileSize / 1024, 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       1);
 }
@@ -410,14 +411,15 @@
           model_utils::ToNamespaceEnum(saved_page_ptr->client_id.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::SUCCESS), 1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       kTestFileSize / 1024, 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       1);
 }
@@ -433,14 +435,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::CANCELLED), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       0);
 }
@@ -456,14 +459,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::DEVICE_FULL), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       0);
 }
@@ -481,14 +485,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::CONTENT_UNAVAILABLE), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       0);
 }
@@ -505,14 +510,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::ARCHIVE_CREATION_FAILED), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       0);
 }
@@ -529,14 +535,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::ARCHIVE_CREATION_FAILED), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       0);
 }
@@ -557,14 +564,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       1);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::SKIPPED), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       0);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       0);
 }
@@ -639,14 +647,15 @@
       static_cast<int>(model_utils::ToNamespaceEnum(kTestClientId1.name_space)),
       2);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::SUCCESS), 2);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1, "OfflinePages.PageSize"),
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
+                                      "OfflinePages.PageSize"),
       kTestFileSize / 1024, 2);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageTime"),
       2);
 }
@@ -677,7 +686,7 @@
                              kEmptyRequestOrigin, nullptr,
                              SavePageResult::CONTENT_UNAVAILABLE);
   histogram_tester()->ExpectUniqueSample(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.SavePageResult"),
       static_cast<int>(SavePageResult::CONTENT_UNAVAILABLE), 1);
 }
@@ -784,11 +793,11 @@
       "OfflinePages.DeletePageResult",
       static_cast<int>(DeletePageResult::SUCCESS), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       1);
 }
@@ -831,11 +840,11 @@
       "OfflinePages.DeletePageResult",
       static_cast<int>(DeletePageResult::SUCCESS), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.PageLifetime"),
       1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(page1.client_id,
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
                                       "OfflinePages.AccessCount"),
       1);
 }
@@ -1034,11 +1043,11 @@
       "OfflinePages.DeletePageResult",
       static_cast<int>(DeletePageResult::SUCCESS), 1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.PageLifetime"),
       1);
   histogram_tester()->ExpectTotalCount(
-      model_utils::AddHistogramSuffix(kTestClientId1,
+      model_utils::AddHistogramSuffix(kTestClientId1.name_space,
                                       "OfflinePages.AccessCount"),
       1);
 }
@@ -1279,7 +1288,6 @@
   ResetModel();
   BuildStore();
   BuildModel();
-  SetTestingClock(task_runner()->GetMockClock());
 
   PumpLoop();
   EXPECT_EQ(task_runner()->Now(), last_clear_page_time());
@@ -1303,6 +1311,11 @@
       std::move(archiver), SavePageResult::SUCCESS);
   PumpLoop();
   EXPECT_EQ(task_runner()->Now(), last_clear_page_time());
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.ClearTemporaryPages.Result",
+      static_cast<int>(ClearStorageResult::UNNECESSARY), 2);
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.ClearTemporaryPages.BatchSize", 0);
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/model/offline_page_model_utils.cc b/components/offline_pages/core/model/offline_page_model_utils.cc
index b517a63..2ef665a 100644
--- a/components/offline_pages/core/model/offline_page_model_utils.cc
+++ b/components/offline_pages/core/model/offline_page_model_utils.cc
@@ -39,15 +39,15 @@
   return OfflinePagesNamespaceEnumeration::DEFAULT;
 }
 
-std::string AddHistogramSuffix(const ClientId& client_id,
+std::string AddHistogramSuffix(const std::string& name_space,
                                const char* histogram_name) {
-  if (client_id.name_space.empty()) {
+  if (name_space.empty()) {
     NOTREACHED();
     return histogram_name;
   }
   std::string adjusted_histogram_name(histogram_name);
   adjusted_histogram_name += ".";
-  adjusted_histogram_name += client_id.name_space;
+  adjusted_histogram_name += name_space;
   return adjusted_histogram_name;
 }
 
diff --git a/components/offline_pages/core/model/offline_page_model_utils.h b/components/offline_pages/core/model/offline_page_model_utils.h
index 671e34f7..17c145bb 100644
--- a/components/offline_pages/core/model/offline_page_model_utils.h
+++ b/components/offline_pages/core/model/offline_page_model_utils.h
@@ -10,7 +10,6 @@
 namespace offline_pages {
 
 enum class OfflinePagesNamespaceEnumeration;
-struct ClientId;
 
 namespace model_utils {
 
@@ -18,7 +17,7 @@
 OfflinePagesNamespaceEnumeration ToNamespaceEnum(const std::string& name_space);
 
 // Metric collection related.
-std::string AddHistogramSuffix(const ClientId& client_id,
+std::string AddHistogramSuffix(const std::string& name_space,
                                const char* histogram_name);
 
 }  // namespace model_utils
diff --git a/components/omnibox/browser/contextual_suggestions_service.cc b/components/omnibox/browser/contextual_suggestions_service.cc
index 7afc5b0..df4bd82 100644
--- a/components/omnibox/browser/contextual_suggestions_service.cc
+++ b/components/omnibox/browser/contextual_suggestions_service.cc
@@ -302,7 +302,8 @@
       "contextual_suggestions_service", signin_manager_, token_service_, scopes,
       base::BindOnce(&ContextualSuggestionsService::AccessTokenAvailable,
                      base::Unretained(this), std::move(fetcher),
-                     std::move(callback)));
+                     std::move(callback)),
+      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 }
 
 void ContextualSuggestionsService::AccessTokenAvailable(
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
index e383db9e..9a1e4ef 100644
--- a/components/safe_browsing/features.h
+++ b/components/safe_browsing/features.h
@@ -49,5 +49,5 @@
 
 base::ListValue GetFeatureStatusList();
 
-#endif  // COMPONENTS_SAFE_BROWSING_FEATURES_H_
 }  // namespace safe_browsing
+#endif  // COMPONENTS_SAFE_BROWSING_FEATURES_H_
diff --git a/components/suggestions/suggestions_service_impl.cc b/components/suggestions/suggestions_service_impl.cc
index 341c75fe..245bcc0 100644
--- a/components/suggestions/suggestions_service_impl.cc
+++ b/components/suggestions/suggestions_service_impl.cc
@@ -404,7 +404,8 @@
   token_fetcher_ = base::MakeUnique<identity::PrimaryAccountAccessTokenFetcher>(
       "suggestions_service", signin_manager_, token_service_, scopes,
       base::BindOnce(&SuggestionsServiceImpl::AccessTokenAvailable,
-                     base::Unretained(this), url));
+                     base::Unretained(this), url),
+      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 }
 
 void SuggestionsServiceImpl::AccessTokenAvailable(
diff --git a/components/translate/core/browser/translate_url_fetcher.cc b/components/translate/core/browser/translate_url_fetcher.cc
index 1be65d1f..2d56fb3 100644
--- a/components/translate/core/browser/translate_url_fetcher.cc
+++ b/components/translate/core/browser/translate_url_fetcher.cc
@@ -86,16 +86,10 @@
             "downloaded regardless of the settings."
           chrome_policy {
             TranslateEnabled {
-              policy_options {mode: MANDATORY}
               TranslateEnabled: false
             }
           }
-        }
-        comments:
-          "There is no policy for disabling download of the list of "
-          "supported languages. It is considered not required as the list is "
-          "needed for rendering user interfaces, and Chrome does not send "
-          "privacy/security sensitive data to the server on downloading it.")");
+        })");
   // Create and initialize the URL fetcher.
   fetcher_ = net::URLFetcher::Create(id_, url_, net::URLFetcher::GET, this,
                                      traffic_annotation);
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 7c5c867b..7f24bdf 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -10,8 +10,13 @@
 
 namespace features {
 
+#if defined(USE_AURA)
+const base::Feature kEnableSurfaceSynchronization{
+    "SurfaceSynchronization", base::FEATURE_ENABLED_BY_DEFAULT};
+#else
 const base::Feature kEnableSurfaceSynchronization{
     "SurfaceSynchronization", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
 
 bool IsSurfaceSynchronizationEnabled() {
   auto* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/content/browser/DEPS b/content/browser/DEPS
index b1fa91a..51bc3a3 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -101,6 +101,7 @@
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h",
   "+third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h",
   "+third_party/WebKit/public/public_features.h",
+  "+third_party/WebKit/public/web/devtools_agent.mojom.h",
   "+third_party/WebKit/public/web/devtools_frontend.mojom.h",
   "+third_party/WebKit/public/web/WebAXEnums.h",
   "+third_party/WebKit/public/web/WebConsoleMessage.h",
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 10fa790..931f3a7f9 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -148,19 +148,18 @@
   return parameters;
 }
 
-void OnSyncEventFinished(
-    scoped_refptr<ServiceWorkerVersion> active_version,
-    int request_id,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback,
-    blink::mojom::ServiceWorkerEventStatus status,
-    base::Time dispatch_event_time) {
+void OnSyncEventFinished(scoped_refptr<ServiceWorkerVersion> active_version,
+                         int request_id,
+                         ServiceWorkerVersion::StatusCallback callback,
+                         blink::mojom::ServiceWorkerEventStatus status,
+                         base::Time dispatch_event_time) {
   if (!active_version->FinishRequest(
           request_id,
           status == blink::mojom::ServiceWorkerEventStatus::COMPLETED,
           dispatch_event_time)) {
     return;
   }
-  callback.Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status));
+  std::move(callback).Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status));
 }
 
 }  // namespace
@@ -268,9 +267,10 @@
     const std::string& tag,
     scoped_refptr<ServiceWorkerVersion> active_version,
     bool last_chance,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
+    ServiceWorkerVersion::StatusCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DispatchSyncEvent(tag, std::move(active_version), last_chance, callback);
+  DispatchSyncEvent(tag, std::move(active_version), last_chance,
+                    std::move(callback));
 }
 
 BackgroundSyncManager::BackgroundSyncManager(
@@ -544,11 +544,11 @@
                         sw_registration->pattern().GetOrigin(),
                         new_registration);
 
-  StoreRegistrations(sw_registration_id,
-                     base::AdaptCallbackForRepeating(base::BindOnce(
-                         &BackgroundSyncManager::RegisterDidStore,
-                         weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
-                         new_registration, std::move(callback))));
+  StoreRegistrations(
+      sw_registration_id,
+      base::BindOnce(&BackgroundSyncManager::RegisterDidStore,
+                     weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
+                     new_registration, std::move(callback)));
 }
 
 void BackgroundSyncManager::DisableAndClearManager(base::OnceClosure callback) {
@@ -757,29 +757,31 @@
     const std::string& tag,
     scoped_refptr<ServiceWorkerVersion> active_version,
     bool last_chance,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
+    ServiceWorkerVersion::StatusCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(active_version);
 
+  auto repeating_callback =
+      base::AdaptCallbackForRepeating(std::move(callback));
   if (active_version->running_status() != EmbeddedWorkerStatus::RUNNING) {
     active_version->RunAfterStartWorker(
         ServiceWorkerMetrics::EventType::SYNC,
         base::BindOnce(&BackgroundSyncManager::DispatchSyncEvent,
                        weak_ptr_factory_.GetWeakPtr(), tag, active_version,
-                       last_chance, callback),
-        callback);
+                       last_chance, repeating_callback),
+        repeating_callback);
     return;
   }
 
   int request_id = active_version->StartRequestWithCustomTimeout(
-      ServiceWorkerMetrics::EventType::SYNC, callback,
+      ServiceWorkerMetrics::EventType::SYNC, repeating_callback,
       parameters_->max_sync_event_duration,
       ServiceWorkerVersion::CONTINUE_ON_TIMEOUT);
 
   active_version->event_dispatcher()->DispatchSyncEvent(
       tag, last_chance,
       base::BindOnce(&OnSyncEventFinished, std::move(active_version),
-                     request_id, callback));
+                     request_id, repeating_callback));
 }
 
 void BackgroundSyncManager::ScheduleDelayedTask(base::OnceClosure callback,
@@ -1000,13 +1002,13 @@
       service_worker_registration->pattern().GetOrigin(),
       base::BindOnce(&BackgroundSyncMetrics::RecordEventStarted));
 
-  DispatchSyncEvent(
-      registration->options()->tag,
-      service_worker_registration->active_version(), last_chance,
-      base::AdaptCallbackForRepeating(base::BindOnce(
-          &BackgroundSyncManager::EventComplete, weak_ptr_factory_.GetWeakPtr(),
-          service_worker_registration, service_worker_registration->id(), tag,
-          std::move(event_completed_callback))));
+  DispatchSyncEvent(registration->options()->tag,
+                    service_worker_registration->active_version(), last_chance,
+                    base::BindOnce(&BackgroundSyncManager::EventComplete,
+                                   weak_ptr_factory_.GetWeakPtr(),
+                                   service_worker_registration,
+                                   service_worker_registration->id(), tag,
+                                   std::move(event_completed_callback)));
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, std::move(event_fired_callback));
@@ -1110,11 +1112,11 @@
     }
   }
 
-  StoreRegistrations(service_worker_id,
-                     base::AdaptCallbackForRepeating(base::BindOnce(
-                         &BackgroundSyncManager::EventCompleteDidStore,
-                         weak_ptr_factory_.GetWeakPtr(), service_worker_id,
-                         std::move(callback))));
+  StoreRegistrations(
+      service_worker_id,
+      base::BindOnce(&BackgroundSyncManager::EventCompleteDidStore,
+                     weak_ptr_factory_.GetWeakPtr(), service_worker_id,
+                     std::move(callback)));
 }
 
 void BackgroundSyncManager::EventCompleteDidStore(
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index f91a47f..b7e6741b 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -105,7 +105,7 @@
       const std::string& tag,
       scoped_refptr<ServiceWorkerVersion> active_version,
       bool last_chance,
-      const ServiceWorkerVersion::LegacyStatusCallback& callback);
+      ServiceWorkerVersion::StatusCallback callback);
 
  protected:
   explicit BackgroundSyncManager(
@@ -128,7 +128,7 @@
       const std::string& tag,
       scoped_refptr<ServiceWorkerVersion> active_version,
       bool last_chance,
-      const ServiceWorkerVersion::LegacyStatusCallback& callback);
+      ServiceWorkerVersion::StatusCallback callback);
   virtual void ScheduleDelayedTask(base::OnceClosure callback,
                                    base::TimeDelta delay);
   virtual void HasMainFrameProviderHost(const GURL& origin,
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 32231c7..8c74e84 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -14,10 +14,10 @@
 #include "base/containers/flat_set.h"
 #include "content/browser/devtools/devtools_io_context.h"
 #include "content/common/content_export.h"
-#include "content/common/devtools.mojom.h"
 #include "content/common/devtools_messages.h"
 #include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/devtools_agent_host.h"
+#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
 
 namespace content {
 
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 2bb5a73..43460c3 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -67,8 +67,8 @@
 }
 
 void DevToolsSession::AttachToAgent(
-    const mojom::DevToolsAgentAssociatedPtr& agent) {
-  mojom::DevToolsSessionHostAssociatedPtrInfo host_ptr_info;
+    const blink::mojom::DevToolsAgentAssociatedPtr& agent) {
+  blink::mojom::DevToolsSessionHostAssociatedPtrInfo host_ptr_info;
   binding_.Bind(mojo::MakeRequest(&host_ptr_info));
   agent->AttachDevToolsSession(
       std::move(host_ptr_info), mojo::MakeRequest(&session_ptr_),
@@ -78,8 +78,8 @@
 }
 
 void DevToolsSession::ReattachToAgent(
-    const mojom::DevToolsAgentAssociatedPtr& agent) {
-  mojom::DevToolsSessionHostAssociatedPtrInfo host_ptr_info;
+    const blink::mojom::DevToolsAgentAssociatedPtr& agent) {
+  blink::mojom::DevToolsSessionHostAssociatedPtrInfo host_ptr_info;
   binding_.Bind(mojo::MakeRequest(&host_ptr_info));
   agent->AttachDevToolsSession(
       std::move(host_ptr_info), mojo::MakeRequest(&session_ptr_),
@@ -195,7 +195,7 @@
 }
 
 void DevToolsSession::DispatchProtocolMessage(
-    mojom::DevToolsMessageChunkPtr chunk) {
+    blink::mojom::DevToolsMessageChunkPtr chunk) {
   if (chunk->is_first) {
     if (response_message_buffer_size_ != 0) {
       ReceivedBadMessage();
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index 24de333..0e33319 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -13,8 +13,8 @@
 #include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/protocol.h"
-#include "content/common/devtools.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
 
 namespace content {
 
@@ -22,7 +22,7 @@
 class RenderFrameHostImpl;
 
 class DevToolsSession : public protocol::FrontendChannel,
-                        public mojom::DevToolsSessionHost {
+                        public blink::mojom::DevToolsSessionHost {
  public:
   DevToolsSession(DevToolsAgentHostImpl* agent_host,
                   DevToolsAgentHostClient* client,
@@ -35,8 +35,8 @@
   void SetRenderer(RenderProcessHost* process_host,
                    RenderFrameHostImpl* frame_host);
   void SetFallThroughForNotFound(bool value);
-  void AttachToAgent(const mojom::DevToolsAgentAssociatedPtr& agent);
-  void ReattachToAgent(const mojom::DevToolsAgentAssociatedPtr& agent);
+  void AttachToAgent(const blink::mojom::DevToolsAgentAssociatedPtr& agent);
+  void ReattachToAgent(const blink::mojom::DevToolsAgentAssociatedPtr& agent);
 
   struct Message {
     std::string method;
@@ -84,12 +84,13 @@
       std::unique_ptr<protocol::Serializable> message) override;
   void flushProtocolNotifications() override;
 
-  // mojom::DevToolsSessionHost implementation.
-  void DispatchProtocolMessage(mojom::DevToolsMessageChunkPtr chunk) override;
+  // blink::mojom::DevToolsSessionHost implementation.
+  void DispatchProtocolMessage(
+      blink::mojom::DevToolsMessageChunkPtr chunk) override;
 
-  mojo::AssociatedBinding<mojom::DevToolsSessionHost> binding_;
-  mojom::DevToolsSessionAssociatedPtr session_ptr_;
-  mojom::DevToolsSessionPtr io_session_ptr_;
+  mojo::AssociatedBinding<blink::mojom::DevToolsSessionHost> binding_;
+  blink::mojom::DevToolsSessionAssociatedPtr session_ptr_;
+  blink::mojom::DevToolsSessionPtr io_session_ptr_;
   DevToolsAgentHostImpl* agent_host_;
   DevToolsAgentHostClient* client_;
   int session_id_;
diff --git a/content/browser/devtools/protocol/service_worker_handler.cc b/content/browser/devtools/protocol/service_worker_handler.cc
index 3e7c32f8..64dff1f 100644
--- a/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/content/browser/devtools/protocol/service_worker_handler.cc
@@ -138,7 +138,7 @@
   // Keep the registration while dispatching the sync event.
   background_sync_manager->EmulateDispatchSyncEvent(
       tag, std::move(version), last_chance,
-      base::Bind(&StatusNoOpKeepingRegistration, std::move(registration)));
+      base::BindOnce(&StatusNoOpKeepingRegistration, std::move(registration)));
 }
 
 void DispatchSyncEventOnIO(scoped_refptr<ServiceWorkerContextWrapper> context,
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index cc49c35..b199393 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -15,10 +15,10 @@
 #include "build/build_config.h"
 #include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/common/content_export.h"
-#include "content/common/devtools.mojom.h"
 #include "content/common/navigation_params.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "net/base/net_errors.h"
+#include "third_party/WebKit/public/web/devtools_agent.mojom.h"
 
 #if defined(OS_ANDROID)
 #include "services/device/public/interfaces/wake_lock.mojom.h"
@@ -144,7 +144,7 @@
 
   // The active host we are talking to.
   RenderFrameHostImpl* frame_host_ = nullptr;
-  mojom::DevToolsAgentAssociatedPtr agent_ptr_;
+  blink::mojom::DevToolsAgentAssociatedPtr agent_ptr_;
   base::flat_set<NavigationHandleImpl*> navigation_handles_;
   bool render_frame_alive_ = false;
 
diff --git a/content/browser/loader/navigation_url_loader_impl_core.cc b/content/browser/loader/navigation_url_loader_impl_core.cc
index 6917407..b9dedfe 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -52,12 +52,13 @@
 
   // The ResourceDispatcherHostImpl can be null in unit tests.
   if (ResourceDispatcherHostImpl::Get()) {
+    GlobalRequestID global_request_id;  // unused.
     ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
         resource_context, url_request_context_getter->GetURLRequestContext(),
         upload_file_system_context, *request_info,
         std::move(navigation_ui_data), this, mojom::URLLoaderClientPtr(),
         mojom::URLLoaderRequest(), service_worker_handle_core,
-        appcache_handle_core, mojom::kURLLoadOptionNone);
+        appcache_handle_core, mojom::kURLLoadOptionNone, &global_request_id);
   }
 
   // Careful, |this| could be destroyed at this point. Don't notify start if
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 7b96343..d6f63565 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -19,6 +19,7 @@
 #include "content/browser/loader/navigation_resource_handler.h"
 #include "content/browser/loader/navigation_url_loader_delegate.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/loader/url_loader_request_handler.h"
 #include "content/browser/resource_context_impl.h"
 #include "content/browser/service_worker/service_worker_navigation_handle.h"
@@ -37,6 +38,7 @@
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_data.h"
 #include "content/public/browser/navigation_ui_data.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/common/content_features.h"
@@ -61,6 +63,9 @@
 // Request ID for browser initiated requests. We start at -2 on the same lines
 // as ResourceDispatcherHostImpl.
 int g_next_request_id = -2;
+GlobalRequestID MakeGlobalRequestID() {
+  return GlobalRequestID(-1, g_next_request_id--);
+}
 
 size_t GetCertificateChainsSizeInKB(const net::SSLInfo& ssl_info) {
   base::Pickle cert_pickle;
@@ -172,11 +177,15 @@
       std::unique_ptr<ResourceRequest> resource_request,
       ResourceContext* resource_context,
       scoped_refptr<URLLoaderFactoryGetter> default_url_loader_factory_getter,
+      const GURL& url,
+      base::Optional<std::string> suggested_filename,
       const base::WeakPtr<NavigationURLLoaderNetworkService>& owner)
       : handlers_(std::move(initial_handlers)),
         resource_request_(std::move(resource_request)),
         resource_context_(resource_context),
         default_url_loader_factory_getter_(default_url_loader_factory_getter),
+        url_(url),
+        suggested_filename_(suggested_filename),
         owner_(owner),
         response_loader_binding_(this),
         weak_factory_(this) {}
@@ -222,7 +231,8 @@
           std::move(navigation_ui_data), nullptr, std::move(url_loader_client),
           std::move(url_loader), service_worker_navigation_handle_core,
           appcache_handle_core,
-          GetURLLoaderOptions(request_info->is_main_frame));
+          GetURLLoaderOptions(request_info->is_main_frame),
+          &global_request_id_);
     }
 
     // TODO(arthursonzogni): Detect when the ResourceDispatcherHost didn't
@@ -275,6 +285,7 @@
     DCHECK(base::FeatureList::IsEnabled(features::kNetworkService));
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     DCHECK(!started_);
+    global_request_id_ = MakeGlobalRequestID();
     frame_tree_node_id_ = frame_tree_node_id;
     started_ = true;
     web_contents_getter_ =
@@ -516,6 +527,30 @@
     scoped_refptr<ResourceResponse> response(new ResourceResponse());
     response->head = head;
 
+    bool is_download;
+    bool is_stream;
+    std::unique_ptr<NavigationData> cloned_navigation_data;
+    if (base::FeatureList::IsEnabled(features::kNetworkService)) {
+      is_download = IsDownload(*response.get(), url_, suggested_filename_);
+      is_stream = false;
+    } else {
+      ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+      net::URLRequest* url_request = rdh->GetURLRequest(global_request_id_);
+      ResourceRequestInfoImpl* info =
+          ResourceRequestInfoImpl::ForRequest(url_request);
+      is_download = info->IsDownload();
+      is_stream = info->is_stream();
+      if (rdh->delegate()) {
+        NavigationData* navigation_data =
+            rdh->delegate()->GetNavigationData(url_request);
+
+        // Clone the embedder's NavigationData before moving it to the UI
+        // thread.
+        if (navigation_data)
+          cloned_navigation_data = navigation_data->Clone();
+      }
+    }
+
     // Make a copy of the ResourceResponse before it is passed to another
     // thread.
     //
@@ -525,8 +560,10 @@
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::BindOnce(&NavigationURLLoaderNetworkService::OnReceiveResponse,
-                       owner_, std::move(url_loader_client_endpoints),
-                       response->DeepCopy(), ssl_info,
+                       owner_, response->DeepCopy(),
+                       std::move(url_loader_client_endpoints),
+                       std::move(ssl_info), std::move(cloned_navigation_data),
+                       global_request_id_, is_download, is_stream,
                        base::Passed(&downloaded_file)));
   }
 
@@ -544,6 +581,7 @@
 
     scoped_refptr<ResourceResponse> response(new ResourceResponse());
     response->head = head;
+    url_ = redirect_info.new_url;
 
     // Make a copy of the ResourceResponse before it is passed to another
     // thread.
@@ -622,6 +660,7 @@
 
   std::unique_ptr<ResourceRequest> resource_request_;
   int frame_tree_node_id_ = 0;
+  GlobalRequestID global_request_id_;
   net::RedirectInfo redirect_info_;
   int redirect_limit_ = net::URLRequest::kMaxRedirects;
   ResourceContext* resource_context_;
@@ -635,6 +674,14 @@
   BlobHandles blob_handles_;
   std::vector<GURL> url_chain_;
 
+  // Current URL that is being navigated, updated after redirection.
+  GURL url_;
+
+  // If this request was triggered by an anchor tag with a download attribute,
+  // the |suggested_filename_| will be the (possibly empty) value of said
+  // attribute.
+  base::Optional<std::string> suggested_filename_;
+
   // Currently used by the AppCache loader to pass its factory to the
   // renderer which enables it to handle subresources.
   base::Optional<SubresourceLoaderParams> subresource_loader_params_;
@@ -689,8 +736,6 @@
     std::vector<std::unique_ptr<URLLoaderRequestHandler>> initial_handlers)
     : delegate_(delegate),
       allow_download_(request_info->common_params.allow_download),
-      suggested_filename_(request_info->begin_params->suggested_filename),
-      url_(request_info->common_params.url),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   int frame_tree_node_id = request_info->frame_tree_node_id;
@@ -714,7 +759,10 @@
         /* initial_handlers = */
         std::vector<std::unique_ptr<URLLoaderRequestHandler>>(),
         /* resource_request = */ nullptr, resource_context,
-        /* default_url_factory_getter = */ nullptr, weak_factory_.GetWeakPtr());
+        /* default_url_factory_getter = */ nullptr,
+        request_info->common_params.url,
+        request_info->begin_params->suggested_filename,
+        weak_factory_.GetWeakPtr());
 
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
@@ -788,13 +836,13 @@
             .PassInterface();
   }
 
-  g_next_request_id--;
-
   auto* partition = static_cast<StoragePartitionImpl*>(storage_partition);
   DCHECK(!request_controller_);
   request_controller_ = std::make_unique<URLLoaderRequestController>(
       std::move(initial_handlers), std::move(new_request), resource_context,
-      partition->url_loader_factory_getter(), weak_factory_.GetWeakPtr());
+      partition->url_loader_factory_getter(), request_info->common_params.url,
+      request_info->begin_params->suggested_filename,
+      weak_factory_.GetWeakPtr());
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::BindOnce(&URLLoaderRequestController::Start,
@@ -841,9 +889,13 @@
 void NavigationURLLoaderNetworkService::ProceedWithResponse() {}
 
 void NavigationURLLoaderNetworkService::OnReceiveResponse(
-    mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     scoped_refptr<ResourceResponse> response,
+    mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
     const base::Optional<net::SSLInfo>& maybe_ssl_info,
+    std::unique_ptr<NavigationData> navigation_data,
+    const GlobalRequestID& global_request_id,
+    bool is_download,
+    bool is_stream,
     mojom::DownloadedTempFilePtr downloaded_file) {
   TRACE_EVENT_ASYNC_END2("navigation", "Navigation timeToResponseStarted", this,
                          "&NavigationURLLoaderNetworkService", this, "success",
@@ -855,17 +907,10 @@
   if (maybe_ssl_info.has_value())
     ssl_info = maybe_ssl_info.value();
 
-  // TODO(arthursonzogni): In NavigationMojoResponse, this is false. The info
-  // coming from the MimeSniffingResourceHandler must be used.
-  DCHECK(response);
-  bool is_download =
-      allow_download_ && IsDownload(*response.get(), url_, suggested_filename_);
-
   delegate_->OnResponseStarted(
       std::move(response), std::move(url_loader_client_endpoints), nullptr,
-      std::move(ssl_info), std::unique_ptr<NavigationData>(),
-      GlobalRequestID(-1, g_next_request_id), is_download,
-      false /* is_stream */,
+      std::move(ssl_info), std::move(navigation_data), global_request_id,
+      allow_download_ && is_download, is_stream,
       request_controller_->TakeSubresourceLoaderParams());
 }
 
@@ -873,7 +918,6 @@
     const net::RedirectInfo& redirect_info,
     scoped_refptr<ResourceResponse> response) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  url_ = redirect_info.new_url;
   delegate_->OnRequestRedirected(redirect_info, std::move(response));
 }
 
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index a7e435ee..3958aee 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "content/browser/loader/navigation_url_loader.h"
 #include "content/public/browser/content_browser_client.h"
@@ -20,10 +21,12 @@
 
 namespace content {
 
-class ResourceContext;
+class NavigationData;
 class NavigationPostDataHandler;
+class ResourceContext;
 class StoragePartition;
 class URLLoaderRequestHandler;
+struct GlobalRequestID;
 
 // This is an implementation of NavigationURLLoader used when
 // --enable-network-service is used.
@@ -48,9 +51,13 @@
   void ProceedWithResponse() override;
 
   void OnReceiveResponse(
-      mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
       scoped_refptr<ResourceResponse> response,
-      const base::Optional<net::SSLInfo>& ssl_info,
+      mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+      const base::Optional<net::SSLInfo>& maybe_ssl_info,
+      std::unique_ptr<NavigationData> navigation_data,
+      const GlobalRequestID& global_request_id,
+      bool is_download,
+      bool is_stream,
       mojom::DownloadedTempFilePtr downloaded_file);
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          scoped_refptr<ResourceResponse> response);
@@ -71,14 +78,6 @@
 
   bool allow_download_;
 
-  // If this request was triggered by an anchor tag with a download attribute,
-  // the |suggested_filename_| will be the (possibly empty) value of said
-  // attribute.
-  base::Optional<std::string> suggested_filename_;
-
-  // Current URL that is being navigated, updated after redirection.
-  GURL url_;
-
   // Factories to handle navigation requests for non-network resources.
   ContentBrowserClient::NonNetworkURLLoaderFactoryMap
       non_network_url_loader_factories_;
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 53ff73d..4c9ec8f 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1816,7 +1816,8 @@
     mojom::URLLoaderRequest url_loader_request,
     ServiceWorkerNavigationHandleCore* service_worker_handle_core,
     AppCacheNavigationHandleCore* appcache_handle_core,
-    uint32_t url_loader_options) {
+    uint32_t url_loader_options,
+    GlobalRequestID* global_request_id) {
   // PlzNavigate: BeginNavigationRequest currently should only be used for the
   // browser-side navigations project.
   CHECK(IsBrowserSideNavigationEnabled());
@@ -1960,6 +1961,8 @@
   // Request takes ownership.
   extra_info->AssociateWithRequest(new_request.get());
 
+  *global_request_id = extra_info->GetGlobalRequestID();
+
   if (new_request->url().SchemeIs(url::kBlobScheme)) {
     // Hang on to a reference to ensure the blob is not released prior
     // to the job being started.
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 595a25b5..c09fd5b 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -249,6 +249,8 @@
 
   // PlzNavigate: Begins a request for NavigationURLLoader. |loader| is the
   // loader to attach to the leaf resource handler.
+  // After calling this function, |global_request_id| will contains the
+  // request's global id.
   void BeginNavigationRequest(
       ResourceContext* resource_context,
       net::URLRequestContext* request_context,
@@ -260,7 +262,8 @@
       mojom::URLLoaderRequest url_loader_request,
       ServiceWorkerNavigationHandleCore* service_worker_handle_core,
       AppCacheNavigationHandleCore* appcache_handle_core,
-      uint32_t url_loader_options);
+      uint32_t url_loader_options,
+      GlobalRequestID* global_request_id);
 
   int num_in_flight_requests_for_testing() const {
     return num_in_flight_requests_;
diff --git a/content/browser/media/midi_host_unittest.cc b/content/browser/media/midi_host_unittest.cc
index 9390717..f2589e1 100644
--- a/content/browser/media/midi_host_unittest.cc
+++ b/content/browser/media/midi_host_unittest.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
@@ -47,7 +48,14 @@
 
 class FakeMidiManager : public midi::MidiManager {
  public:
-  explicit FakeMidiManager(midi::MidiService* service) : MidiManager(service) {}
+  explicit FakeMidiManager(midi::MidiService* service)
+      : MidiManager(service), weak_factory_(this) {}
+  ~FakeMidiManager() override = default;
+
+  base::WeakPtr<FakeMidiManager> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
   void DispatchSendMidiData(midi::MidiManagerClient* client,
                             uint32_t port_index,
                             const std::vector<uint8_t>& data,
@@ -59,31 +67,33 @@
   }
   std::vector<MidiEvent> events_;
 
+  base::WeakPtrFactory<FakeMidiManager> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
 };
 
 class FakeMidiManagerFactory : public midi::MidiService::ManagerFactory {
  public:
-  FakeMidiManagerFactory() = default;
+  FakeMidiManagerFactory() : weak_factory_(this) {}
   ~FakeMidiManagerFactory() override = default;
   std::unique_ptr<midi::MidiManager> Create(
       midi::MidiService* service) override {
     std::unique_ptr<FakeMidiManager> manager =
         std::make_unique<FakeMidiManager>(service);
-    // |manaegr| will be owned by the caller MidiService instance, and valid
-    // while the MidiService instance is running.
-    // MidiService::Shutdown() or destructor will destruct it, and |manager_|
-    // get to be invalid after that.
-    manager_ = manager.get();
+    manager_ = manager->GetWeakPtr();
     return manager;
   }
-  FakeMidiManager* GetCreatedManager() {
-    DCHECK(manager_);
-    return manager_;
+
+  base::WeakPtr<FakeMidiManagerFactory> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
   }
 
+  base::WeakPtr<FakeMidiManager> GetCreatedManager() { return manager_; }
+
  private:
-  FakeMidiManager* manager_ = nullptr;
+  base::WeakPtr<FakeMidiManager> manager_;
+
+  base::WeakPtrFactory<FakeMidiManagerFactory> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerFactory);
 };
@@ -113,12 +123,13 @@
         port_id_(0) {
     std::unique_ptr<FakeMidiManagerFactory> factory =
         std::make_unique<FakeMidiManagerFactory>();
-    factory_ = factory.get();
+    factory_ = factory->GetWeakPtr();
     service_ = std::make_unique<midi::MidiService>(std::move(factory));
-    manager_ = factory_->GetCreatedManager();
     host_ = new MidiHostForTesting(kRenderProcessId, service_.get());
+    host_->OnStartSession();
   }
   ~MidiHostTest() override {
+    host_->OnEndSession();
     service_->Shutdown();
     RunLoopUntilIdle();
   }
@@ -141,13 +152,19 @@
     host_->OnMessageReceived(*message.get());
   }
 
-  size_t GetEventSize() const { return manager_->events_.size(); }
+  size_t GetEventSize() const {
+    if (!factory_->GetCreatedManager())
+      return 0U;
+    return factory_->GetCreatedManager()->events_.size();
+  }
 
   void CheckSendEventAt(size_t at, uint32_t port) {
-    EXPECT_EQ(DISPATCH_SEND_MIDI_DATA, manager_->events_[at].type);
-    EXPECT_EQ(port, manager_->events_[at].port_index);
-    EXPECT_EQ(data_, manager_->events_[at].data);
-    EXPECT_EQ(0.0, manager_->events_[at].timestamp);
+    base::WeakPtr<FakeMidiManager> manager = factory_->GetCreatedManager();
+    ASSERT_TRUE(manager);
+    EXPECT_EQ(DISPATCH_SEND_MIDI_DATA, manager->events_[at].type);
+    EXPECT_EQ(port, manager->events_[at].port_index);
+    EXPECT_EQ(data_, manager->events_[at].data);
+    EXPECT_EQ(0.0, manager->events_[at].timestamp);
   }
 
   void RunLoopUntilIdle() {
@@ -161,8 +178,7 @@
 
   std::vector<uint8_t> data_;
   int32_t port_id_;
-  FakeMidiManager* manager_;  // Raw pointer for testing, owned by |service_|.
-  FakeMidiManagerFactory* factory_;  // Owned by |service_|.
+  base::WeakPtr<FakeMidiManagerFactory> factory_;
   std::unique_ptr<midi::MidiService> service_;
   scoped_refptr<MidiHostForTesting> host_;
 
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index f950759..958f92b7 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -209,10 +209,10 @@
     const NotificationDatabaseData& notification_database_data,
     const base::Optional<int>& action_index,
     const base::Optional<base::string16>& reply,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
+    ServiceWorkerVersion::StatusCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   int request_id = service_worker->StartRequest(
-      ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, callback);
+      ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, std::move(callback));
 
   int action_index_int = -1 /* no value */;
   if (action_index.has_value())
@@ -232,15 +232,16 @@
     const scoped_refptr<PlatformNotificationContext>& notification_context,
     const ServiceWorkerRegistration* service_worker_registration,
     const NotificationDatabaseData& notification_database_data) {
-  ServiceWorkerVersion::LegacyStatusCallback status_callback = base::Bind(
-      &ServiceWorkerNotificationEventFinished, dispatch_complete_callback);
   service_worker_registration->active_version()->RunAfterStartWorker(
       ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK,
       base::BindOnce(
           &DispatchNotificationClickEventOnWorker,
           base::WrapRefCounted(service_worker_registration->active_version()),
-          notification_database_data, action_index, reply, status_callback),
-      status_callback);
+          notification_database_data, action_index, reply,
+          base::BindOnce(&ServiceWorkerNotificationEventFinished,
+                         dispatch_complete_callback)),
+      base::BindOnce(&ServiceWorkerNotificationEventFinished,
+                     dispatch_complete_callback));
 }
 
 // -----------------------------------------------------------------------------
@@ -281,10 +282,10 @@
 void DispatchNotificationCloseEventOnWorker(
     const scoped_refptr<ServiceWorkerVersion>& service_worker,
     const NotificationDatabaseData& notification_database_data,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
+    ServiceWorkerVersion::StatusCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   int request_id = service_worker->StartRequest(
-      ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, callback);
+      ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, std::move(callback));
 
   service_worker->event_dispatcher()->DispatchNotificationCloseEvent(
       notification_database_data.notification_id,
@@ -292,8 +293,7 @@
       service_worker->CreateSimpleEventCallback(request_id));
 }
 
-// Actually dispatches the notification close event on the service worker
-// registration.
+// Dispatches the notification close event on the service worker registration.
 void DoDispatchNotificationCloseEvent(
     const std::string& notification_id,
     bool by_user,
@@ -301,20 +301,24 @@
     const scoped_refptr<PlatformNotificationContext>& notification_context,
     const ServiceWorkerRegistration* service_worker_registration,
     const NotificationDatabaseData& notification_database_data) {
-  const ServiceWorkerVersion::LegacyStatusCallback dispatch_event_callback =
-      base::Bind(&DeleteNotificationDataFromDatabase, notification_id,
-                 notification_database_data.origin, notification_context,
-                 dispatch_complete_callback);
   if (by_user) {
     service_worker_registration->active_version()->RunAfterStartWorker(
         ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE,
         base::BindOnce(
             &DispatchNotificationCloseEventOnWorker,
             base::WrapRefCounted(service_worker_registration->active_version()),
-            notification_database_data, dispatch_event_callback),
-        dispatch_event_callback);
+            notification_database_data,
+            base::BindOnce(&DeleteNotificationDataFromDatabase, notification_id,
+                           notification_database_data.origin,
+                           notification_context, dispatch_complete_callback)),
+        base::BindOnce(&DeleteNotificationDataFromDatabase, notification_id,
+                       notification_database_data.origin, notification_context,
+                       dispatch_complete_callback));
   } else {
-    dispatch_event_callback.Run(ServiceWorkerStatusCode::SERVICE_WORKER_OK);
+    DeleteNotificationDataFromDatabase(
+        notification_id, notification_database_data.origin,
+        notification_context, dispatch_complete_callback,
+        ServiceWorkerStatusCode::SERVICE_WORKER_OK);
   }
 }
 
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 51cd0a4..c47066ec 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -293,8 +293,10 @@
     client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
         surface_id, current_frame_size_in_dip_, GetGutterColor(),
         GetSurfaceReferenceFactory());
-    if (compositor_)
+    if (compositor_ && !base::CommandLine::ForCurrentProcess()->HasSwitch(
+                           switches::kDisableResizeLock)) {
       compositor_->OnChildResizing();
+    }
     // Input throttling and guttering are handled differently when surface
     // synchronization is enabled so exit early here.
     return;
@@ -578,8 +580,7 @@
     UpdateGutters();
   }
 
-  if (HasFallbackSurface())
-    frame_evictor_->SwappedFrame(client_->DelegatedFrameHostIsVisible());
+  frame_evictor_->SwappedFrame(client_->DelegatedFrameHostIsVisible());
   // Note: the frame may have been evicted immediately.
 }
 
diff --git a/content/browser/renderer_host/input/mouse_latency_browsertest.cc b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
index 87e0d90c..c993494 100644
--- a/content/browser/renderer_host/input/mouse_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
@@ -258,7 +258,8 @@
 // MouseDown events in the case where no swap is generated.
 // Disabled on Android because we don't support synthetic mouse input on
 // Android (crbug.com/723618).
-#if defined(OS_ANDROID)
+// Disabled on Windows due to flakyness (https://crbug.com/800303).
+#if defined(OS_ANDROID) || defined(OS_WIN)
 #define MAYBE_MouseDownAndUpRecordedWithoutSwap \
   DISABLED_MouseDownAndUpRecordedWithoutSwap
 #else
diff --git a/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc b/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
index f4492c7..9c214ec 100644
--- a/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
+++ b/content/browser/renderer_host/input/wheel_scroll_latching_browsertest.cc
@@ -65,20 +65,26 @@
     " document.scrollingElement.addEventListener('wheel',"
     "   function(e) { documentWheelEventCounter++; });"
     "</script>";
+
+enum WheelScrollingMode {
+  kWheelScrollingModeNone,
+  kWheelScrollLatching,
+  kAsyncWheelEvents,
+};
 }  // namespace
 
 namespace content {
 class WheelScrollLatchingBrowserTest : public ContentBrowserTest {
  public:
-  WheelScrollLatchingBrowserTest(bool wheel_scroll_latching_enabled = true)
-      : wheel_scroll_latching_enabled_(wheel_scroll_latching_enabled) {
+  WheelScrollLatchingBrowserTest(
+      WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching)
+      : wheel_scrolling_mode_(wheel_scrolling_mode),
+        wheel_scroll_latching_enabled_(wheel_scrolling_mode_ !=
+                                       kWheelScrollingModeNone) {
     ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
         0);
 
-    if (wheel_scroll_latching_enabled_)
-      EnableWheelScrollLatching();
-    else
-      DisableWheelScrollLatching();
+    SetFeatureList();
   }
   ~WheelScrollLatchingBrowserTest() override {}
 
@@ -127,75 +133,108 @@
         shell(), "domAutomationController.send(" + script + ")", &value));
     return value;
   }
-  void EnableWheelScrollLatching() {
-    feature_list_.InitFromCommandLine(
-        features::kTouchpadAndWheelScrollLatching.name, "");
-  }
-  void DisableWheelScrollLatching() {
-    feature_list_.InitFromCommandLine(
-        "", features::kTouchpadAndWheelScrollLatching.name);
+  void SetFeatureList() {
+    if (wheel_scrolling_mode_ == kAsyncWheelEvents) {
+      feature_list_.InitWithFeatures({features::kTouchpadAndWheelScrollLatching,
+                                      features::kAsyncWheelEvents},
+                                     {});
+    } else if (wheel_scrolling_mode_ == kWheelScrollLatching) {
+      feature_list_.InitWithFeatures(
+          {features::kTouchpadAndWheelScrollLatching},
+          {features::kAsyncWheelEvents});
+    } else if (wheel_scrolling_mode_ == kWheelScrollingModeNone) {
+      feature_list_.InitWithFeatures({},
+                                     {features::kTouchpadAndWheelScrollLatching,
+                                      features::kAsyncWheelEvents});
+    }
   }
 
-  void WheelEventTargetTest() {
-    LoadURL();
-    EXPECT_EQ(0, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
-    EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
+  void WheelEventTargetTest();
+  void WheelEventRetargetWhenTargetRemovedTest();
+  void WheelScrollingRelatchWhenLatchedScrollerRemovedTest();
 
-    MainThreadFrameObserver frame_observer(
-        shell()->web_contents()->GetRenderViewHost()->GetWidget());
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  WheelScrollingMode wheel_scrolling_mode_;
+  bool wheel_scroll_latching_enabled_;
+};
 
-    auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
-        GetWidgetHost(), blink::WebInputEvent::kMouseWheel);
+class WheelScrollLatchingDisabledBrowserTest
+    : public WheelScrollLatchingBrowserTest {
+ public:
+  WheelScrollLatchingDisabledBrowserTest()
+      : WheelScrollLatchingBrowserTest(kWheelScrollingModeNone) {}
+  ~WheelScrollLatchingDisabledBrowserTest() override {}
+};
 
-    float scrollable_div_top =
-        ExecuteScriptAndExtractInt("scrollableDiv.getBoundingClientRect().top");
-    float x = (ExecuteScriptAndExtractInt(
-                   "scrollableDiv.getBoundingClientRect().left") +
-               ExecuteScriptAndExtractInt(
-                   "scrollableDiv.getBoundingClientRect().right")) /
-              2;
-    float y = 0.5 * scrollable_div_top;
-    float delta_x = 0;
-    float delta_y = -0.6 * scrollable_div_top;
-    blink::WebMouseWheelEvent wheel_event =
-        SyntheticWebMouseWheelEventBuilder::Build(x, y, x, y, delta_x, delta_y,
-                                                  0, true);
+class AsyncWheelEventsBrowserTest : public WheelScrollLatchingBrowserTest {
+ public:
+  AsyncWheelEventsBrowserTest()
+      : WheelScrollLatchingBrowserTest(kAsyncWheelEvents) {}
+  ~AsyncWheelEventsBrowserTest() override {}
+};
 
-    wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
-    GetRouter()->RouteMouseWheelEvent(GetRootView(), &wheel_event,
-                                      ui::LatencyInfo());
+void WheelScrollLatchingBrowserTest::WheelEventTargetTest() {
+  LoadURL();
+  EXPECT_EQ(0, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
+  EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
 
+  MainThreadFrameObserver frame_observer(
+      shell()->web_contents()->GetRenderViewHost()->GetWidget());
+
+  auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
+      GetWidgetHost(), blink::WebInputEvent::kMouseWheel);
+
+  float scrollable_div_top =
+      ExecuteScriptAndExtractInt("scrollableDiv.getBoundingClientRect().top");
+  float x = (ExecuteScriptAndExtractInt(
+                 "scrollableDiv.getBoundingClientRect().left") +
+             ExecuteScriptAndExtractInt(
+                 "scrollableDiv.getBoundingClientRect().right")) /
+            2;
+  float y = 0.5 * scrollable_div_top;
+  float delta_x = 0;
+  float delta_y = -0.6 * scrollable_div_top;
+  blink::WebMouseWheelEvent wheel_event =
+      SyntheticWebMouseWheelEventBuilder::Build(x, y, x, y, delta_x, delta_y, 0,
+                                                true);
+
+  wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+  GetRouter()->RouteMouseWheelEvent(GetRootView(), &wheel_event,
+                                    ui::LatencyInfo());
+
+  // Runs until we get the InputMsgAck callback.
+  EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
+            input_msg_watcher->WaitForAck());
+
+  while (ExecuteScriptAndExtractInt("document.scrollingElement.scrollTop") <
+         -delta_y) {
+    frame_observer.Wait();
+  }
+
+  EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDiv.scrollTop"));
+  EXPECT_EQ(1, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
+  EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
+
+  wheel_event.phase = blink::WebMouseWheelEvent::kPhaseChanged;
+  GetRouter()->RouteMouseWheelEvent(GetRootView(), &wheel_event,
+                                    ui::LatencyInfo());
+
+  if (wheel_scrolling_mode_ != kAsyncWheelEvents) {
     // Runs until we get the InputMsgAck callback.
     EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
               input_msg_watcher->WaitForAck());
+  }
 
+  if (wheel_scroll_latching_enabled_) {
     while (ExecuteScriptAndExtractInt("document.scrollingElement.scrollTop") <
-           -delta_y) {
+           -2 * delta_y) {
       frame_observer.Wait();
     }
 
     EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDiv.scrollTop"));
-    EXPECT_EQ(1, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
+    EXPECT_EQ(2, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
     EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
-
-    wheel_event.phase = blink::WebMouseWheelEvent::kPhaseChanged;
-    GetRouter()->RouteMouseWheelEvent(GetRootView(), &wheel_event,
-                                      ui::LatencyInfo());
-
-    // Runs until we get the InputMsgAck callback.
-    EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
-              input_msg_watcher->WaitForAck());
-
-    if (wheel_scroll_latching_enabled_) {
-      while (ExecuteScriptAndExtractInt("document.scrollingElement.scrollTop") <
-             -2 * delta_y) {
-        frame_observer.Wait();
-      }
-
-      EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDiv.scrollTop"));
-      EXPECT_EQ(2, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
-      EXPECT_EQ(0,
-                ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
     } else {  // !wheel_scroll_latching_enabled_
       while (ExecuteScriptAndExtractInt("scrollableDiv.scrollTop") < -delta_y)
         frame_observer.Wait();
@@ -205,20 +244,6 @@
                 ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
     }
   }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-  bool wheel_scroll_latching_enabled_;
-};
-
-class WheelScrollLatchingDisabledBrowserTest
-    : public WheelScrollLatchingBrowserTest {
- public:
-  WheelScrollLatchingDisabledBrowserTest()
-      : WheelScrollLatchingBrowserTest(false) {}
-  ~WheelScrollLatchingDisabledBrowserTest() override {}
-};
-
 // Start scrolling by mouse wheel on the document: the wheel event will be sent
 // to the document's scrolling element, the scrollable div will be under the
 // cursor after applying the scrolling. Continue scrolling by mouse wheel, since
@@ -228,6 +253,9 @@
 IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest, WheelEventTarget) {
   WheelEventTargetTest();
 }
+IN_PROC_BROWSER_TEST_F(AsyncWheelEventsBrowserTest, WheelEventTarget) {
+  WheelEventTargetTest();
+}
 
 // Start scrolling by mouse wheel on the document: the wheel event will be sent
 // to the document's scrolling element, the scrollable div will be under the
@@ -242,8 +270,11 @@
 
 // Tests that wheel events are retargeted if their target gets deleted in the
 // middle of scrolling.
-IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest,
-                       WheelEventRetargetWhenTargetRemoved) {
+void WheelScrollLatchingBrowserTest::WheelEventRetargetWhenTargetRemovedTest() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (!wheel_scroll_latching_enabled_)
+    return;
+
   LoadURL();
   EXPECT_EQ(0, ExecuteScriptAndExtractInt("documentWheelEventCounter"));
   EXPECT_EQ(0, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
@@ -294,6 +325,14 @@
 
   EXPECT_EQ(1, ExecuteScriptAndExtractInt("scrollableDivWheelEventCounter"));
 }
+IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest,
+                       WheelEventRetargetWhenTargetRemoved) {
+  WheelEventRetargetWhenTargetRemovedTest();
+}
+IN_PROC_BROWSER_TEST_F(AsyncWheelEventsBrowserTest,
+                       WheelEventRetargetWhenTargetRemoved) {
+  WheelEventRetargetWhenTargetRemovedTest();
+}
 
 // crbug.com/777258 Flaky on Android.
 #if defined(OS_ANDROID)
@@ -303,8 +342,12 @@
 #define MAYBE_WheelScrollingRelatchWhenLatchedScrollerRemoved \
   WheelScrollingRelatchWhenLatchedScrollerRemoved
 #endif
-IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest,
-                       MAYBE_WheelScrollingRelatchWhenLatchedScrollerRemoved) {
+void WheelScrollLatchingBrowserTest::
+    WheelScrollingRelatchWhenLatchedScrollerRemovedTest() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (!wheel_scroll_latching_enabled_)
+    return;
+
   LoadURL();
   EXPECT_EQ(ExecuteScriptAndExtractInt("document.scrollingElement.scrollTop"),
             0);
@@ -366,5 +409,13 @@
     GiveItSomeTime();
   }
 }
+IN_PROC_BROWSER_TEST_F(WheelScrollLatchingBrowserTest,
+                       MAYBE_WheelScrollingRelatchWhenLatchedScrollerRemoved) {
+  WheelScrollingRelatchWhenLatchedScrollerRemovedTest();
+}
+IN_PROC_BROWSER_TEST_F(AsyncWheelEventsBrowserTest,
+                       MAYBE_WheelScrollingRelatchWhenLatchedScrollerRemoved) {
+  WheelScrollingRelatchWhenLatchedScrollerRemovedTest();
+}
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 7f16f2b..572401e 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -19,6 +19,8 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "components/viz/test/compositor_frame_helpers.h"
 #include "content/browser/gpu/compositor_util.h"
@@ -294,8 +296,11 @@
         bottom_controls_height_(0.f) {}
 
   // Sets the bounds returned by GetViewBounds.
-  void set_bounds(const gfx::Rect& bounds) {
+  void SetBounds(const gfx::Rect& bounds) override {
+    if (bounds_ == bounds)
+      return;
     bounds_ = bounds;
+    local_surface_id_ = local_surface_id_allocator_.GenerateId();
   }
 
   void set_top_controls_height(float top_controls_height) {
@@ -340,6 +345,10 @@
   float GetBottomControlsHeight() const override {
     return bottom_controls_height_;
   }
+  viz::LocalSurfaceId GetLocalSurfaceId() const override {
+    return local_surface_id_;
+  }
+
   void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
                               InputEventAckState ack_result) override {
     acked_event_ = touch.event;
@@ -379,6 +388,8 @@
   float top_controls_height_;
   float bottom_controls_height_;
   viz::BeginFrameAck last_did_not_produce_frame_ack_;
+  viz::LocalSurfaceId local_surface_id_;
+  viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestView);
@@ -911,7 +922,7 @@
 TEST_F(RenderWidgetHostTest, Resize) {
   // The initial bounds is the empty rect, so setting it to the same thing
   // shouldn't send the resize message.
-  view_->set_bounds(gfx::Rect());
+  view_->SetBounds(gfx::Rect());
   host_->WasResized();
   EXPECT_FALSE(host_->resize_ack_pending_);
   EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
@@ -926,7 +937,7 @@
   // but should not expect ack for empty physical backing size.
   gfx::Rect original_size(0, 0, 100, 100);
   process_->sink().ClearMessages();
-  view_->set_bounds(original_size);
+  view_->SetBounds(original_size);
   view_->SetMockPhysicalBackingSize(gfx::Size());
   host_->WasResized();
   EXPECT_FALSE(host_->resize_ack_pending_);
@@ -952,7 +963,7 @@
   process_->sink().ClearMessages();
   gfx::Rect second_size(0, 0, 110, 110);
   EXPECT_FALSE(host_->resize_ack_pending_);
-  view_->set_bounds(second_size);
+  view_->SetBounds(second_size);
   host_->WasResized();
   EXPECT_TRUE(host_->resize_ack_pending_);
   params.flags = 0;
@@ -965,7 +976,7 @@
   // a resize ACK is pending.
   gfx::Rect third_size(0, 0, 120, 120);
   process_->sink().ClearMessages();
-  view_->set_bounds(third_size);
+  view_->SetBounds(third_size);
   host_->WasResized();
   EXPECT_TRUE(host_->resize_ack_pending_);
   EXPECT_EQ(second_size.size(), host_->old_resize_params_->new_size);
@@ -995,7 +1006,7 @@
   // expect a resize ack (since the renderer won't ack empty sizes). The message
   // should contain the new size (0x0) and not the previous one that we skipped
   process_->sink().ClearMessages();
-  view_->set_bounds(gfx::Rect());
+  view_->SetBounds(gfx::Rect());
   host_->WasResized();
   EXPECT_FALSE(host_->resize_ack_pending_);
   EXPECT_EQ(gfx::Size(), host_->old_resize_params_->new_size);
@@ -1003,7 +1014,7 @@
 
   // Send a rect that has no area but has either width or height set.
   process_->sink().ClearMessages();
-  view_->set_bounds(gfx::Rect(0, 0, 0, 30));
+  view_->SetBounds(gfx::Rect(0, 0, 0, 30));
   host_->WasResized();
   EXPECT_FALSE(host_->resize_ack_pending_);
   EXPECT_EQ(gfx::Size(0, 30), host_->old_resize_params_->new_size);
@@ -1017,7 +1028,7 @@
   EXPECT_FALSE(process_->sink().GetFirstMessageMatching(ViewMsg_Resize::ID));
 
   // A different size should be sent again, however.
-  view_->set_bounds(gfx::Rect(0, 0, 0, 31));
+  view_->SetBounds(gfx::Rect(0, 0, 0, 31));
   host_->WasResized();
   EXPECT_FALSE(host_->resize_ack_pending_);
   EXPECT_EQ(gfx::Size(0, 31), host_->old_resize_params_->new_size);
@@ -1075,7 +1086,7 @@
 
   // Setting the bounds to a "real" rect should send out the notification.
   gfx::Rect original_size(0, 0, 100, 100);
-  view_->set_bounds(original_size);
+  view_->SetBounds(original_size);
   host_->WasResized();
   EXPECT_TRUE(host_->resize_ack_pending_);
   EXPECT_EQ(original_size.size(), host_->old_resize_params_->new_size);
@@ -1839,7 +1850,7 @@
       TouchEmulator::Mode::kEmulatingTouchFromMouse,
       ui::GestureProviderConfigType::GENERIC_MOBILE);
   process_->sink().ClearMessages();
-  view_->set_bounds(gfx::Rect(0, 0, 400, 200));
+  view_->SetBounds(gfx::Rect(0, 0, 400, 200));
   view_->Show();
 
   SimulateMouseEvent(WebInputEvent::kMouseMove, 10, 10, 0, false);
@@ -1992,7 +2003,7 @@
       TouchEmulator::Mode::kEmulatingTouchFromMouse,
       ui::GestureProviderConfigType::GENERIC_MOBILE);
   process_->sink().ClearMessages();
-  view_->set_bounds(gfx::Rect(0, 0, 400, 200));
+  view_->SetBounds(gfx::Rect(0, 0, 400, 200));
   view_->Show();
 
   SimulateMouseEvent(WebInputEvent::kMouseMove, 10, 10, 0, false);
@@ -2593,7 +2604,7 @@
 TEST_F(RenderWidgetHostTest, ResizeParams) {
   gfx::Rect bounds(0, 0, 100, 100);
   gfx::Size physical_backing_size(40, 50);
-  view_->set_bounds(bounds);
+  view_->SetBounds(bounds);
   view_->SetMockPhysicalBackingSize(physical_backing_size);
 
   ResizeParams resize_params;
@@ -2659,7 +2670,7 @@
       : RenderWidgetHostTest(), initial_size_(200, 100) {}
 
   void ConfigureView(TestView* view) override {
-    view->set_bounds(gfx::Rect(initial_size_));
+    view->SetBounds(gfx::Rect(initial_size_));
   }
 
  protected:
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 0ec431c..8fb1c1dd 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -532,8 +532,10 @@
 
 class RenderWidgetHostViewAuraTest : public testing::Test {
  public:
-  RenderWidgetHostViewAuraTest()
-      : widget_host_uses_shutdown_to_destroy_(false),
+  RenderWidgetHostViewAuraTest(
+      WheelScrollingMode wheel_scrolling_mode = kWheelScrollingModeNone)
+      : wheel_scrolling_mode_(wheel_scrolling_mode),
+        widget_host_uses_shutdown_to_destroy_(false),
         is_guest_view_hack_(false) {}
 
   static void InstallDelegatedFrameHostClient(
@@ -645,27 +647,16 @@
 
   const ui::MotionEventAura& pointer_state() { return view_->pointer_state(); }
 
-  void EnableWheelScrollLatching() {
-    feature_list_.InitFromCommandLine(
-        features::kTouchpadAndWheelScrollLatching.name, "");
-  }
-
-  void DisableWheelScrollLatching() {
-    feature_list_.InitFromCommandLine(
-        "", features::kTouchpadAndWheelScrollLatching.name);
-  }
-
-  void SetFeatureList(
-      WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching) {
-    if (wheel_scrolling_mode == kAsyncWheelEvents) {
+  void SetFeatureList() {
+    if (wheel_scrolling_mode_ == kAsyncWheelEvents) {
       feature_list_.InitWithFeatures({features::kTouchpadAndWheelScrollLatching,
                                       features::kAsyncWheelEvents},
                                      {});
-    } else if (wheel_scrolling_mode == kWheelScrollLatching) {
+    } else if (wheel_scrolling_mode_ == kWheelScrollLatching) {
       feature_list_.InitWithFeatures(
           {features::kTouchpadAndWheelScrollLatching},
           {features::kAsyncWheelEvents});
-    } else if (wheel_scrolling_mode == kWheelScrollingModeNone) {
+    } else if (wheel_scrolling_mode_ == kWheelScrollingModeNone) {
       feature_list_.InitWithFeatures({},
                                      {features::kTouchpadAndWheelScrollLatching,
                                       features::kAsyncWheelEvents});
@@ -675,6 +666,13 @@
         features::kVsyncAlignedInputEvents);
   }
 
+  void TimerBasedWheelEventPhaseInfo();
+  void TimerBasedLatchingBreaksWithMouseMove();
+  void TouchpadFlingStartResetsWheelPhaseState();
+  void GSBWithTouchSourceStopsWheelScrollSequence();
+
+  WheelScrollingMode wheel_scrolling_mode_;
+
  protected:
   BrowserContext* browser_context() { return browser_context_.get(); }
 
@@ -759,8 +757,23 @@
 class RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest
     : public RenderWidgetHostViewAuraTest {
  public:
+  RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest()
+      : RenderWidgetHostViewAuraTest(kWheelScrollLatching) {}
   void SetUp() override {
-    EnableWheelScrollLatching();
+    SetFeatureList();
+    ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
+        0);
+    RenderWidgetHostViewAuraTest::SetUp();
+  }
+};
+
+class RenderWidgetHostViewAuraAsyncWheelEventsEnabledTest
+    : public RenderWidgetHostViewAuraTest {
+ public:
+  RenderWidgetHostViewAuraAsyncWheelEventsEnabledTest()
+      : RenderWidgetHostViewAuraTest(kAsyncWheelEvents) {}
+  void SetUp() override {
+    SetFeatureList();
     ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
         0);
     RenderWidgetHostViewAuraTest::SetUp();
@@ -816,9 +829,9 @@
  public:
   RenderWidgetHostViewAuraOverscrollTest(
       WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching)
-      : wheel_scroll_latching_enabled_(wheel_scrolling_mode !=
-                                       kWheelScrollingModeNone),
-        wheel_scrolling_mode_(wheel_scrolling_mode) {}
+      : RenderWidgetHostViewAuraTest(wheel_scrolling_mode),
+        wheel_scroll_latching_enabled_(wheel_scrolling_mode !=
+                                       kWheelScrollingModeNone) {}
 
   // We explicitly invoke SetUp to allow gesture debounce customization.
   void SetUp() override {}
@@ -870,7 +883,7 @@
   void SetUpOverscrollEnvironment() { SetUpOverscrollEnvironmentImpl(0); }
 
   void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms) {
-    SetFeatureList(wheel_scrolling_mode_);
+    SetFeatureList();
     ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
         debounce_interval_in_ms);
 
@@ -1206,7 +1219,6 @@
   std::unique_ptr<TestOverscrollDelegate> overscroll_delegate_;
 
   bool wheel_scroll_latching_enabled_;
-  WheelScrollingMode wheel_scrolling_mode_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraOverscrollTest);
@@ -1730,8 +1742,11 @@
   EXPECT_EQ(0U, events.size());
 }
 
-TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
-       TimerBasedWheelEventPhaseInfo) {
+void RenderWidgetHostViewAuraTest::TimerBasedWheelEventPhaseInfo() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (wheel_scrolling_mode_ == kWheelScrollingModeNone)
+    return;
+
   view_->InitAsChild(nullptr);
   view_->Show();
   sink_->ClearMessages();
@@ -1776,11 +1791,16 @@
   base::TimeTicks wheel_event_timestamp =
       ui::EventTimeStampFromSeconds(wheel_event->TimeStampSeconds());
   EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, wheel_event->phase);
-  events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  if (wheel_scrolling_mode_ == kWheelScrollLatching) {
+    events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    events = GetAndResetDispatchedMessages();
+    gesture_event = static_cast<const WebGestureEvent*>(
+        events[0]->ToEvent()->Event()->web_event.get());
+  } else {  // wheel_scrolling_mode_ == kAsyncWheelEvents.
+    gesture_event = static_cast<const WebGestureEvent*>(
+        events[1]->ToEvent()->Event()->web_event.get());
+  }
 
-  events = GetAndResetDispatchedMessages();
-  gesture_event = static_cast<const WebGestureEvent*>(
-      events[0]->ToEvent()->Event()->web_event.get());
   EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, gesture_event->GetType());
   EXPECT_EQ(0U, gesture_event->data.scroll_update.delta_x);
   EXPECT_EQ(2U, gesture_event->data.scroll_update.delta_y);
@@ -1810,12 +1830,23 @@
   EXPECT_EQ(WebInputEvent::kGestureScrollEnd, gesture_event->GetType());
   EXPECT_TRUE(gesture_event->data.scroll_end.synthetic);
 }
+TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
+       TimerBasedWheelEventPhaseInfo) {
+  TimerBasedWheelEventPhaseInfo();
+}
+TEST_F(RenderWidgetHostViewAuraAsyncWheelEventsEnabledTest,
+       TimerBasedWheelEventPhaseInfo) {
+  TimerBasedWheelEventPhaseInfo();
+}
 
 // Tests that latching breaks when the difference between location of the first
 // wheel event in the sequence and the location of the current wheel event is
 // larger than some maximum threshold.
-TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
-       TimerBasedLatchingBreaksWithMouseMove) {
+void RenderWidgetHostViewAuraTest::TimerBasedLatchingBreaksWithMouseMove() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (wheel_scrolling_mode_ == kWheelScrollingModeNone)
+    return;
+
   view_->InitAsChild(nullptr);
   view_->Show();
   sink_->ClearMessages();
@@ -1845,11 +1876,16 @@
   view_->OnMouseEvent(&event2);
   base::RunLoop().RunUntilIdle();
   events = GetAndResetDispatchedMessages();
-  EXPECT_EQ("MouseWheel", GetMessageNames(events));
+  if (wheel_scrolling_mode_ == kWheelScrollLatching)
+    EXPECT_EQ("MouseWheel", GetMessageNames(events));
+  else
+    EXPECT_EQ("MouseWheel GestureScrollUpdate", GetMessageNames(events));
+
   wheel_event = static_cast<const WebMouseWheelEvent*>(
       events[0]->ToEvent()->Event()->web_event.get());
   EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, wheel_event->phase);
-  events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  if (wheel_scrolling_mode_ == kWheelScrollLatching)
+    events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
   events = GetAndResetDispatchedMessages();
 
   // Send the third wheel event with a location outside of the slop region. The
@@ -1870,11 +1906,22 @@
       events[2]->ToEvent()->Event()->web_event.get());
   EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, wheel_event->phase);
 }
+TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
+       TimerBasedLatchingBreaksWithMouseMove) {
+  TimerBasedLatchingBreaksWithMouseMove();
+}
+TEST_F(RenderWidgetHostViewAuraAsyncWheelEventsEnabledTest,
+       TimerBasedLatchingBreaksWithMouseMove) {
+  TimerBasedLatchingBreaksWithMouseMove();
+}
 
 // Tests that a gesture fling start with touchpad source resets wheel phase
 // state.
-TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
-       TouchpadFlingStartResetsWheelPhaseState) {
+void RenderWidgetHostViewAuraTest::TouchpadFlingStartResetsWheelPhaseState() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (wheel_scrolling_mode_ == kWheelScrollingModeNone)
+    return;
+
   // When the user puts their fingers down a GFC is receieved.
   ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gfx::Point(2, 2),
                                ui::EventTimeForNow(), 0, 0, 0, 0, 0, 2);
@@ -1921,20 +1968,29 @@
   view_->OnScrollEvent(&scroll1);
   base::RunLoop().RunUntilIdle();
   events = GetAndResetDispatchedMessages();
-  EXPECT_EQ(1U, events.size());
+  if (wheel_scrolling_mode_ == kWheelScrollLatching)
+    EXPECT_EQ(1U, events.size());
+  else
+    EXPECT_EQ(2U, events.size());
   wheel_event = static_cast<const WebMouseWheelEvent*>(
       events[0]->ToEvent()->Event()->web_event.get());
   EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, wheel_event->phase);
-  events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-
-  events = GetAndResetDispatchedMessages();
-  EXPECT_EQ("GestureScrollUpdate", GetMessageNames(events));
-  gesture_event = static_cast<const WebGestureEvent*>(
-      events[0]->ToEvent()->Event()->web_event.get());
+  if (wheel_scrolling_mode_ == kWheelScrollLatching) {
+    events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+    events = GetAndResetDispatchedMessages();
+    EXPECT_EQ("GestureScrollUpdate", GetMessageNames(events));
+    gesture_event = static_cast<const WebGestureEvent*>(
+        events[0]->ToEvent()->Event()->web_event.get());
+    events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_CONSUMED);
+  } else {  // wheel_scrolling_mode_ == kAsyncWheelEvents
+    EXPECT_EQ("MouseWheel GestureScrollUpdate", GetMessageNames(events));
+    gesture_event = static_cast<const WebGestureEvent*>(
+        events[1]->ToEvent()->Event()->web_event.get());
+    events[1]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_CONSUMED);
+  }
   EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, gesture_event->GetType());
   EXPECT_EQ(0U, gesture_event->data.scroll_update.delta_x);
   EXPECT_EQ(15U, gesture_event->data.scroll_update.delta_y);
-  events[0]->ToEvent()->CallCallback(INPUT_EVENT_ACK_STATE_CONSUMED);
 
   // A GFS is received showing that the user has lifted their fingers. This will
   // reset the scroll state of the wheel phase handler.
@@ -1964,9 +2020,21 @@
       events[2]->ToEvent()->Event()->web_event.get());
   EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, wheel_event->phase);
 }
-
 TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
-       GSBWithTouchSourceStopsWheelScrollSequence) {
+       TouchpadFlingStartResetsWheelPhaseState) {
+  TouchpadFlingStartResetsWheelPhaseState();
+}
+TEST_F(RenderWidgetHostViewAuraAsyncWheelEventsEnabledTest,
+       TouchpadFlingStartResetsWheelPhaseState) {
+  TouchpadFlingStartResetsWheelPhaseState();
+}
+
+void RenderWidgetHostViewAuraTest::
+    GSBWithTouchSourceStopsWheelScrollSequence() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (wheel_scrolling_mode_ == kWheelScrollingModeNone)
+    return;
+
   ui::ScrollEvent scroll0(ui::ET_SCROLL, gfx::Point(2, 2),
                           ui::EventTimeForNow(), 0, 0, 5, 0, 5, 2);
   view_->OnScrollEvent(&scroll0);
@@ -2020,6 +2088,16 @@
   EXPECT_EQ(blink::kWebGestureDeviceTouchscreen, gesture_event->source_device);
 }
 
+TEST_F(RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest,
+       GSBWithTouchSourceStopsWheelScrollSequence) {
+  GSBWithTouchSourceStopsWheelScrollSequence();
+}
+
+TEST_F(RenderWidgetHostViewAuraAsyncWheelEventsEnabledTest,
+       GSBWithTouchSourceStopsWheelScrollSequence) {
+  GSBWithTouchSourceStopsWheelScrollSequence();
+}
+
 // Checks that touch-event state is maintained correctly for multiple touch
 // points.
 TEST_F(RenderWidgetHostViewAuraTest, MultiTouchPointsStates) {
@@ -2566,6 +2644,11 @@
 // If the view size is larger than the compositor frame then extra layers
 // should be created to fill the gap.
 TEST_F(RenderWidgetHostViewAuraTest, DelegatedFrameGutter) {
+  // TODO(fsamuel): Delete this test once surface synchronization is on for
+  // all platforms.
+  if (features::IsSurfaceSynchronizationEnabled())
+    return;
+
   gfx::Size large_size(100, 100);
   gfx::Size small_size(40, 45);
   gfx::Size medium_size(40, 95);
@@ -2753,6 +2836,11 @@
 
 // Skipped frames should not drop their damage.
 TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
+  // TODO(fsamuel): Delete this test once surface synchronization is on for
+  // all platforms.
+  if (features::IsSurfaceSynchronizationEnabled())
+    return;
+
   gfx::Rect view_rect(100, 100);
   gfx::Size frame_size = view_rect.size();
   viz::LocalSurfaceId local_surface_id =
@@ -2867,6 +2955,11 @@
 
 // If resize races with a renderer frame, we should lock for the right size.
 TEST_F(RenderWidgetHostViewAuraTest, ResizeAfterReceivingFrame) {
+  // TODO(fsamuel): Delete this test once surface synchronization is on for
+  // all platforms.
+  if (features::IsSurfaceSynchronizationEnabled())
+    return;
+
   gfx::Rect view_rect(100, 100);
   gfx::Size frame_size = view_rect.size();
   viz::LocalSurfaceId local_surface_id =
@@ -2942,6 +3035,11 @@
 // no reason to lock the compositor as there can't be guttering around a
 // renderer frame that doesn't exist.
 TEST_F(RenderWidgetHostViewAuraTest, MissingFramesDontLock) {
+  // TODO(fsamuel): Delete this test once surface synchronization is on for
+  // all platforms.
+  if (features::IsSurfaceSynchronizationEnabled())
+    return;
+
   gfx::Rect view_rect(100, 100);
   gfx::Size frame_size = view_rect.size();
 
@@ -3296,6 +3394,11 @@
 }
 
 TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
+  // TODO(fsamuel): Delete this test once surface synchronization is on for
+  // all platforms.
+  if (features::IsSurfaceSynchronizationEnabled())
+    return;
+
   view_->InitAsChild(nullptr);
 
   size_t max_renderer_frames =
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 75205c44..6f52479 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -317,13 +317,9 @@
   return event;
 }
 
-NSEvent* MockScrollWheelEventWithoutPhase(int32_t delta) {
-  return MockScrollWheelEventWithPhase(@selector(phaseNone), delta);
-}
-
 NSEvent* MockScrollWheelEventWithMomentumPhase(SEL mockPhaseSelector,
                                                int32_t delta) {
-  // Create a dummy event with phaseNone. This is for resetting the phase info
+  // Create a fake event with phaseNone. This is for resetting the phase info
   // of CGEventRef.
   MockScrollWheelEventWithPhase(@selector(phaseNone), 0);
   CGEventRef cg_event = CGEventCreateScrollWheelEvent(
@@ -338,20 +334,30 @@
   return event;
 }
 
+NSEvent* MockScrollWheelEventWithoutPhase(int32_t delta) {
+  return MockScrollWheelEventWithMomentumPhase(@selector(phaseNone), delta);
+}
+
+enum WheelScrollingMode {
+  kWheelScrollingModeNone,
+  kWheelScrollLatching,
+  kAsyncWheelEvents,
+};
+
 }  // namespace
 
 class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
  public:
-  RenderWidgetHostViewMacTest(bool scroll_latching = false)
-      : rwhv_mac_(nullptr), scroll_latching_(scroll_latching) {
+  RenderWidgetHostViewMacTest(
+      WheelScrollingMode wheel_scrolling_mode = kWheelScrollingModeNone)
+      : rwhv_mac_(nullptr),
+        wheel_scrolling_mode_(wheel_scrolling_mode),
+        scroll_latching_(wheel_scrolling_mode_ != kWheelScrollingModeNone) {
     std::unique_ptr<base::SimpleTestTickClock> mock_clock(
         new base::SimpleTestTickClock());
     mock_clock->Advance(base::TimeDelta::FromMilliseconds(100));
     ui::SetEventTickClockForTesting(std::move(mock_clock));
-    if (scroll_latching)
-      EnableWheelScrollLatching();
-    else
-      DisableWheelScrollLatching();
+    SetFeatureList();
 
     mojo_feature_list_.InitAndEnableFeature(features::kMojoInputMessages);
     vsync_feature_list_.InitAndEnableFeature(
@@ -403,18 +409,28 @@
     return base::UTF16ToUTF8(rwhv_mac_->GetTextSelection()->selected_text());
   }
 
-  void EnableWheelScrollLatching() {
-    feature_list_.InitFromCommandLine(
-        features::kTouchpadAndWheelScrollLatching.name, "");
-  }
-
-  void DisableWheelScrollLatching() {
-    feature_list_.InitFromCommandLine(
-        "", features::kTouchpadAndWheelScrollLatching.name);
+  void SetFeatureList() {
+    if (wheel_scrolling_mode_ == kAsyncWheelEvents) {
+      feature_list_.InitWithFeatures({features::kTouchpadAndWheelScrollLatching,
+                                      features::kAsyncWheelEvents},
+                                     {});
+    } else if (wheel_scrolling_mode_ == kWheelScrollLatching) {
+      feature_list_.InitWithFeatures(
+          {features::kTouchpadAndWheelScrollLatching},
+          {features::kAsyncWheelEvents});
+    } else if (wheel_scrolling_mode_ == kWheelScrollingModeNone) {
+      feature_list_.InitWithFeatures({},
+                                     {features::kTouchpadAndWheelScrollLatching,
+                                      features::kAsyncWheelEvents});
+    }
   }
 
   void IgnoreEmptyUnhandledWheelEventWithWheelGestures();
   void ScrollWheelEndEventDelivery();
+  void TimerBasedPhaseInfo();
+  void WheelWithPhaseEndedIsNotForwardedImmediately();
+  void WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer();
+  void WheelWithPhaseBeganDispatchesThePendingWheelEnd();
 
   MockRenderWidgetHostDelegate delegate_;
 
@@ -425,6 +441,7 @@
   RenderWidgetHostViewMac* rwhv_mac_ = nullptr;
   base::scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa_;
 
+  WheelScrollingMode wheel_scrolling_mode_;
   bool scroll_latching_;
 
  private:
@@ -1246,24 +1263,42 @@
     : public RenderWidgetHostViewMacTest {
  public:
   RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest()
-      : RenderWidgetHostViewMacTest(true) {}
+      : RenderWidgetHostViewMacTest(kWheelScrollLatching) {}
+};
+
+class RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest
+    : public RenderWidgetHostViewMacTest {
+ public:
+  RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest()
+      : RenderWidgetHostViewMacTest(kAsyncWheelEvents) {}
 };
 
 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
        IgnoreEmptyUnhandledWheelEventWithWheelGestures) {
   IgnoreEmptyUnhandledWheelEventWithWheelGestures();
 }
+TEST_F(RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest,
+       IgnoreEmptyUnhandledWheelEventWithWheelGestures) {
+  IgnoreEmptyUnhandledWheelEventWithWheelGestures();
+}
 
 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
        ScrollWheelEndEventDelivery) {
   ScrollWheelEndEventDelivery();
 }
+TEST_F(RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest,
+       ScrollWheelEndEventDelivery) {
+  ScrollWheelEndEventDelivery();
+}
 
 // Scrolling with a mouse wheel device on Mac won't give phase information.
 // MouseWheelPhaseHandler adds timer based phase information to wheel events
 // generated from this type of devices.
-TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
-       TimerBasedPhaseInfo) {
+void RenderWidgetHostViewMacTest::TimerBasedPhaseInfo() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (!scroll_latching_)
+    return;
+
   rwhv_mac_->set_mouse_wheel_wheel_phase_handler_timeout(
       base::TimeDelta::FromMilliseconds(100));
 
@@ -1299,12 +1334,24 @@
                   events[1]->ToEvent()->Event()->web_event.get())
                   ->data.scroll_end.synthetic);
 }
+TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
+       TimerBasedPhaseInfo) {
+  TimerBasedPhaseInfo();
+}
+TEST_F(RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest,
+       TimerBasedPhaseInfo) {
+  TimerBasedPhaseInfo();
+}
 
 // When wheel scroll latching is enabled, wheel end events are not sent
 // immediately, instead we start a timer to see if momentum phase of the scroll
 // starts or not.
-TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
-       WheelWithPhaseEndedIsNotForwardedImmediately) {
+void RenderWidgetHostViewMacTest::
+    WheelWithPhaseEndedIsNotForwardedImmediately() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (!scroll_latching_)
+    return;
+
   // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
   // the MockRenderProcessHost that is set up by the test harness which mocks
   // out |OnMessageReceived()|.
@@ -1358,9 +1405,21 @@
       kMaximumTimeBetweenPhaseEndedAndMomentumPhaseBegan);
   run_loop.Run();
 }
-
 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
-       WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer) {
+       WheelWithPhaseEndedIsNotForwardedImmediately) {
+  WheelWithPhaseEndedIsNotForwardedImmediately();
+}
+TEST_F(RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest,
+       WheelWithPhaseEndedIsNotForwardedImmediately) {
+  WheelWithPhaseEndedIsNotForwardedImmediately();
+}
+
+void RenderWidgetHostViewMacTest::
+    WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (!scroll_latching_)
+    return;
+
   // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
   // the MockRenderProcessHost that is set up by the test harness which mocks
   // out |OnMessageReceived()|.
@@ -1410,14 +1469,29 @@
   [view->cocoa_view() scrollWheel:wheelEvent3];
   base::RunLoop().RunUntilIdle();
   events = host->GetAndResetDispatchedMessages();
-  ASSERT_EQ("MouseWheel", GetMessageNames(events));
+  if (wheel_scrolling_mode_ == kAsyncWheelEvents)
+    ASSERT_EQ("MouseWheel GestureScrollUpdate", GetMessageNames(events));
+  else
+    ASSERT_EQ("MouseWheel", GetMessageNames(events));
   DCHECK(!view->HasPendingWheelEndEventForTesting());
 
   host->ShutdownAndDestroyWidget(true);
 }
-
 TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
-       WheelWithPhaseBeganDispatchesThePendingWheelEnd) {
+       WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer) {
+  WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer();
+}
+TEST_F(RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest,
+       WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer) {
+  WheelWithMomentumPhaseBeganStopsTheWheelEndDispatchTimer();
+}
+
+void RenderWidgetHostViewMacTest::
+    WheelWithPhaseBeganDispatchesThePendingWheelEnd() {
+  // The test is valid only when wheel scroll latching is enabled.
+  if (!scroll_latching_)
+    return;
+
   // Initialize the view associated with a MockRenderWidgetHostImpl, rather than
   // the MockRenderProcessHost that is set up by the test harness which mocks
   // out |OnMessageReceived()|.
@@ -1473,6 +1547,14 @@
 
   host->ShutdownAndDestroyWidget(true);
 }
+TEST_F(RenderWidgetHostViewMacWithWheelScrollLatchingEnabledTest,
+       WheelWithPhaseBeganDispatchesThePendingWheelEnd) {
+  WheelWithPhaseBeganDispatchesThePendingWheelEnd();
+}
+TEST_F(RenderWidgetHostViewMacWithAsyncWheelEventsEnabledTest,
+       WheelWithPhaseBeganDispatchesThePendingWheelEnd) {
+  WheelWithPhaseBeganDispatchesThePendingWheelEnd();
+}
 
 class RenderWidgetHostViewMacPinchTest : public RenderWidgetHostViewMacTest {
  public:
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 38f3bb2f..2cfa6ea 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -470,15 +470,9 @@
   process_handle_.reset();
 }
 
-void EmbeddedWorkerInstance::Start(
-    mojom::EmbeddedWorkerStartParamsPtr params,
-    ProviderInfoGetter provider_info_getter,
-    mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-    mojom::ControllerServiceWorkerRequest controller_request,
-    blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
-    blink::mojom::ServiceWorkerHostAssociatedPtrInfo
-        service_worker_host_ptr_info,
-    StatusCallback callback) {
+void EmbeddedWorkerInstance::Start(mojom::EmbeddedWorkerStartParamsPtr params,
+                                   ProviderInfoGetter provider_info_getter,
+                                   StatusCallback callback) {
   restart_count_++;
   if (!context_) {
     std::move(callback).Run(SERVICE_WORKER_ERROR_ABORT);
@@ -509,11 +503,6 @@
       mojo::MakeRequest(&client_);
   client_.set_connection_error_handler(
       base::BindOnce(&EmbeddedWorkerInstance::Detach, base::Unretained(this)));
-  pending_dispatcher_request_ = std::move(dispatcher_request);
-  pending_controller_request_ = std::move(controller_request);
-  pending_installed_scripts_info_ = std::move(installed_scripts_info);
-  pending_service_worker_host_ptr_info_ =
-      std::move(service_worker_host_ptr_info);
   inflight_start_task_.reset(
       new StartTask(this, params->script_url, std::move(request)));
   inflight_start_task_->Start(std::move(params), std::move(callback));
@@ -643,30 +632,21 @@
     // Mojo doesn't consider it an error. See https://crbug.com/732729.
     return SERVICE_WORKER_ERROR_IPC_FAILED;
   }
-  DCHECK(pending_dispatcher_request_.is_pending());
-  DCHECK(pending_controller_request_.is_pending());
-  DCHECK(pending_service_worker_host_ptr_info_.is_valid());
-
+  DCHECK(params->dispatcher_request.is_pending());
+  DCHECK(params->controller_request.is_pending());
+  DCHECK(params->service_worker_host.is_valid());
   DCHECK(!instance_host_binding_.is_bound());
-  mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo host_ptr_info;
-  instance_host_binding_.Bind(mojo::MakeRequest(&host_ptr_info));
+  instance_host_binding_.Bind(mojo::MakeRequest(&params->instance_host));
 
   blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy_ptr_info;
   content_settings_ = std::make_unique<ServiceWorkerContentSettingsProxyImpl>(
       params->script_url, context_,
-      mojo::MakeRequest(&content_settings_proxy_ptr_info));
+      mojo::MakeRequest(&params->content_settings_proxy));
 
-  const bool is_script_streaming = !pending_installed_scripts_info_.is_null();
+  const bool is_script_streaming = !params->installed_scripts_info.is_null();
   inflight_start_task_->set_start_worker_sent_time(base::TimeTicks::Now());
-  mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info =
-      std::move(provider_info_getter_).Run(process_id());
-  client_->StartWorker(std::move(params),
-                       std::move(pending_dispatcher_request_),
-                       std::move(pending_controller_request_),
-                       std::move(pending_installed_scripts_info_),
-                       std::move(pending_service_worker_host_ptr_info_),
-                       std::move(host_ptr_info), std::move(provider_info),
-                       std::move(content_settings_proxy_ptr_info));
+  params->provider_info = std::move(provider_info_getter_).Run(process_id());
+  client_->StartWorker(std::move(params));
   registry_->BindWorkerToProcess(process_id(), embedded_worker_id());
   OnStartWorkerMessageSent(is_script_streaming);
   return SERVICE_WORKER_OK;
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
index 9cdb3c2..d30232a 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -135,11 +135,6 @@
   void Start(
       mojom::EmbeddedWorkerStartParamsPtr params,
       ProviderInfoGetter provider_info_getter,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-      mojom::ControllerServiceWorkerRequest controller_request,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo
-          service_worker_host_ptr_info,
       StatusCallback callback);
 
   // Stops the worker. It is invalid to call this when the worker is not in
@@ -323,20 +318,6 @@
   // Binding for EmbeddedWorkerInstanceHost, runs on IO thread.
   mojo::AssociatedBinding<EmbeddedWorkerInstanceHost> instance_host_binding_;
 
-  // |pending_dispatcher_request_|, |pending_controller_request_|,
-  // |pending_installed_scripts_info_|, and
-  // |pending_service_worker_host_ptr_info_| are parameters of the StartWorker
-  // message. These are called "pending" because they are not used directly by
-  // this class and are just transferred to the renderer in SendStartWorker().
-  // TODO(shimazu): Remove these when EmbeddedWorkerStartParams is
-  // changed to a mojo struct and we put them in EmbeddedWorkerStartParams.
-  mojom::ServiceWorkerEventDispatcherRequest pending_dispatcher_request_;
-  mojom::ControllerServiceWorkerRequest pending_controller_request_;
-  blink::mojom::ServiceWorkerInstalledScriptsInfoPtr
-      pending_installed_scripts_info_;
-  blink::mojom::ServiceWorkerHostAssociatedPtrInfo
-      pending_service_worker_host_ptr_info_;
-
   // This is set at Start and used on SendStartWorker.
   ProviderInfoGetter provider_info_getter_;
 
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index 01a53b9..d80d015 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -189,9 +189,7 @@
     mojom::EmbeddedWorkerStartParamsPtr params =
         CreateStartParams(id, pattern, url);
     worker->Start(
-        std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-        CreateController(), GetInstalledScriptsInfoPtr(),
-        GetServiceWorkerHostPtrInfo(),
+        std::move(params), CreateProviderInfoGetter(),
         base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
     run_loop.Run();
     return status;
@@ -205,6 +203,11 @@
     params->script_url = script_url;
     params->pause_after_download = false;
     params->is_installed = false;
+
+    params->dispatcher_request = CreateEventDispatcher();
+    params->controller_request = CreateController();
+    params->installed_scripts_info = GetInstalledScriptsInfoPtr();
+    params->service_worker_host = GetServiceWorkerHostPtrInfo();
     return params;
   }
 
@@ -370,9 +373,7 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(service_worker_version_id, pattern, url);
   worker->Start(
-      std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-      CreateController(), GetInstalledScriptsInfoPtr(),
-      GetServiceWorkerHostPtrInfo(),
+      std::move(params), CreateProviderInfoGetter(),
       base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
   EXPECT_EQ(EmbeddedWorkerStatus::STARTING, worker->status());
   run_loop.Run();
@@ -430,9 +431,7 @@
     mojom::EmbeddedWorkerStartParamsPtr params =
         CreateStartParams(service_worker_version_id, pattern, url);
     worker->Start(
-        std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-        CreateController(), GetInstalledScriptsInfoPtr(),
-        GetServiceWorkerHostPtrInfo(),
+        std::move(params), CreateProviderInfoGetter(),
         base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
     run_loop.Run();
     EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -457,9 +456,7 @@
     mojom::EmbeddedWorkerStartParamsPtr params =
         CreateStartParams(service_worker_version_id, pattern, url);
     worker->Start(
-        std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-        CreateController(), GetInstalledScriptsInfoPtr(),
-        GetServiceWorkerHostPtrInfo(),
+        std::move(params), CreateProviderInfoGetter(),
         base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
     EXPECT_EQ(EmbeddedWorkerStatus::STARTING, worker->status());
     run_loop.Run();
@@ -546,9 +543,7 @@
     mojom::EmbeddedWorkerStartParamsPtr params =
         CreateStartParams(version_id1, pattern, url);
     worker1->Start(
-        std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-        CreateController(), GetInstalledScriptsInfoPtr(),
-        GetServiceWorkerHostPtrInfo(),
+        std::move(params), CreateProviderInfoGetter(),
         base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
     run_loop.Run();
     EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -561,9 +556,7 @@
     mojom::EmbeddedWorkerStartParamsPtr params =
         CreateStartParams(version_id2, pattern, url);
     worker2->Start(
-        std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-        CreateController(), GetInstalledScriptsInfoPtr(),
-        GetServiceWorkerHostPtrInfo(),
+        std::move(params), CreateProviderInfoGetter(),
         base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
     run_loop.Run();
     EXPECT_EQ(SERVICE_WORKER_OK, status);
@@ -602,8 +595,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, scope, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&SaveStatusAndCall, &status,
                                base::BindOnce(&base::DoNothing)));
   worker->Detach();
@@ -638,8 +629,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, scope, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&SaveStatusAndCall, &status,
                                base::BindOnce(&base::DoNothing)));
   base::RunLoop().RunUntilIdle();
@@ -681,8 +670,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, scope, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&SaveStatusAndCall, &status,
                                base::BindOnce(&base::DoNothing)));
   worker->Stop();
@@ -706,9 +693,7 @@
   std::unique_ptr<base::RunLoop> run_loop(new base::RunLoop);
   params = CreateStartParams(version_id, scope, url);
   worker->Start(
-      std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-      CreateController(), GetInstalledScriptsInfoPtr(),
-      GetServiceWorkerHostPtrInfo(),
+      std::move(params), CreateProviderInfoGetter(),
       base::BindOnce(&SaveStatusAndCall, &status, run_loop->QuitClosure()));
   run_loop->Run();
 
@@ -761,8 +746,6 @@
       CreateStartParams(version_id, scope, url);
   params->pause_after_download = true;
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&SaveStatusAndCall, &status,
                                base::BindOnce(&base::DoNothing)));
   base::RunLoop().RunUntilIdle();
@@ -794,8 +777,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, scope, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&SaveStatusAndCall, &status,
                                base::BindOnce(&base::DoNothing)));
   base::RunLoop().RunUntilIdle();
@@ -829,9 +810,7 @@
 
   params = CreateStartParams(version_id, scope, url);
   worker->Start(
-      std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-      CreateController(), GetInstalledScriptsInfoPtr(),
-      GetServiceWorkerHostPtrInfo(),
+      std::move(params), CreateProviderInfoGetter(),
       base::BindOnce(&SaveStatusAndCall, &status, run_loop->QuitClosure()));
   run_loop->Run();
 
@@ -864,9 +843,7 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, pattern, url);
   worker->Start(
-      std::move(params), CreateProviderInfoGetter(), CreateEventDispatcher(),
-      CreateController(), GetInstalledScriptsInfoPtr(),
-      GetServiceWorkerHostPtrInfo(),
+      std::move(params), CreateProviderInfoGetter(),
       base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
   run_loop.Run();
 
@@ -902,8 +879,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, pattern, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&ServiceWorkerUtils::NoOpStatusCallback));
   base::RunLoop().RunUntilIdle();
 
@@ -924,16 +899,7 @@
       : EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient(helper) {}
 
  private:
-  void StartWorker(
-      mojom::EmbeddedWorkerStartParamsPtr,
-      mojom::ServiceWorkerEventDispatcherRequest,
-      mojom::ControllerServiceWorkerRequest,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr /* unused */,
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo,
-      mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo,
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr,
-      blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy)
-      override {
+  void StartWorker(mojom::EmbeddedWorkerStartParamsPtr) override {
     helper_->mock_instance_clients()->clear();
   }
 };
@@ -960,8 +926,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, pattern, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&ServiceWorkerUtils::NoOpStatusCallback));
   base::RunLoop().RunUntilIdle();
 
@@ -1019,8 +983,6 @@
   mojom::EmbeddedWorkerStartParamsPtr params =
       CreateStartParams(version_id, pattern, url);
   worker->Start(std::move(params), CreateProviderInfoGetter(),
-                CreateEventDispatcher(), CreateController(),
-                GetInstalledScriptsInfoPtr(), GetServiceWorkerHostPtrInfo(),
                 base::BindOnce(&ServiceWorkerUtils::NoOpStatusCallback));
   worker->AddMessageToConsole(test_message.first, test_message.second);
   base::RunLoop().RunUntilIdle();
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index ed49728..c0d321fa 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -96,14 +96,7 @@
     ~MockEmbeddedWorkerInstanceClient() {}
 
 void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker(
-    mojom::EmbeddedWorkerStartParamsPtr params,
-    mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-    mojom::ControllerServiceWorkerRequest controller_request,
-    blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
-    blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-    mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-    mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-    blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy) {
+    mojom::EmbeddedWorkerStartParamsPtr params) {
   if (!helper_)
     return;
 
@@ -114,11 +107,7 @@
   ASSERT_TRUE(worker);
   EXPECT_EQ(EmbeddedWorkerStatus::STARTING, worker->status());
 
-  helper_->OnStartWorkerStub(std::move(params), std::move(dispatcher_request),
-                             std::move(controller_request),
-                             std::move(service_worker_host),
-                             std::move(instance_host), std::move(provider_info),
-                             std::move(installed_scripts_info));
+  helper_->OnStartWorkerStub(std::move(params));
 }
 
 void EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StopWorker() {
@@ -830,13 +819,7 @@
 }
 
 void EmbeddedWorkerTestHelper::OnStartWorkerStub(
-    mojom::EmbeddedWorkerStartParamsPtr params,
-    mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-    mojom::ControllerServiceWorkerRequest controller_request,
-    blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-    mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-    mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-    blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) {
+    mojom::EmbeddedWorkerStartParamsPtr params) {
   EmbeddedWorkerInstance* worker =
       registry()->GetWorker(params->embedded_worker_id);
   ASSERT_TRUE(worker);
@@ -847,9 +830,11 @@
           &EmbeddedWorkerTestHelper::OnStartWorker, AsWeakPtr(),
           params->embedded_worker_id, params->service_worker_version_id,
           params->scope, params->script_url, params->pause_after_download,
-          std::move(dispatcher_request), std::move(controller_request),
-          std::move(service_worker_host), std::move(instance_host),
-          std::move(provider_info), std::move(installed_scripts_info)));
+          std::move(params->dispatcher_request),
+          std::move(params->controller_request),
+          std::move(params->service_worker_host),
+          std::move(params->instance_host), std::move(params->provider_info),
+          std::move(params->installed_scripts_info)));
 }
 
 void EmbeddedWorkerTestHelper::OnResumeAfterDownloadStub(
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index 6f3c69d..8ff9458d 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -79,17 +79,7 @@
 
    protected:
     // mojom::EmbeddedWorkerInstanceClient implementation.
-    void StartWorker(
-        mojom::EmbeddedWorkerStartParamsPtr params,
-        mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-        mojom::ControllerServiceWorkerRequest controller_request,
-        blink::mojom::ServiceWorkerInstalledScriptsInfoPtr
-            installed_scripts_info,
-        blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-        mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-        mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-        blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy)
-        override;
+    void StartWorker(mojom::EmbeddedWorkerStartParamsPtr params) override;
     void StopWorker() override;
     void ResumeAfterDownload() override;
     void AddMessageToConsole(blink::WebConsoleMessage::Level level,
@@ -301,15 +291,7 @@
   void DidSimulateWorkerScriptCached(int embedded_worker_id,
                                      bool pause_after_download);
 
-  void OnStartWorkerStub(
-      mojom::EmbeddedWorkerStartParamsPtr params,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-      mojom::ControllerServiceWorkerRequest controller_request,
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-      mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr
-          installed_scripts_info);
+  void OnStartWorkerStub(mojom::EmbeddedWorkerStartParamsPtr params);
   void OnResumeAfterDownloadStub(int embedded_worker_id);
   void OnStopWorkerStub(int embedded_worker_id);
   void OnMessageToWorkerStub(int thread_id,
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc
index 312496c..6f97811 100644
--- a/content/browser/service_worker/service_worker_client_utils.cc
+++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -20,7 +20,6 @@
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/service_worker/service_worker_client_info.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -33,7 +32,6 @@
 #include "content/public/common/child_process_host.h"
 #include "services/network/public/interfaces/request_context_frame_type.mojom.h"
 #include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
-#include "third_party/WebKit/common/service_worker/service_worker_client.mojom.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -108,7 +106,7 @@
   DISALLOW_COPY_AND_ASSIGN(OpenURLObserver);
 };
 
-ServiceWorkerClientInfo GetWindowClientInfoOnUI(
+blink::mojom::ServiceWorkerClientInfo GetWindowClientInfoOnUI(
     int render_process_id,
     int render_frame_id,
     base::TimeTicks create_time,
@@ -117,25 +115,26 @@
   RenderFrameHostImpl* render_frame_host =
       RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
   if (!render_frame_host)
-    return ServiceWorkerClientInfo();
+    return blink::mojom::ServiceWorkerClientInfo();
 
   // TODO(mlamouri,michaeln): it is possible to end up collecting information
   // for a frame that is actually being navigated and isn't exactly what we are
   // expecting.
-  return ServiceWorkerClientInfo(
-      client_uuid, render_frame_host->GetVisibilityState(),
-      render_frame_host->IsFocused(), render_frame_host->GetLastCommittedURL(),
+  return blink::mojom::ServiceWorkerClientInfo(
+      render_frame_host->GetLastCommittedURL(), client_uuid,
+      blink::mojom::ServiceWorkerClientType::kWindow,
+      render_frame_host->GetVisibilityState(), render_frame_host->IsFocused(),
       render_frame_host->GetParent()
           ? network::mojom::RequestContextFrameType::kNested
           : network::mojom::RequestContextFrameType::kTopLevel,
-      render_frame_host->frame_tree_node()->last_focus_time(), create_time,
-      blink::mojom::ServiceWorkerClientType::kWindow);
+      render_frame_host->frame_tree_node()->last_focus_time(), create_time);
 }
 
-ServiceWorkerClientInfo FocusOnUI(int render_process_id,
-                                  int render_frame_id,
-                                  base::TimeTicks create_time,
-                                  const std::string& client_uuid) {
+blink::mojom::ServiceWorkerClientInfo FocusOnUI(
+    int render_process_id,
+    int render_frame_id,
+    base::TimeTicks create_time,
+    const std::string& client_uuid) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   RenderFrameHostImpl* render_frame_host =
       RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
@@ -143,7 +142,7 @@
       WebContents::FromRenderFrameHost(render_frame_host));
 
   if (!render_frame_host || !web_contents)
-    return ServiceWorkerClientInfo();
+    return blink::mojom::ServiceWorkerClientInfo();
 
   FrameTreeNode* frame_tree_node = render_frame_host->frame_tree_node();
 
@@ -266,13 +265,15 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (!context) {
-    callback.Run(SERVICE_WORKER_ERROR_ABORT, ServiceWorkerClientInfo());
+    callback.Run(SERVICE_WORKER_ERROR_ABORT,
+                 blink::mojom::ServiceWorkerClientInfo());
     return;
   }
 
   if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
       render_frame_id == MSG_ROUTING_NONE) {
-    callback.Run(SERVICE_WORKER_ERROR_FAILED, ServiceWorkerClientInfo());
+    callback.Run(SERVICE_WORKER_ERROR_FAILED,
+                 blink::mojom::ServiceWorkerClientInfo());
     return;
   }
 
@@ -295,7 +296,7 @@
 
   // If here, it means that no provider_host was found, in which case, the
   // renderer should still be informed that the window was opened.
-  callback.Run(SERVICE_WORKER_OK, ServiceWorkerClientInfo());
+  callback.Run(SERVICE_WORKER_OK, blink::mojom::ServiceWorkerClientInfo());
 }
 
 void AddWindowClient(
@@ -321,11 +322,12 @@
       options.client_type != host_client_type)
     return;
 
-  ServiceWorkerClientInfo client_info(
-      host->client_uuid(), blink::mojom::PageVisibilityState::kHidden,
+  blink::mojom::ServiceWorkerClientInfo client_info(
+      host->document_url(), host->client_uuid(), host_client_type,
+      blink::mojom::PageVisibilityState::kHidden,
       false,  // is_focused
-      host->document_url(), network::mojom::RequestContextFrameType::kNone,
-      base::TimeTicks(), host->create_time(), host_client_type);
+      network::mojom::RequestContextFrameType::kNone, base::TimeTicks(),
+      host->create_time());
   clients->push_back(client_info);
 }
 
@@ -339,14 +341,14 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   for (const auto& it : clients_info) {
-    ServiceWorkerClientInfo info = GetWindowClientInfoOnUI(
+    blink::mojom::ServiceWorkerClientInfo info = GetWindowClientInfoOnUI(
         std::get<0>(it), std::get<1>(it), std::get<2>(it), std::get<3>(it));
 
-    // If the request to the provider_host returned an empty
+    // If the request to the provider_host returned an invalid
     // ServiceWorkerClientInfo, that means that it wasn't possible to associate
     // it with a valid RenderFrameHost. It might be because the frame was killed
     // or navigated in between.
-    if (info.IsEmpty())
+    if (info.client_uuid.empty())
       continue;
 
     // We can get info for a frame that was navigating end ended up with a
@@ -363,8 +365,8 @@
 }
 
 struct ServiceWorkerClientInfoSort {
-  bool operator()(const ServiceWorkerClientInfo& a,
-                  const ServiceWorkerClientInfo& b) const {
+  bool operator()(const blink::mojom::ServiceWorkerClientInfo& a,
+                  const blink::mojom::ServiceWorkerClientInfo& b) const {
     // Clients for windows should be appeared earlier.
     if (a.client_type == blink::mojom::ServiceWorkerClientType::kWindow &&
         b.client_type != blink::mojom::ServiceWorkerClientType::kWindow) {
@@ -380,7 +382,7 @@
       return a.last_focus_time > b.last_focus_time;
 
     // Clients created before should be appeared earlier.
-    return a.create_time < b.create_time;
+    return a.creation_time < b.creation_time;
   }
 };
 
@@ -521,12 +523,12 @@
     return;
   }
 
-  ServiceWorkerClientInfo client_info(
-      provider_host->client_uuid(), blink::mojom::PageVisibilityState::kHidden,
+  blink::mojom::ServiceWorkerClientInfo client_info(
+      provider_host->document_url(), provider_host->client_uuid(),
+      provider_host->client_type(), blink::mojom::PageVisibilityState::kHidden,
       false,  // is_focused
-      provider_host->document_url(),
       network::mojom::RequestContextFrameType::kNone, base::TimeTicks(),
-      provider_host->create_time(), provider_host->client_type());
+      provider_host->create_time());
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                           base::BindOnce(callback, client_info));
 }
diff --git a/content/browser/service_worker/service_worker_client_utils.h b/content/browser/service_worker/service_worker_client_utils.h
index aecfdace8..4863d76a 100644
--- a/content/browser/service_worker/service_worker_client_utils.h
+++ b/content/browser/service_worker/service_worker_client_utils.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/service_worker/service_worker_status_code.h"
+#include "third_party/WebKit/common/service_worker/service_worker_client.mojom.h"
 #include "ui/base/mojo/window_open_disposition.mojom.h"
 
 class GURL;
@@ -20,17 +21,16 @@
 class ServiceWorkerContextCore;
 class ServiceWorkerProviderHost;
 class ServiceWorkerVersion;
-struct ServiceWorkerClientInfo;
 struct ServiceWorkerClientQueryOptions;
 
 namespace service_worker_client_utils {
 
-using NavigationCallback =
-    base::Callback<void(ServiceWorkerStatusCode status,
-                        const ServiceWorkerClientInfo& client_info)>;
-using ClientCallback =
-    base::Callback<void(const ServiceWorkerClientInfo& client_info)>;
-using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
+using NavigationCallback = base::Callback<void(
+    ServiceWorkerStatusCode status,
+    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 ClientsCallback =
     base::Callback<void(std::unique_ptr<ServiceWorkerClients> clients)>;
 
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index c17773d7..02e1a271 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -181,22 +181,10 @@
   const std::vector<Message>& events() const { return events_; }
 
  protected:
-  void StartWorker(
-      mojom::EmbeddedWorkerStartParamsPtr params,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-      mojom::ControllerServiceWorkerRequest controller_request,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr scripts_info,
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-      mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-      blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy)
-      override {
+  void StartWorker(mojom::EmbeddedWorkerStartParamsPtr params) override {
     events_.push_back(Message::StartWorker);
     EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker(
-        std::move(params), std::move(dispatcher_request),
-        std::move(controller_request), std::move(scripts_info),
-        std::move(service_worker_host), std::move(instance_host),
-        std::move(provider_info), std::move(content_settings_proxy));
+        std::move(params));
   }
 
   void StopWorker() override {
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index f4843cb..ed1a166 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -237,7 +237,7 @@
           sender_provider_host,
           base::Bind(&ServiceWorkerDispatcherHost::
                          DispatchExtendableMessageEventInternal<
-                             ServiceWorkerClientInfo>,
+                             blink::mojom::ServiceWorkerClientInfo>,
                      this, worker, message, source_origin, sent_message_ports,
                      base::nullopt, callback));
       break;
@@ -390,7 +390,7 @@
 
   // Hide the client url if the client has a unique origin.
   if (source_origin.unique()) {
-    if (event->source.client_info.IsValid())
+    if (IsValidSourceInfo(event->source.client_info))
       event->source.client_info.url = GURL();
     else
       event->source.service_worker_info.url = GURL();
@@ -412,18 +412,18 @@
 }
 
 bool ServiceWorkerDispatcherHost::IsValidSourceInfo(
-    const ServiceWorkerClientInfo& source_info) {
-  return source_info.IsValid();
+    const blink::mojom::ServiceWorkerClientInfo& source_info) const {
+  return !source_info.client_uuid.empty();
 }
 
 bool ServiceWorkerDispatcherHost::IsValidSourceInfo(
-    const blink::mojom::ServiceWorkerObjectInfo& source_info) {
+    const blink::mojom::ServiceWorkerObjectInfo& source_info) const {
   return source_info.handle_id != blink::mojom::kInvalidServiceWorkerHandleId &&
          source_info.version_id != blink::mojom::kInvalidServiceWorkerVersionId;
 }
 
 void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
-    const ServiceWorkerClientInfo& source_info) {
+    const blink::mojom::ServiceWorkerClientInfo& source_info) {
   // ServiceWorkerClientInfo is just a snapshot of the client. There is no need
   // to do anything for it.
 }
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index 6de6aa8..2d3c4fdc 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -179,10 +179,12 @@
       const SourceInfo& source_info,
       const StatusCallback& callback,
       ServiceWorkerStatusCode status);
-  bool IsValidSourceInfo(const ServiceWorkerClientInfo& source_info);
   bool IsValidSourceInfo(
-      const blink::mojom::ServiceWorkerObjectInfo& source_info);
-  void ReleaseSourceInfo(const ServiceWorkerClientInfo& source_info);
+      const blink::mojom::ServiceWorkerClientInfo& source_info) const;
+  bool IsValidSourceInfo(
+      const blink::mojom::ServiceWorkerObjectInfo& source_info) const;
+  void ReleaseSourceInfo(
+      const blink::mojom::ServiceWorkerClientInfo& source_info);
   void ReleaseSourceInfo(
       const blink::mojom::ServiceWorkerObjectInfo& source_info);
 
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index cfb7a9a..ab615e7 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1781,24 +1781,12 @@
   }
 
  protected:
-  void StartWorker(
-      mojom::EmbeddedWorkerStartParamsPtr params,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-      mojom::ControllerServiceWorkerRequest controller_request,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr scripts_info,
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-      mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-      blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy)
-      override {
+  void StartWorker(mojom::EmbeddedWorkerStartParamsPtr params) override {
     ASSERT_TRUE(next_pause_after_download_.has_value());
     EXPECT_EQ(next_pause_after_download_.value(), params->pause_after_download);
     num_of_startworker_++;
     EmbeddedWorkerTestHelper::MockEmbeddedWorkerInstanceClient::StartWorker(
-        std::move(params), std::move(dispatcher_request),
-        std::move(controller_request), std::move(scripts_info),
-        std::move(service_worker_host), std::move(instance_host),
-        std::move(provider_info), std::move(content_settings_proxy));
+        std::move(params));
   }
 
  private:
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index b3c74d8..e41496a 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -674,8 +674,8 @@
 ServiceWorkerVersion::CreateSimpleEventCallback(int request_id) {
   // The weak reference to |this| is safe because storage of the callbacks, the
   // inflight responses of the ServiceWorkerEventDispatcher, is owned by |this|.
-  return base::Bind(&ServiceWorkerVersion::OnSimpleEventFinished,
-                    base::Unretained(this), request_id);
+  return base::BindOnce(&ServiceWorkerVersion::OnSimpleEventFinished,
+                        base::Unretained(this), request_id);
 }
 
 void ServiceWorkerVersion::RunAfterStartWorker(
@@ -1104,7 +1104,7 @@
   if (!provider_host ||
       provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
     // The promise will be resolved to 'undefined'.
-    OnGetClientFinished(request_id, ServiceWorkerClientInfo());
+    OnGetClientFinished(request_id, blink::mojom::ServiceWorkerClientInfo());
     return;
   }
   service_worker_client_utils::GetClient(
@@ -1114,7 +1114,7 @@
 
 void ServiceWorkerVersion::OnGetClientFinished(
     int request_id,
-    const ServiceWorkerClientInfo& client_info) {
+    const blink::mojom::ServiceWorkerClientInfo& client_info) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   TRACE_EVENT_ASYNC_END1(
       "ServiceWorker", "ServiceWorkerVersion::OnGetClient", request_id,
@@ -1252,7 +1252,7 @@
 void ServiceWorkerVersion::OnOpenWindowFinished(
     int request_id,
     ServiceWorkerStatusCode status,
-    const ServiceWorkerClientInfo& client_info) {
+    const blink::mojom::ServiceWorkerClientInfo& client_info) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (running_status() != EmbeddedWorkerStatus::RUNNING)
@@ -1324,7 +1324,7 @@
 
 void ServiceWorkerVersion::OnFocusClientFinished(
     int request_id,
-    const ServiceWorkerClientInfo& client_info) {
+    const blink::mojom::ServiceWorkerClientInfo& client_info) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (running_status() != EmbeddedWorkerStatus::RUNNING)
@@ -1379,7 +1379,7 @@
 void ServiceWorkerVersion::OnNavigateClientFinished(
     int request_id,
     ServiceWorkerStatusCode status,
-    const ServiceWorkerClientInfo& client_info) {
+    const blink::mojom::ServiceWorkerClientInfo& client_info) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (running_status() != EmbeddedWorkerStatus::RUNNING)
@@ -1532,24 +1532,25 @@
   params->is_installed = IsInstalled(status_);
   params->pause_after_download = pause_after_download_;
 
-  blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info;
   if (ServiceWorkerUtils::IsScriptStreamingEnabled() && IsInstalled(status()) &&
       !pause_after_download_) {
     DCHECK(!installed_scripts_sender_);
     installed_scripts_sender_ =
         std::make_unique<ServiceWorkerInstalledScriptsSender>(this);
-    installed_scripts_info = installed_scripts_sender_->CreateInfoAndBind();
+    params->installed_scripts_info =
+        installed_scripts_sender_->CreateInfoAndBind();
     installed_scripts_sender_->Start();
   }
 
-  auto event_dispatcher_request = mojo::MakeRequest(&event_dispatcher_);
+  params->dispatcher_request = mojo::MakeRequest(&event_dispatcher_);
   // TODO(horo): These CHECKs are for debugging crbug.com/759938.
   CHECK(event_dispatcher_.is_bound());
-  CHECK(event_dispatcher_request.is_pending());
+  CHECK(params->dispatcher_request.is_pending());
 
-  blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host_ptr_info;
   binding_.Close();
-  binding_.Bind(mojo::MakeRequest(&service_worker_host_ptr_info));
+  binding_.Bind(mojo::MakeRequest(&params->service_worker_host));
+
+  params->controller_request = mojo::MakeRequest(&controller_ptr_);
 
   embedded_worker_->Start(
       std::move(params),
@@ -1557,9 +1558,6 @@
       // |embedded_worker_| whose owner is |this|.
       base::BindOnce(&CompleteProviderHostPreparation, base::Unretained(this),
                      std::move(provider_host), context()),
-      mojo::MakeRequest(&event_dispatcher_),
-      mojo::MakeRequest(&controller_ptr_), std::move(installed_scripts_info),
-      std::move(service_worker_host_ptr_info),
       base::BindOnce(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
                      weak_factory_.GetWeakPtr()));
   event_dispatcher_.set_connection_error_handler(base::BindOnce(
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index bdb230c..9e35eb3 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -62,7 +62,6 @@
 class ServiceWorkerInstalledScriptsSender;
 class ServiceWorkerProviderHost;
 class ServiceWorkerRegistration;
-struct ServiceWorkerClientInfo;
 struct ServiceWorkerVersionInfo;
 
 namespace service_worker_controllee_request_handler_unittest {
@@ -114,12 +113,10 @@
       public base::RefCounted<ServiceWorkerVersion>,
       public EmbeddedWorkerInstance::Listener {
  public:
-  // TODO(crbug.com/755477): LegacyStatusCallback which does not use
-  // OnceCallback is deprecated and should be removed soon.
-  using LegacyStatusCallback = base::Callback<void(ServiceWorkerStatusCode)>;
   using StatusCallback = base::OnceCallback<void(ServiceWorkerStatusCode)>;
   using SimpleEventCallback =
-      base::Callback<void(blink::mojom::ServiceWorkerEventStatus, base::Time)>;
+      base::OnceCallback<void(blink::mojom::ServiceWorkerEventStatus,
+                              base::Time)>;
 
   // Current version status; some of the status (e.g. INSTALLED and ACTIVATED)
   // should be persisted unlike running status.
@@ -573,7 +570,8 @@
     std::set<InflightRequestTimeoutInfo>::iterator timeout_iter;
   };
 
-  using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
+  using ServiceWorkerClients =
+      std::vector<blink::mojom::ServiceWorkerClientInfo>;
 
   // The timeout timer interval.
   static constexpr base::TimeDelta kTimeoutTimerDelay =
@@ -645,9 +643,10 @@
   void OnOpenWindow(int request_id,
                     GURL url,
                     WindowOpenDisposition disposition);
-  void OnOpenWindowFinished(int request_id,
-                            ServiceWorkerStatusCode status,
-                            const ServiceWorkerClientInfo& client_info);
+  void OnOpenWindowFinished(
+      int request_id,
+      ServiceWorkerStatusCode status,
+      const blink::mojom::ServiceWorkerClientInfo& client_info);
 
   void OnPostMessageToClient(
       const std::string& client_uuid,
@@ -657,14 +656,16 @@
   void OnNavigateClient(int request_id,
                         const std::string& client_uuid,
                         const GURL& url);
-  void OnNavigateClientFinished(int request_id,
-                                ServiceWorkerStatusCode status,
-                                const ServiceWorkerClientInfo& client_info);
+  void OnNavigateClientFinished(
+      int request_id,
+      ServiceWorkerStatusCode status,
+      const blink::mojom::ServiceWorkerClientInfo& client_info);
   void OnSkipWaiting(int request_id);
   void OnPongFromWorker();
 
-  void OnFocusClientFinished(int request_id,
-                             const ServiceWorkerClientInfo& client_info);
+  void OnFocusClientFinished(
+      int request_id,
+      const blink::mojom::ServiceWorkerClientInfo& client_info);
 
   void DidEnsureLiveRegistrationForStartWorker(
       ServiceWorkerMetrics::EventType purpose,
@@ -684,8 +685,9 @@
                              blink::mojom::ServiceWorkerEventStatus status,
                              base::Time dispatch_event_time);
 
-  void OnGetClientFinished(int request_id,
-                           const ServiceWorkerClientInfo& client_info);
+  void OnGetClientFinished(
+      int request_id,
+      const blink::mojom::ServiceWorkerClientInfo& client_info);
 
   void OnGetClientsFinished(int request_id,
                             std::unique_ptr<ServiceWorkerClients> clients);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 22a73db..e5c7baf 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -6688,7 +6688,7 @@
   // Send a mouse wheel event to the main frame. If wheel scroll latching is
   // enabled it will be still routed to child till the end of current scrolling
   // sequence.
-  SendMouseWheel(gfx::Point(10, 10));
+  SendMouseWheel(pos);
   if (child_rwhv->wheel_scroll_latching_enabled())
     EXPECT_EQ(child_rwhv, router->wheel_target_.target);
   else
@@ -7061,6 +7061,20 @@
     RenderWidgetHostViewBase* expected_target) {
   auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
 
+  if (root_view_aura->wheel_scroll_latching_enabled()) {
+    // Touchpad Fling must be sent inside a gesture scroll seqeunce.
+    blink::WebGestureEvent gesture_event(
+        blink::WebGestureEvent::kGestureScrollBegin,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::kTimeStampForTesting);
+    gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
+    gesture_event.x = gesture_point.x();
+    gesture_event.y = gesture_point.y();
+    gesture_event.data.scroll_begin.delta_x_hint = 0.0f;
+    gesture_event.data.scroll_begin.delta_y_hint = 1.0f;
+    expected_target->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event);
+  }
+
   ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gesture_point,
                               ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
   root_view_aura->OnScrollEvent(&fling_start);
@@ -7070,6 +7084,17 @@
                                ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
   root_view_aura->OnScrollEvent(&fling_cancel);
   EXPECT_EQ(expected_target, router_touchpad_gesture_target);
+
+  if (root_view_aura->wheel_scroll_latching_enabled()) {
+    blink::WebGestureEvent gesture_event(
+        blink::WebGestureEvent::kGestureScrollEnd,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::kTimeStampForTesting);
+    gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
+    gesture_event.x = gesture_point.x();
+    gesture_event.y = gesture_point.y();
+    expected_target->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event);
+  }
 }
 #endif
 
diff --git a/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc b/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
index 1a1e0cda..b519009 100644
--- a/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
+++ b/content/browser/webrtc/webrtc_audio_debug_recordings_browsertest.cc
@@ -77,6 +77,19 @@
   return ret;
 }
 
+// Deletes the the file specified by |path|. If that fails, waits for 100 ms and
+// tries again. Returns true if the delete was successful.
+// This is to handle when not being able to delete the file due to race when the
+// file is being closed. See comment for CallWithAudioDebugRecordings test case
+// below.
+bool DeleteFileWithRetryAfterPause(const base::FilePath& path, bool recursive) {
+  if (base::DeleteFile(path, recursive))
+    return true;
+
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  return base::DeleteFile(path, recursive);
+}
+
 }  // namespace
 
 namespace content {
@@ -110,9 +123,8 @@
 // Note: Both stopping the streams (at hangup()) and disabling the recordings
 // are asynchronous without response when finished. This means that closing the
 // files is asynchronous and being able to delete the files in the test is
-// therefore timing dependent and flaky prone. If it becomes flaky, it's
-// probably good enough to change the test to retry deleting after a short
-// sleep.
+// therefore timing dependent and flaky prone. For this reason we use
+// DeleteFileWithRetryAfterPause() as a simple mitigation.
 IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest,
                        MAYBE_CallWithAudioDebugRecordings) {
   if (!HasAudioOutputDevices()) {
@@ -156,7 +168,7 @@
   int64_t file_size = 0;
   EXPECT_TRUE(base::GetFileSize(input_files[0], &file_size));
   EXPECT_GT(file_size, kWaveHeaderSizeBytes);
-  EXPECT_TRUE(base::DeleteFile(input_files[0], false));
+  EXPECT_TRUE(DeleteFileWithRetryAfterPause(input_files[0], false));
 
   // Verify that the expected output audio files exist and contain some data.
   // Two files are expected, one for each peer in the call.
@@ -167,7 +179,7 @@
     file_size = 0;
     EXPECT_TRUE(base::GetFileSize(file_path, &file_size));
     EXPECT_GT(file_size, kWaveHeaderSizeBytes);
-    EXPECT_TRUE(base::DeleteFile(file_path, false));
+    EXPECT_TRUE(DeleteFileWithRetryAfterPause(file_path, false));
   }
 
   // Verify that the expected AEC dump file exists and contains some data.
@@ -179,7 +191,7 @@
   file_size = 0;
   EXPECT_TRUE(base::GetFileSize(file_path, &file_size));
   EXPECT_GT(file_size, 0);
-  EXPECT_TRUE(base::DeleteFile(file_path, false));
+  EXPECT_TRUE(DeleteFileWithRetryAfterPause(file_path, false));
 
   // Verify that no other files exist and remove temp dir.
   EXPECT_TRUE(base::IsDirectoryEmpty(temp_dir_path));
@@ -311,7 +323,7 @@
     file_size = 0;
     EXPECT_TRUE(base::GetFileSize(file_path, &file_size));
     EXPECT_GT(file_size, kWaveHeaderSizeBytes);
-    EXPECT_TRUE(base::DeleteFile(file_path, false));
+    EXPECT_TRUE(DeleteFileWithRetryAfterPause(file_path, false));
   }
 
   // Verify that the expected output audio files exist and contain some data.
@@ -324,7 +336,7 @@
     file_size = 0;
     EXPECT_TRUE(base::GetFileSize(file_path, &file_size));
     EXPECT_GT(file_size, kWaveHeaderSizeBytes);
-    EXPECT_TRUE(base::DeleteFile(file_path, false));
+    EXPECT_TRUE(DeleteFileWithRetryAfterPause(file_path, false));
   }
 
   // Verify that the expected AEC dump files exist and contain some data.
@@ -341,7 +353,7 @@
     file_size = 0;
     EXPECT_TRUE(base::GetFileSize(file_path, &file_size));
     EXPECT_GT(file_size, 0);
-    EXPECT_TRUE(base::DeleteFile(file_path, false));
+    EXPECT_TRUE(DeleteFileWithRetryAfterPause(file_path, false));
   }
 
   // Verify that no other files exist and remove temp dir.
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 726c909..2a238646 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -273,8 +273,6 @@
     "service_manager/service_manager_connection_impl.cc",
     "service_manager/service_manager_connection_impl.h",
     "service_worker/embedded_worker_messages.h",
-    "service_worker/service_worker_client_info.cc",
-    "service_worker/service_worker_client_info.h",
     "service_worker/service_worker_loader_helpers.cc",
     "service_worker/service_worker_loader_helpers.h",
     "service_worker/service_worker_messages.h",
@@ -535,7 +533,6 @@
     "child.mojom",
     "child_control.mojom",
     "child_memory_coordinator.mojom",
-    "devtools.mojom",
     "field_trial_recorder.mojom",
     "file_utilities.mojom",
     "frame.mojom",
diff --git a/content/common/page_messages.h b/content/common/page_messages.h
index a1d38aab..423a9f1 100644
--- a/content/common/page_messages.h
+++ b/content/common/page_messages.h
@@ -11,6 +11,7 @@
 #include "ui/gfx/geometry/rect.h"
 
 // IPC messages for page-level actions.
+// TODO(https://crbug.com/775827): Convert to mojo.
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
diff --git a/content/common/service_worker/embedded_worker.mojom b/content/common/service_worker/embedded_worker.mojom
index 9d9179b..db83900 100644
--- a/content/common/service_worker/embedded_worker.mojom
+++ b/content/common/service_worker/embedded_worker.mojom
@@ -48,6 +48,23 @@
   V8CacheOptions v8_cache_options;
   // True if Data Saver is enabled.
   bool data_saver_enabled;
+
+  // Used to dispatch events from (via) the browser process.
+  ServiceWorkerEventDispatcher& dispatcher_request;
+  // S13nServiceWorker: cloned and passed to each controllee to directly
+  // dispatch events from the controllees.
+  ControllerServiceWorker& controller_request;
+  // Information to transfer installed scripts from the browser to the renderer.
+  blink.mojom.ServiceWorkerInstalledScriptsInfo? installed_scripts_info;
+  // Interface for the renderer to ask the browser to do operations needed for
+  // ServiceWorkerGlobalScope functionalities.
+  associated blink.mojom.ServiceWorkerHost service_worker_host;
+  // Interface for the renderer to send the status updates to the browser.
+  associated EmbeddedWorkerInstanceHost instance_host;
+  // Information for creating ServiceWorkerNetworkProvider on the renderer.
+  ServiceWorkerProviderInfoForStartWorker provider_info;
+  // Interface for the renderer to query the content settings in the browser.
+  blink.mojom.WorkerContentSettingsProxy content_settings_proxy;
 };
 
 // Holds timing information about the start worker sequence for UMA.
@@ -65,20 +82,7 @@
 interface EmbeddedWorkerInstanceClient {
   // Called back as various functions in EmbeddedWorkerInstanceHost, such
   // as OnThreadStarted(), OnStarted().
-  // |dispatcher_request| is used to dispatch events from (via) the browser
-  // process.
-  //
-  // S13nServiceWorker:
-  // |controller_request| is cloned and passed to each
-  // controllee to directly dispatch events from the controllees.
-  StartWorker(EmbeddedWorkerStartParams params,
-              ServiceWorkerEventDispatcher& dispatcher_request,
-              ControllerServiceWorker& controller_request,
-              blink.mojom.ServiceWorkerInstalledScriptsInfo? installed_scripts_info,
-              associated blink.mojom.ServiceWorkerHost service_worker_host,
-              associated EmbeddedWorkerInstanceHost instance_host,
-              ServiceWorkerProviderInfoForStartWorker provider_info,
-              blink.mojom.WorkerContentSettingsProxy content_settings_proxy);
+  StartWorker(EmbeddedWorkerStartParams params);
   // The response is sent back via EmbeddedWorkerInstanceHost.OnStopped().
   StopWorker();
   ResumeAfterDownload();
diff --git a/content/common/service_worker/service_worker_client_info.cc b/content/common/service_worker/service_worker_client_info.cc
deleted file mode 100644
index 9e6c72e..0000000
--- a/content/common/service_worker/service_worker_client_info.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/service_worker/service_worker_client_info.h"
-
-#include "base/logging.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "services/network/public/interfaces/request_context_frame_type.mojom.h"
-#include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
-#include "third_party/WebKit/common/service_worker/service_worker_client.mojom.h"
-
-namespace content {
-
-ServiceWorkerClientInfo::ServiceWorkerClientInfo()
-    : ServiceWorkerClientInfo(
-          std::string(),
-          blink::mojom::PageVisibilityState::kLast,
-          false,
-          GURL(),
-          network::mojom::RequestContextFrameType::kTopLevel,
-          base::TimeTicks(),
-          base::TimeTicks(),
-          blink::mojom::ServiceWorkerClientType::kLast) {}
-
-ServiceWorkerClientInfo::ServiceWorkerClientInfo(
-    const std::string& client_uuid,
-    blink::mojom::PageVisibilityState page_visibility_state,
-    bool is_focused,
-    const GURL& url,
-    network::mojom::RequestContextFrameType frame_type,
-    base::TimeTicks last_focus_time,
-    base::TimeTicks create_time,
-    blink::mojom::ServiceWorkerClientType client_type)
-    : client_uuid(client_uuid),
-      page_visibility_state(page_visibility_state),
-      is_focused(is_focused),
-      url(url),
-      frame_type(frame_type),
-      last_focus_time(last_focus_time),
-      create_time(create_time),
-      client_type(client_type) {}
-
-ServiceWorkerClientInfo::ServiceWorkerClientInfo(
-    const ServiceWorkerClientInfo& other) = default;
-
-bool ServiceWorkerClientInfo::IsEmpty() const {
-  return page_visibility_state == blink::mojom::PageVisibilityState::kLast &&
-         is_focused == false && url.is_empty() &&
-         frame_type == network::mojom::RequestContextFrameType::kTopLevel &&
-         client_type == blink::mojom::ServiceWorkerClientType::kLast;
-}
-
-bool ServiceWorkerClientInfo::IsValid() const {
-  return !IsEmpty() && !client_uuid.empty();
-}
-
-}  // namespace content
diff --git a/content/common/service_worker/service_worker_client_info.h b/content/common/service_worker/service_worker_client_info.h
deleted file mode 100644
index 7e19c2c..0000000
--- a/content/common/service_worker/service_worker_client_info.h
+++ /dev/null
@@ -1,53 +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_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_
-#define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_
-
-#include "base/time/time.h"
-#include "services/network/public/interfaces/request_context_frame_type.mojom.h"
-#include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
-#include "third_party/WebKit/common/service_worker/service_worker_client.mojom.h"
-#include "url/gurl.h"
-
-namespace content {
-
-// This class holds the information related to a service worker window client.
-// It is the content/ equivalent of Blink's WebServiceWorkerClientInfo.
-// An instance can be created empty or can be filed with the expected
-// properties. Except for the client_uuid, it is preferred to use the
-// constructor to fill the properties.
-struct ServiceWorkerClientInfo {
-  ServiceWorkerClientInfo();
-  ServiceWorkerClientInfo(
-      const std::string& client_uuid,
-      blink::mojom::PageVisibilityState page_visibility_state,
-      bool is_focused,
-      const GURL& url,
-      network::mojom::RequestContextFrameType frame_type,
-      base::TimeTicks last_focus_time,
-      base::TimeTicks create_time,
-      blink::mojom::ServiceWorkerClientType client_type);
-  ServiceWorkerClientInfo(const ServiceWorkerClientInfo& other);
-
-  // Returns whether the instance is empty.
-  bool IsEmpty() const;
-
-  // Returns whether the instance is valid. A valid instance is not empty and
-  // has a valid client_uuid.
-  bool IsValid() const;
-
-  std::string client_uuid;
-  blink::mojom::PageVisibilityState page_visibility_state;
-  bool is_focused;
-  GURL url;
-  network::mojom::RequestContextFrameType frame_type;
-  base::TimeTicks last_focus_time;
-  base::TimeTicks create_time;
-  blink::mojom::ServiceWorkerClientType client_type;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_
diff --git a/content/common/service_worker/service_worker_event_dispatcher.typemap b/content/common/service_worker/service_worker_event_dispatcher.typemap
index 2c7bc26..f09c55f 100644
--- a/content/common/service_worker/service_worker_event_dispatcher.typemap
+++ b/content/common/service_worker/service_worker_event_dispatcher.typemap
@@ -5,7 +5,6 @@
 mojom = "//content/common/service_worker/service_worker_event_dispatcher.mojom"
 public_headers = [
   "//content/common/background_fetch/background_fetch_types.h",
-  "//content/common/service_worker/service_worker_client_info.h",
   "//content/common/service_worker/service_worker_status_code.h",
   "//content/common/service_worker/service_worker_types.h",
   "//content/public/common/platform_notification_data.h",
diff --git a/content/common/service_worker/service_worker_fetch_request.typemap b/content/common/service_worker/service_worker_fetch_request.typemap
index fd1d53e..8e1fe8c 100644
--- a/content/common/service_worker/service_worker_fetch_request.typemap
+++ b/content/common/service_worker/service_worker_fetch_request.typemap
@@ -5,7 +5,6 @@
 mojom =
     "//third_party/WebKit/public/platform/modules/fetch/fetch_api_request.mojom"
 public_headers = [
-  "//content/common/service_worker/service_worker_client_info.h",
   "//content/common/service_worker/service_worker_types.h",
   "//content/public/common/request_context_type.h",
   "//content/public/common/service_worker_modes.h",
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index e285067b..920008d 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -12,7 +12,6 @@
 
 #include "base/strings/string16.h"
 #include "base/time/time.h"
-#include "content/common/service_worker/service_worker_client_info.h"
 #include "content/common/service_worker/service_worker_status_code.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/platform_notification_data.h"
@@ -100,7 +99,7 @@
   IPC_STRUCT_TRAITS_MEMBER(version_id)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(content::ServiceWorkerClientInfo)
+IPC_STRUCT_TRAITS_BEGIN(blink::mojom::ServiceWorkerClientInfo)
   IPC_STRUCT_TRAITS_MEMBER(client_uuid)
   IPC_STRUCT_TRAITS_MEMBER(page_visibility_state)
   IPC_STRUCT_TRAITS_MEMBER(is_focused)
@@ -207,17 +206,17 @@
 // Sent via EmbeddedWorker as a response of GetClient.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClient,
                      int /* request_id */,
-                     content::ServiceWorkerClientInfo)
+                     blink::mojom::ServiceWorkerClientInfo)
 
 // Sent via EmbeddedWorker as a response of GetClients.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClients,
                      int /* request_id */,
-                     std::vector<content::ServiceWorkerClientInfo>)
+                     std::vector<blink::mojom::ServiceWorkerClientInfo>)
 
 // Sent via EmbeddedWorker as a response of OpenWindow.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_OpenWindowResponse,
                      int /* request_id */,
-                     content::ServiceWorkerClientInfo /* client */)
+                     blink::mojom::ServiceWorkerClientInfo /* client */)
 
 // Sent via EmbeddedWorker as an error response of OpenWindow.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_OpenWindowError,
@@ -227,12 +226,12 @@
 // Sent via EmbeddedWorker as a response of FocusClient.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_FocusClientResponse,
                      int /* request_id */,
-                     content::ServiceWorkerClientInfo /* client */)
+                     blink::mojom::ServiceWorkerClientInfo /* client */)
 
 // Sent via EmbeddedWorker as a response of NavigateClient.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_NavigateClientResponse,
                      int /* request_id */,
-                     content::ServiceWorkerClientInfo /* client */)
+                     blink::mojom::ServiceWorkerClientInfo /* client */)
 
 // Sent via EmbeddedWorker as an error response of NavigateClient.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_NavigateClientError,
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc
index 845669b..bb96725 100644
--- a/content/common/service_worker/service_worker_types.cc
+++ b/content/common/service_worker/service_worker_types.cc
@@ -154,7 +154,7 @@
 ExtendableMessageEventSource::ExtendableMessageEventSource() {}
 
 ExtendableMessageEventSource::ExtendableMessageEventSource(
-    const ServiceWorkerClientInfo& client_info)
+    const blink::mojom::ServiceWorkerClientInfo& client_info)
     : client_info(client_info) {}
 
 ExtendableMessageEventSource::ExtendableMessageEventSource(
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h
index 6e6e494d..78dcfda 100644
--- a/content/common/service_worker/service_worker_types.h
+++ b/content/common/service_worker/service_worker_types.h
@@ -14,7 +14,6 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
-#include "content/common/service_worker/service_worker_client_info.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/request_context_type.h"
 #include "content/public/common/service_worker_modes.h"
@@ -192,12 +191,12 @@
 struct ExtendableMessageEventSource {
   ExtendableMessageEventSource();
   explicit ExtendableMessageEventSource(
-      const ServiceWorkerClientInfo& client_info);
+      const blink::mojom::ServiceWorkerClientInfo& client_info);
   explicit ExtendableMessageEventSource(
       const blink::mojom::ServiceWorkerObjectInfo& service_worker_info);
 
   // Exactly one of these infos should be valid.
-  ServiceWorkerClientInfo client_info;
+  blink::mojom::ServiceWorkerClientInfo client_info;
   blink::mojom::ServiceWorkerObjectInfo service_worker_info;
 };
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index c91654d1..1c4a15a 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -92,8 +92,6 @@
     "device_sensors/device_orientation_event_pump.cc",
     "device_sensors/device_orientation_event_pump.h",
     "device_sensors/device_sensor_event_pump.h",
-    "devtools/devtools_agent.cc",
-    "devtools/devtools_agent.h",
     "devtools/render_widget_screen_metrics_emulator.cc",
     "devtools/render_widget_screen_metrics_emulator.h",
     "devtools/render_widget_screen_metrics_emulator_delegate.h",
diff --git a/content/renderer/devtools/devtools_agent.cc b/content/renderer/devtools/devtools_agent.cc
deleted file mode 100644
index dbb576f..0000000
--- a/content/renderer/devtools/devtools_agent.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/devtools/devtools_agent.h"
-
-#include <stddef.h>
-
-#include <map>
-#include <utility>
-
-#include "base/json/json_writer.h"
-#include "base/lazy_instance.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/child/child_process.h"
-#include "content/common/devtools_messages.h"
-#include "content/common/frame_messages.h"
-#include "content/public/common/manifest.h"
-#include "content/renderer/render_frame_impl.h"
-#include "content/renderer/render_widget.h"
-#include "ipc/ipc_channel.h"
-#include "third_party/WebKit/public/platform/WebFloatRect.h"
-#include "third_party/WebKit/public/platform/WebPoint.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-
-using blink::WebDevToolsAgent;
-using blink::WebDevToolsAgentClient;
-using blink::WebLocalFrame;
-using blink::WebPoint;
-using blink::WebString;
-
-using base::trace_event::TraceLog;
-
-namespace content {
-
-namespace {
-
-// TODO(dgozman): somehow get this from a mojo config.
-// See kMaximumMojoMessageSize in services/service_manager/embedder/main.cc.
-const size_t kMaxDevToolsMessageChunkSize = 128 * 1024 * 1024 / 4;
-
-} //  namespace
-
-class DevToolsAgent::MessageImpl : public WebDevToolsAgent::MessageDescriptor {
- public:
-  MessageImpl(base::WeakPtr<DevToolsAgent> agent,
-              const std::string& method,
-              const std::string& message)
-      : agent_(std::move(agent)), method_(method), msg_(message) {}
-  ~MessageImpl() override {}
-
-  WebDevToolsAgent* Agent() override {
-    if (!agent_)
-      return nullptr;
-    return agent_->GetWebAgent();
-  }
-  WebString Message() override { return WebString::FromUTF8(msg_); }
-  WebString Method() override { return WebString::FromUTF8(method_); }
-
- private:
-  base::WeakPtr<DevToolsAgent> agent_;
-  std::string method_;
-  std::string msg_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageImpl);
-};
-
-// Created and stored in unique_ptr on UI.
-// Binds request, receives messages and destroys on IO.
-class DevToolsAgent::IOSession : public mojom::DevToolsSession {
- public:
-  IOSession(int session_id,
-            base::SequencedTaskRunner* session_task_runner,
-            scoped_refptr<base::SingleThreadTaskRunner> agent_task_runner,
-            base::WeakPtr<DevToolsAgent> agent,
-            mojom::DevToolsSessionRequest request)
-      : session_id_(session_id),
-        agent_task_runner_(agent_task_runner),
-        agent_(std::move(agent)),
-        binding_(this) {
-    session_task_runner->PostTask(
-        FROM_HERE, base::BindOnce(&IOSession::BindInterface,
-                                  base::Unretained(this), std::move(request)));
-  }
-
-  ~IOSession() override {}
-
-  void BindInterface(mojom::DevToolsSessionRequest request) {
-    binding_.Bind(std::move(request));
-  }
-
-  // mojom::DevToolsSession implementation.
-  void DispatchProtocolMessage(int call_id,
-                               const std::string& method,
-                               const std::string& message) override {
-    DCHECK(WebDevToolsAgent::ShouldInterruptForMethod(
-        WebString::FromUTF8(method)));
-    WebDevToolsAgent::InterruptAndDispatch(
-        session_id_, new DevToolsAgent::MessageImpl(agent_, method, message));
-    agent_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&DevToolsAgent::DispatchOnInspectorBackend,
-                              agent_, session_id_, call_id, method, message));
-  }
-
-  void InspectElement(const gfx::Point& point) override { NOTREACHED(); }
-
- private:
-  int session_id_;
-  scoped_refptr<base::SingleThreadTaskRunner> agent_task_runner_;
-  base::WeakPtr<DevToolsAgent> agent_;
-  mojo::Binding<mojom::DevToolsSession> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(IOSession);
-};
-
-class DevToolsAgent::Session : public mojom::DevToolsSession {
- public:
-  Session(int session_id,
-          DevToolsAgent* agent,
-          mojom::DevToolsSessionAssociatedRequest request)
-      : session_id_(session_id),
-        agent_(agent),
-        binding_(this, std::move(request)) {}
-
-  ~Session() override {}
-
-  // mojom::DevToolsSession implementation.
-  void DispatchProtocolMessage(int call_id,
-                               const std::string& method,
-                               const std::string& message) override {
-    DCHECK(!WebDevToolsAgent::ShouldInterruptForMethod(
-        WebString::FromUTF8(method)));
-    agent_->DispatchOnInspectorBackend(session_id_, call_id, method, message);
-  }
-
-  void InspectElement(const gfx::Point& point) override {
-    agent_->InspectElement(session_id_, point);
-  }
-
- private:
-  int session_id_;
-  DevToolsAgent* agent_;
-  mojo::AssociatedBinding<mojom::DevToolsSession> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(Session);
-};
-
-DevToolsAgent::DevToolsAgent(RenderFrameImpl* frame)
-    : RenderFrameObserver(frame),
-      binding_(this),
-      frame_(frame),
-      weak_factory_(this) {
-  frame_->GetWebFrame()->SetDevToolsAgentClient(this);
-}
-
-DevToolsAgent::~DevToolsAgent() {
-}
-
-void DevToolsAgent::OnDestruct() {
-  delete this;
-}
-
-void DevToolsAgent::AttachDevToolsSession(
-    mojom::DevToolsSessionHostAssociatedPtrInfo host,
-    mojom::DevToolsSessionAssociatedRequest session,
-    mojom::DevToolsSessionRequest io_session,
-    const base::Optional<std::string>& reattach_state) {
-  int session_id = ++last_session_id_;
-
-  if (reattach_state.has_value()) {
-    GetWebAgent()->Reattach(session_id,
-                            WebString::FromUTF8(reattach_state.value()));
-  } else {
-    GetWebAgent()->Attach(session_id);
-  }
-
-  sessions_[session_id].reset(
-      new Session(session_id, this, std::move(session)));
-
-  base::SequencedTaskRunner* io_task_runner =
-      ChildProcess::current()->io_task_runner();
-  io_sessions_.emplace(
-      session_id,
-      std::unique_ptr<IOSession, base::OnTaskRunnerDeleter>(
-          new IOSession(session_id, io_task_runner,
-                        frame_->GetTaskRunner(blink::TaskType::kUnthrottled),
-                        weak_factory_.GetWeakPtr(), std::move(io_session)),
-          base::OnTaskRunnerDeleter(io_task_runner)));
-
-  hosts_[session_id].Bind(std::move(host));
-  hosts_[session_id].set_connection_error_handler(base::BindOnce(
-      &DevToolsAgent::DetachSession, base::Unretained(this), session_id));
-}
-
-void DevToolsAgent::DetachSession(int session_id) {
-  GetWebAgent()->Detach(session_id);
-  io_sessions_.erase(session_id);
-  sessions_.erase(session_id);
-  hosts_.erase(session_id);
-}
-
-void DevToolsAgent::SendProtocolMessage(int session_id,
-                                        int call_id,
-                                        const blink::WebString& message,
-                                        const blink::WebString& state_cookie) {
-  SendChunkedProtocolMessage(session_id, call_id, message.Utf8(),
-                             state_cookie.Utf8());
-}
-
-void DevToolsAgent::SendChunkedProtocolMessage(int session_id,
-                                               int call_id,
-                                               std::string message,
-                                               std::string post_state) {
-  auto it = hosts_.find(session_id);
-  if (it == hosts_.end())
-    return;
-
-  bool single_chunk = message.length() < kMaxDevToolsMessageChunkSize;
-  for (size_t pos = 0; pos < message.length();
-       pos += kMaxDevToolsMessageChunkSize) {
-    mojom::DevToolsMessageChunkPtr chunk = mojom::DevToolsMessageChunk::New();
-    chunk->is_first = pos == 0;
-    chunk->message_size = chunk->is_first ? message.size() : 0;
-    chunk->is_last = pos + kMaxDevToolsMessageChunkSize >= message.length();
-    chunk->call_id = chunk->is_last ? call_id : 0;
-    chunk->post_state = chunk->is_last ? std::move(post_state) : std::string();
-    chunk->data = single_chunk
-                      ? std::move(message)
-                      : message.substr(pos, kMaxDevToolsMessageChunkSize);
-    it->second->DispatchProtocolMessage(std::move(chunk));
-  }
-}
-
-void DevToolsAgent::DispatchOnInspectorBackend(int session_id,
-                                               int call_id,
-                                               const std::string& method,
-                                               const std::string& message) {
-  TRACE_EVENT0("devtools", "DevToolsAgent::DispatchOnInspectorBackend");
-  GetWebAgent()->DispatchOnInspectorBackend(session_id, call_id,
-                                            WebString::FromUTF8(method),
-                                            WebString::FromUTF8(message));
-}
-
-void DevToolsAgent::InspectElement(int session_id, const gfx::Point& point) {
-  GetWebAgent()->InspectElementAt(session_id, WebPoint(point.x(), point.y()));
-}
-
-WebDevToolsAgent* DevToolsAgent::GetWebAgent() {
-  return frame_->GetWebFrame()->DevToolsAgent();
-}
-
-void DevToolsAgent::BindRequest(mojom::DevToolsAgentAssociatedRequest request) {
-  binding_.Bind(std::move(request));
-}
-
-base::WeakPtr<DevToolsAgent> DevToolsAgent::GetWeakPtr() {
-  return weak_factory_.GetWeakPtr();
-}
-
-}  // namespace content
diff --git a/content/renderer/devtools/devtools_agent.h b/content/renderer/devtools/devtools_agent.h
deleted file mode 100644
index d08683e..0000000
--- a/content/renderer/devtools/devtools_agent.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_
-#define CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/callback.h"
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
-#include "content/common/devtools.mojom.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "third_party/WebKit/public/web/WebDevToolsAgentClient.h"
-
-namespace blink {
-class WebDevToolsAgent;
-}
-
-namespace content {
-
-class RenderFrameImpl;
-
-// Implementation of content.mojom.DevToolsAgent interface for RenderFrameImpl.
-class CONTENT_EXPORT DevToolsAgent : public RenderFrameObserver,
-                                     public blink::WebDevToolsAgentClient,
-                                     public mojom::DevToolsAgent {
- public:
-  explicit DevToolsAgent(RenderFrameImpl* frame);
-  ~DevToolsAgent() override;
-
-  void BindRequest(mojom::DevToolsAgentAssociatedRequest request);
-  base::WeakPtr<DevToolsAgent> GetWeakPtr();
-
- private:
-  class Session;
-  class IOSession;
-  class MessageImpl;
-
-  // RenderFrameObserver implementation.
-  void OnDestruct() override;
-
-  // mojom::DevToolsAgent implementation.
-  void AttachDevToolsSession(
-      mojom::DevToolsSessionHostAssociatedPtrInfo host,
-      mojom::DevToolsSessionAssociatedRequest session,
-      mojom::DevToolsSessionRequest io_session,
-      const base::Optional<std::string>& reattach_state) override;
-
-  // WebDevToolsAgentClient implementation.
-  void SendProtocolMessage(int session_id,
-                           int call_id,
-                           const blink::WebString& message,
-                           const blink::WebString& state_cookie) override;
-
-  void DetachSession(int session_id);
-  blink::WebDevToolsAgent* GetWebAgent();
-  void DispatchOnInspectorBackend(int session_id,
-                                  int call_id,
-                                  const std::string& method,
-                                  const std::string& message);
-  void InspectElement(int session_id, const gfx::Point& point);
-  void SendChunkedProtocolMessage(int session_id,
-                                  int call_id,
-                                  std::string message,
-                                  std::string post_state);
-
-  mojo::AssociatedBinding<mojom::DevToolsAgent> binding_;
-  int last_session_id_ = 0;
-  base::flat_map<int, std::unique_ptr<Session>> sessions_;
-  base::flat_map<int, std::unique_ptr<IOSession, base::OnTaskRunnerDeleter>>
-      io_sessions_;
-  base::flat_map<int, mojom::DevToolsSessionHostAssociatedPtr> hosts_;
-  RenderFrameImpl* frame_;
-  base::WeakPtrFactory<DevToolsAgent> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(DevToolsAgent);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index dc4dd961..859d102 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -94,7 +94,6 @@
 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
 #include "content/renderer/content_security_policy_util.h"
 #include "content/renderer/context_menu_params_builder.h"
-#include "content/renderer/devtools/devtools_agent.h"
 #include "content/renderer/dom_automation_controller.h"
 #include "content/renderer/effective_connection_type_helper.h"
 #include "content/renderer/external_popup_menu.h"
@@ -1286,7 +1285,6 @@
       selection_range_(gfx::Range::InvalidRange()),
       handling_select_range_(false),
       web_user_media_client_(nullptr),
-      devtools_agent_(nullptr),
       presentation_dispatcher_(nullptr),
       push_messaging_client_(nullptr),
       screen_orientation_dispatcher_(nullptr),
@@ -1429,12 +1427,6 @@
   GetWebFrame()->SetSharedWorkerRepositoryClient(
       shared_worker_repository_.get());
 
-  if (IsLocalRoot()) {
-    // DevToolsAgent is a RenderFrameObserver, and will destruct itself
-    // when |this| is deleted.
-    devtools_agent_ = new DevToolsAgent(this);
-  }
-
   RegisterMojoInterfaces();
 
   // We delay calling this until we have the WebFrame so that any observer or
@@ -6950,11 +6942,6 @@
   GetAssociatedInterfaceRegistry()->AddInterface(
       base::Bind(&RenderFrameImpl::BindEngagement, weak_factory_.GetWeakPtr()));
 
-  if (devtools_agent_) {
-    GetAssociatedInterfaceRegistry()->AddInterface(
-        base::Bind(&DevToolsAgent::BindRequest, devtools_agent_->GetWeakPtr()));
-  }
-
   GetAssociatedInterfaceRegistry()->AddInterface(base::Bind(
       &RenderFrameImpl::BindMediaEngagement, weak_factory_.GetWeakPtr()));
 
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index c34468e..86b1f7d 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -144,7 +144,6 @@
 class BlinkInterfaceRegistryImpl;
 class ChildURLLoaderFactoryGetter;
 class CompositorDependencies;
-class DevToolsAgent;
 class DocumentState;
 class ExternalPopupMenu;
 class HistoryEntry;
@@ -296,8 +295,6 @@
   // Returns the RenderWidget associated with this frame.
   RenderWidget* GetRenderWidget();
 
-  DevToolsAgent* devtools_agent() { return devtools_agent_; }
-
   // This method must be called after the frame has been added to the frame
   // tree. It creates all objects that depend on the frame being at its proper
   // spot.
@@ -1432,10 +1429,6 @@
   // The media permission dispatcher attached to this frame.
   std::unique_ptr<MediaPermissionDispatcher> media_permission_dispatcher_;
 
-  // The devtools agent for this frame; only created for main frame and
-  // local roots.
-  DevToolsAgent* devtools_agent_;
-
   // The presentation dispatcher implementation attached to this frame, lazily
   // initialized.
   PresentationDispatcher* presentation_dispatcher_;
diff --git a/content/renderer/render_widget_browsertest.cc b/content/renderer/render_widget_browsertest.cc
index 15599b4..3abdd25a 100644
--- a/content/renderer/render_widget_browsertest.cc
+++ b/content/renderer/render_widget_browsertest.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/strings/utf_string_conversions.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
 #include "content/common/resize_params.h"
 #include "content/public/renderer/render_frame_visitor.h"
 #include "content/public/test/render_view_test.h"
@@ -53,6 +55,8 @@
 TEST_F(RenderWidgetTest, OnResize) {
   // The initial bounds is empty, so setting it to the same thing should do
   // nothing.
+  viz::LocalSurfaceId local_surface_id;
+  viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator;
   ResizeParams resize_params;
   resize_params.screen_info = ScreenInfo();
   resize_params.new_size = gfx::Size();
@@ -61,6 +65,8 @@
   resize_params.browser_controls_shrink_blink_size = false;
   resize_params.is_fullscreen_granted = false;
   resize_params.needs_resize_ack = false;
+  local_surface_id = local_surface_id_allocator.GenerateId();
+  resize_params.local_surface_id = local_surface_id;
   OnResize(resize_params);
   EXPECT_EQ(resize_params.needs_resize_ack, next_paint_is_resize_ack());
 
@@ -105,8 +111,9 @@
 
 class RenderWidgetInitialSizeTest : public RenderWidgetTest {
  public:
-  RenderWidgetInitialSizeTest()
-      : RenderWidgetTest(), initial_size_(200, 100) {}
+  RenderWidgetInitialSizeTest() : RenderWidgetTest(), initial_size_(200, 100) {
+    local_surface_id_ = local_surface_id_allocator_.GenerateId();
+  }
 
  protected:
   std::unique_ptr<ResizeParams> InitialSizeParams() override {
@@ -114,10 +121,13 @@
     initial_size_params->new_size = initial_size_;
     initial_size_params->physical_backing_size = initial_size_;
     initial_size_params->needs_resize_ack = true;
+    initial_size_params->local_surface_id = local_surface_id_;
     return initial_size_params;
   }
 
   gfx::Size initial_size_;
+  viz::LocalSurfaceId local_surface_id_;
+  viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_;
 };
 
 TEST_F(RenderWidgetInitialSizeTest, InitialSize) {
diff --git a/content/renderer/service_worker/embedded_worker_devtools_agent.cc b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
index 14b1725..30142c2 100644
--- a/content/renderer/service_worker/embedded_worker_devtools_agent.cc
+++ b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
@@ -5,7 +5,6 @@
 #include "content/renderer/service_worker/embedded_worker_devtools_agent.h"
 
 #include "content/common/devtools_messages.h"
-#include "content/renderer/devtools/devtools_agent.h"
 #include "content/renderer/render_thread_impl.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebEmbeddedWorker.h"
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 61caa76..85e0e64 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -57,33 +57,28 @@
 }
 
 void EmbeddedWorkerInstanceClientImpl::StartWorker(
-    mojom::EmbeddedWorkerStartParamsPtr params,
-    mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-    mojom::ControllerServiceWorkerRequest controller_request,
-    blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
-    blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-    mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-    mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-    blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy) {
+    mojom::EmbeddedWorkerStartParamsPtr params) {
   DCHECK(ChildThreadImpl::current());
   DCHECK(!wrapper_);
   TRACE_EVENT0("ServiceWorker",
                "EmbeddedWorkerInstanceClientImpl::StartWorker");
   service_manager::mojom::InterfaceProviderPtr interface_provider(
-      std::move(provider_info->interface_provider));
+      std::move(params->provider_info->interface_provider));
+  const bool use_script_streaming =
+      ServiceWorkerUtils::IsScriptStreamingEnabled() &&
+      params->installed_scripts_info;
   auto client = std::make_unique<ServiceWorkerContextClient>(
       params->embedded_worker_id, params->service_worker_version_id,
-      params->scope, params->script_url,
-      ServiceWorkerUtils::IsScriptStreamingEnabled() && installed_scripts_info,
-      std::move(dispatcher_request), std::move(controller_request),
-      std::move(service_worker_host), std::move(instance_host),
-      std::move(provider_info), std::move(temporal_self_),
+      params->scope, params->script_url, use_script_streaming,
+      std::move(params->dispatcher_request),
+      std::move(params->controller_request),
+      std::move(params->service_worker_host), std::move(params->instance_host),
+      std::move(params->provider_info), std::move(temporal_self_),
       ChildThreadImpl::current()->thread_safe_sender(), io_thread_runner_);
   client->set_blink_initialized_time(blink_initialized_time_);
   client->set_start_worker_received_time(base::TimeTicks::Now());
-  wrapper_ = StartWorkerContext(
-      std::move(params), std::move(installed_scripts_info), std::move(client),
-      std::move(content_settings_proxy), std::move(interface_provider));
+  wrapper_ = StartWorkerContext(std::move(params), std::move(client),
+                                std::move(interface_provider));
 }
 
 void EmbeddedWorkerInstanceClientImpl::StopWorker() {
@@ -131,24 +126,22 @@
 std::unique_ptr<EmbeddedWorkerInstanceClientImpl::WorkerWrapper>
 EmbeddedWorkerInstanceClientImpl::StartWorkerContext(
     mojom::EmbeddedWorkerStartParamsPtr params,
-    blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
     std::unique_ptr<ServiceWorkerContextClient> context_client,
-    blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy,
     service_manager::mojom::InterfaceProviderPtr interface_provider) {
   std::unique_ptr<blink::WebServiceWorkerInstalledScriptsManager> manager;
   // |installed_scripts_info| is null if scripts should be served by net layer,
   // when the worker is not installed, or the worker is launched for checking
   // the update.
   if (ServiceWorkerUtils::IsScriptStreamingEnabled() &&
-      installed_scripts_info) {
+      params->installed_scripts_info) {
     manager = WebServiceWorkerInstalledScriptsManagerImpl::Create(
-        std::move(installed_scripts_info), io_thread_runner_);
+        std::move(params->installed_scripts_info), io_thread_runner_);
   }
 
   auto wrapper = std::make_unique<WorkerWrapper>(
       blink::WebEmbeddedWorker::Create(
           std::move(context_client), std::move(manager),
-          content_settings_proxy.PassInterface().PassHandle(),
+          params->content_settings_proxy.PassHandle(),
           interface_provider.PassInterface().PassHandle()),
       params->worker_devtools_agent_route_id);
 
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.h b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
index 00d0698..a57b888 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.h
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
@@ -87,16 +87,7 @@
       mojom::EmbeddedWorkerInstanceClientAssociatedRequest request);
 
   // mojom::EmbeddedWorkerInstanceClient implementation
-  void StartWorker(
-      mojom::EmbeddedWorkerStartParamsPtr params,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
-      mojom::ControllerServiceWorkerRequest controller_request,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-      mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-      blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy)
-      override;
+  void StartWorker(mojom::EmbeddedWorkerStartParamsPtr params) override;
   void StopWorker() override;
   void ResumeAfterDownload() override;
   void AddMessageToConsole(blink::WebConsoleMessage::Level level,
@@ -107,9 +98,7 @@
 
   std::unique_ptr<WorkerWrapper> StartWorkerContext(
       mojom::EmbeddedWorkerStartParamsPtr params,
-      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info,
       std::unique_ptr<ServiceWorkerContextClient> context_client,
-      blink::mojom::WorkerContentSettingsProxyPtr content_settings_proxy,
       service_manager::mojom::InterfaceProviderPtr interface_provider);
 
   mojo::AssociatedBinding<mojom::EmbeddedWorkerInstanceClient> binding_;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index f78d0d8..e08f844 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -61,6 +61,7 @@
 #include "third_party/WebKit/common/blob/blob.mojom.h"
 #include "third_party/WebKit/common/blob/blob_registry.mojom.h"
 #include "third_party/WebKit/common/message_port/message_port_channel.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_event_status.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
@@ -169,9 +170,9 @@
   return static_cast<WebURLRequest::RequestContext>(request_context_type);
 }
 
-blink::WebServiceWorkerClientInfo
-ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) {
-  DCHECK(client_info.IsValid());
+blink::WebServiceWorkerClientInfo ToWebServiceWorkerClientInfo(
+    const blink::mojom::ServiceWorkerClientInfo& client_info) {
+  DCHECK(!client_info.client_uuid.empty());
 
   blink::WebServiceWorkerClientInfo web_client_info;
 
@@ -1475,7 +1476,7 @@
       CreateAbortCallback(&context_->message_event_callbacks));
   context_->message_event_callbacks.emplace(request_id, std::move(callback));
 
-  if (event->source.client_info.IsValid()) {
+  if (!event->source.client_info.client_uuid.empty()) {
     blink::WebServiceWorkerClientInfo web_client =
         ToWebServiceWorkerClientInfo(event->source.client_info);
     proxy_->DispatchExtendableMessageEvent(
@@ -1623,7 +1624,7 @@
 
 void ServiceWorkerContextClient::OnDidGetClient(
     int request_id,
-    const ServiceWorkerClientInfo& client) {
+    const blink::mojom::ServiceWorkerClientInfo& client) {
   TRACE_EVENT0("ServiceWorker", "ServiceWorkerContextClient::OnDidGetClient");
   blink::WebServiceWorkerClientCallbacks* callbacks =
       context_->client_callbacks.Lookup(request_id);
@@ -1632,8 +1633,7 @@
     return;
   }
   std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client;
-  if (!client.IsEmpty()) {
-    DCHECK(client.IsValid());
+  if (!client.client_uuid.empty()) {
     web_client.reset(new blink::WebServiceWorkerClientInfo(
         ToWebServiceWorkerClientInfo(client)));
   }
@@ -1642,7 +1642,8 @@
 }
 
 void ServiceWorkerContextClient::OnDidGetClients(
-    int request_id, const std::vector<ServiceWorkerClientInfo>& clients) {
+    int request_id,
+    const std::vector<blink::mojom::ServiceWorkerClientInfo>& clients) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::OnDidGetClients");
   blink::WebServiceWorkerClientsCallbacks* callbacks =
@@ -1663,7 +1664,7 @@
 
 void ServiceWorkerContextClient::OnOpenWindowResponse(
     int request_id,
-    const ServiceWorkerClientInfo& client) {
+    const blink::mojom::ServiceWorkerClientInfo& client) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::OnOpenWindowResponse");
   blink::WebServiceWorkerClientCallbacks* callbacks =
@@ -1673,8 +1674,7 @@
     return;
   }
   std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client;
-  if (!client.IsEmpty()) {
-    DCHECK(client.IsValid());
+  if (!client.client_uuid.empty()) {
     web_client.reset(new blink::WebServiceWorkerClientInfo(
         ToWebServiceWorkerClientInfo(client)));
   }
@@ -1700,7 +1700,8 @@
 }
 
 void ServiceWorkerContextClient::OnFocusClientResponse(
-    int request_id, const ServiceWorkerClientInfo& client) {
+    int request_id,
+    const blink::mojom::ServiceWorkerClientInfo& client) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::OnFocusClientResponse");
   blink::WebServiceWorkerClientCallbacks* callback =
@@ -1709,8 +1710,7 @@
     NOTREACHED() << "Got stray response: " << request_id;
     return;
   }
-  if (!client.IsEmpty()) {
-    DCHECK(client.IsValid());
+  if (!client.client_uuid.empty()) {
     std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client(
         new blink::WebServiceWorkerClientInfo(
             ToWebServiceWorkerClientInfo(client)));
@@ -1726,7 +1726,7 @@
 
 void ServiceWorkerContextClient::OnNavigateClientResponse(
     int request_id,
-    const ServiceWorkerClientInfo& client) {
+    const blink::mojom::ServiceWorkerClientInfo& client) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::OnNavigateClientResponse");
   blink::WebServiceWorkerClientCallbacks* callbacks =
@@ -1736,8 +1736,7 @@
     return;
   }
   std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client;
-  if (!client.IsEmpty()) {
-    DCHECK(client.IsValid());
+  if (!client.client_uuid.empty()) {
     web_client.reset(new blink::WebServiceWorkerClientInfo(
         ToWebServiceWorkerClientInfo(client)));
   }
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 8bad09f..c224fbb 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -30,6 +30,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/WebKit/common/blob/blob_registry.mojom.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 "third_party/WebKit/common/service_worker/service_worker_registration.mojom.h"
 #include "third_party/WebKit/public/platform/modules/payments/payment_app.mojom.h"
@@ -60,7 +61,6 @@
 
 struct PlatformNotificationData;
 struct PushEventPayload;
-struct ServiceWorkerClientInfo;
 class EmbeddedWorkerInstanceClientImpl;
 class ServiceWorkerNetworkProvider;
 class ServiceWorkerProviderContext;
@@ -362,16 +362,21 @@
       const std::string& notification_id,
       const PlatformNotificationData& notification_data);
 
-  void OnDidGetClient(int request_id, const ServiceWorkerClientInfo& client);
-  void OnDidGetClients(int request_id,
-                       const std::vector<ServiceWorkerClientInfo>& clients);
-  void OnOpenWindowResponse(int request_id,
-                            const ServiceWorkerClientInfo& client);
+  void OnDidGetClient(int request_id,
+                      const blink::mojom::ServiceWorkerClientInfo& client);
+  void OnDidGetClients(
+      int request_id,
+      const std::vector<blink::mojom::ServiceWorkerClientInfo>& clients);
+  void OnOpenWindowResponse(
+      int request_id,
+      const blink::mojom::ServiceWorkerClientInfo& client);
   void OnOpenWindowError(int request_id, const std::string& message);
-  void OnFocusClientResponse(int request_id,
-                             const ServiceWorkerClientInfo& client);
-  void OnNavigateClientResponse(int request_id,
-                                const ServiceWorkerClientInfo& client);
+  void OnFocusClientResponse(
+      int request_id,
+      const blink::mojom::ServiceWorkerClientInfo& client);
+  void OnNavigateClientResponse(
+      int request_id,
+      const blink::mojom::ServiceWorkerClientInfo& client);
   void OnNavigateClientError(int request_id, const GURL& url);
   void OnDidSkipWaiting(int request_id);
   void OnDidClaimClients(
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index fa6b67bd..83eee06 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -180,6 +180,7 @@
       return true;
     }
 #endif
+    command_line.AppendSwitch(switches::kDisableResizeLock);
     command_line.AppendSwitch(cc::switches::kEnableGpuBenchmarking);
     command_line.AppendSwitch(switches::kEnableLogging);
     command_line.AppendSwitch(switches::kAllowFileAccessFromFiles);
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index c2df8fa5..00f8a4a 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -80,7 +80,6 @@
 #include "third_party/WebKit/public/platform/modules/app_banner/app_banner.mojom.h"
 #include "third_party/WebKit/public/web/WebArrayBufferView.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
-#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebElement.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
@@ -98,7 +97,6 @@
 using blink::Platform;
 using blink::WebArrayBufferView;
 using blink::WebContextMenuData;
-using blink::WebDevToolsAgent;
 using device::MotionData;
 using device::OrientationData;
 using blink::WebElement;
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index c175dfb..c3e427d 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1453,6 +1453,8 @@
           # On Android, these are already run on the main waterfall.
           # Run them on the one-off Android FYI bots, though.
           'Android Release (Nexus 5X)',
+          # Temporarily disabled due to AMDGPU-PRO issues crbug.com/786219
+          'Linux Release (AMD R7 240)',
         ],
       },
     ],
diff --git a/content/test/test_background_sync_manager.cc b/content/test/test_background_sync_manager.cc
index bc2a57b..5da1ced7 100644
--- a/content/test/test_background_sync_manager.cc
+++ b/content/test/test_background_sync_manager.cc
@@ -79,10 +79,10 @@
     const std::string& tag,
     scoped_refptr<ServiceWorkerVersion> active_version,
     bool last_chance,
-    const ServiceWorkerVersion::LegacyStatusCallback& callback) {
+    ServiceWorkerVersion::StatusCallback callback) {
   ASSERT_TRUE(dispatch_sync_callback_);
   last_chance_ = last_chance;
-  dispatch_sync_callback_.Run(active_version, callback);
+  dispatch_sync_callback_.Run(active_version, std::move(callback));
 }
 
 void TestBackgroundSyncManager::ScheduleDelayedTask(base::OnceClosure callback,
diff --git a/content/test/test_background_sync_manager.h b/content/test/test_background_sync_manager.h
index 6abf376..2a5fcf8 100644
--- a/content/test/test_background_sync_manager.h
+++ b/content/test/test_background_sync_manager.h
@@ -106,7 +106,7 @@
       const std::string& tag,
       scoped_refptr<ServiceWorkerVersion> active_version,
       bool last_chance,
-      const ServiceWorkerVersion::LegacyStatusCallback& callback) override;
+      ServiceWorkerVersion::StatusCallback callback) override;
 
   // Override to just store delayed task, and allow tests to control the clock
   // and when delayed tasks are executed.
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
index f9a2e23..5f78621 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
@@ -6,10 +6,12 @@
 
 #include <iterator>
 #include <limits>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "dbus/property.h"
 #include "device/bluetooth/bluetooth_device.h"
@@ -68,12 +70,6 @@
   bluez::BluezDBusManager::Get()
       ->GetBluetoothGattDescriptorClient()
       ->RemoveObserver(this);
-
-  // Clean up all the descriptors. There isn't much point in notifying service
-  // observers for each descriptor that gets removed, so just delete them.
-  for (DescriptorMap::iterator iter = descriptors_.begin();
-       iter != descriptors_.end(); ++iter)
-    delete iter->second;
 }
 
 device::BluetoothUUID BluetoothRemoteGattCharacteristicBlueZ::GetUUID() const {
@@ -162,20 +158,16 @@
 std::vector<device::BluetoothRemoteGattDescriptor*>
 BluetoothRemoteGattCharacteristicBlueZ::GetDescriptors() const {
   std::vector<device::BluetoothRemoteGattDescriptor*> descriptors;
-  for (DescriptorMap::const_iterator iter = descriptors_.begin();
-       iter != descriptors_.end(); ++iter)
-    descriptors.push_back(iter->second);
+  for (const auto& descriptor : descriptors_)
+    descriptors.push_back(descriptor.second.get());
   return descriptors;
 }
 
 device::BluetoothRemoteGattDescriptor*
 BluetoothRemoteGattCharacteristicBlueZ::GetDescriptor(
     const std::string& identifier) const {
-  DescriptorMap::const_iterator iter =
-      descriptors_.find(dbus::ObjectPath(identifier));
-  if (iter == descriptors_.end())
-    return nullptr;
-  return iter->second;
+  auto iter = descriptors_.find(dbus::ObjectPath(identifier));
+  return iter != descriptors_.end() ? iter->second.get() : nullptr;
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::ReadRemoteCharacteristic(
@@ -264,9 +256,10 @@
   VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: "
           << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
 
+  // NOTE: Can't use std::make_unique due to private constructor.
   BluetoothRemoteGattDescriptorBlueZ* descriptor =
       new BluetoothRemoteGattDescriptorBlueZ(this, object_path);
-  descriptors_[object_path] = descriptor;
+  descriptors_.emplace(object_path, base::WrapUnique(descriptor));
   DCHECK(descriptor->GetIdentifier() == object_path.value());
   DCHECK(descriptor->GetUUID().IsValid());
   DCHECK(service_);
@@ -286,15 +279,14 @@
   VLOG(1) << "Removing remote GATT descriptor from characteristic: "
           << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
 
-  BluetoothRemoteGattDescriptorBlueZ* descriptor = iter->second;
+  auto descriptor = std::move(iter->second);
   DCHECK(descriptor->object_path() == object_path);
   descriptors_.erase(iter);
 
   DCHECK(service_);
   static_cast<BluetoothRemoteGattServiceBlueZ*>(service_)
-      ->NotifyDescriptorAddedOrRemoved(this, descriptor, false /* added */);
-
-  delete descriptor;
+      ->NotifyDescriptorAddedOrRemoved(this, descriptor.get(),
+                                       false /* added */);
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::GattDescriptorPropertyChanged(
@@ -318,7 +310,7 @@
 
   DCHECK(service_);
   static_cast<BluetoothRemoteGattServiceBlueZ*>(service_)
-      ->NotifyDescriptorValueChanged(this, iter->second,
+      ->NotifyDescriptorValueChanged(this, iter->second.get(),
                                      properties->value.value());
 }
 
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
index 01b61f2..f40d317 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <map>
+#include <memory>
 #include <queue>
 #include <string>
 #include <utility>
@@ -45,6 +46,7 @@
       public device::BluetoothRemoteGattCharacteristic {
  public:
   // device::BluetoothGattCharacteristic overrides.
+  ~BluetoothRemoteGattCharacteristicBlueZ() override;
   device::BluetoothUUID GetUUID() const override;
   Properties GetProperties() const override;
   Permissions GetPermissions() const override;
@@ -79,7 +81,6 @@
   BluetoothRemoteGattCharacteristicBlueZ(
       BluetoothRemoteGattServiceBlueZ* service,
       const dbus::ObjectPath& object_path);
-  ~BluetoothRemoteGattCharacteristicBlueZ() override;
 
   // bluez::BluetoothGattDescriptorClient::Observer overrides.
   void GattDescriptorAdded(const dbus::ObjectPath& object_path) override;
@@ -122,10 +123,9 @@
   // True, if there exists a Bluez notify session.
   bool has_notify_session_;
 
-  // TODO(rkc): Investigate and fix ownership of the descriptor objects in this
-  // map. See crbug.com/604166.
   using DescriptorMap =
-      std::map<dbus::ObjectPath, BluetoothRemoteGattDescriptorBlueZ*>;
+      std::map<dbus::ObjectPath,
+               std::unique_ptr<BluetoothRemoteGattDescriptorBlueZ>>;
 
   // Mapping from GATT descriptor object paths to descriptor objects owned by
   // this characteristic. Since the BlueZ implementation uses object paths
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h
index 29114d1..b68e12b 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.h
@@ -29,6 +29,7 @@
       public device::BluetoothRemoteGattDescriptor {
  public:
   // device::BluetoothRemoteGattDescriptor overrides.
+  ~BluetoothRemoteGattDescriptorBlueZ() override;
   device::BluetoothUUID GetUUID() const override;
   const std::vector<uint8_t>& GetValue() const override;
   device::BluetoothRemoteGattCharacteristic* GetCharacteristic() const override;
@@ -46,7 +47,6 @@
   BluetoothRemoteGattDescriptorBlueZ(
       BluetoothRemoteGattCharacteristicBlueZ* characteristic,
       const dbus::ObjectPath& object_path);
-  ~BluetoothRemoteGattDescriptorBlueZ() override;
 
   // Called by dbus:: on unsuccessful completion of a request to read or write
   // the descriptor value.
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc
index a11fcd87..158e0ad 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include <iterator>
+#include <utility>
 
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "dbus/property.h"
 #include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
 #include "device/bluetooth/bluez/bluetooth_device_bluez.h"
@@ -51,17 +53,15 @@
       ->GetBluetoothGattCharacteristicClient()
       ->RemoveObserver(this);
 
-  // Clean up all the characteristics. Copy the characteristics list here and
+  // Clean up all the characteristics. Move the characteristics list here and
   // clear the original so that when we send GattCharacteristicRemoved(),
   // GetCharacteristics() returns no characteristics.
-  CharacteristicMap characteristics = characteristics_;
+  CharacteristicMap characteristics = std::move(characteristics_);
   characteristics_.clear();
-  for (CharacteristicMap::iterator iter = characteristics.begin();
-       iter != characteristics.end(); ++iter) {
-    DCHECK(GetAdapter());
-    GetAdapter()->NotifyGattCharacteristicRemoved(iter->second);
 
-    delete iter->second;
+  for (const auto& characteristic : characteristics) {
+    DCHECK(GetAdapter());
+    GetAdapter()->NotifyGattCharacteristicRemoved(characteristic.second.get());
   }
 }
 
@@ -90,10 +90,8 @@
 std::vector<device::BluetoothRemoteGattCharacteristic*>
 BluetoothRemoteGattServiceBlueZ::GetCharacteristics() const {
   std::vector<device::BluetoothRemoteGattCharacteristic*> characteristics;
-  for (CharacteristicMap::const_iterator iter = characteristics_.begin();
-       iter != characteristics_.end(); ++iter) {
-    characteristics.push_back(iter->second);
-  }
+  for (const auto& characteristic : characteristics_)
+    characteristics.push_back(characteristic.second.get());
   return characteristics;
 }
 
@@ -106,11 +104,8 @@
 device::BluetoothRemoteGattCharacteristic*
 BluetoothRemoteGattServiceBlueZ::GetCharacteristic(
     const std::string& identifier) const {
-  CharacteristicMap::const_iterator iter =
-      characteristics_.find(dbus::ObjectPath(identifier));
-  if (iter == characteristics_.end())
-    return nullptr;
-  return iter->second;
+  auto iter = characteristics_.find(dbus::ObjectPath(identifier));
+  return iter != characteristics_.end() ? iter->second.get() : nullptr;
 }
 
 void BluetoothRemoteGattServiceBlueZ::NotifyServiceChanged() {
@@ -188,9 +183,10 @@
   VLOG(1) << "Adding new remote GATT characteristic for GATT service: "
           << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
 
+  // NOTE: Can't use std::make_unique due to private constructor.
   BluetoothRemoteGattCharacteristicBlueZ* characteristic =
       new BluetoothRemoteGattCharacteristicBlueZ(this, object_path);
-  characteristics_[object_path] = characteristic;
+  characteristics_.emplace(object_path, base::WrapUnique(characteristic));
   DCHECK(characteristic->GetIdentifier() == object_path.value());
   DCHECK(characteristic->GetUUID().IsValid());
 
@@ -209,14 +205,12 @@
   VLOG(1) << "Removing remote GATT characteristic from service: "
           << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
 
-  BluetoothRemoteGattCharacteristicBlueZ* characteristic = iter->second;
+  auto characteristic = std::move(iter->second);
   DCHECK(characteristic->object_path() == object_path);
   characteristics_.erase(iter);
 
   DCHECK(GetAdapter());
-  GetAdapter()->NotifyGattCharacteristicRemoved(characteristic);
-
-  delete characteristic;
+  GetAdapter()->NotifyGattCharacteristicRemoved(characteristic.get());
 }
 
 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicPropertyChanged(
@@ -241,15 +235,15 @@
   DCHECK(properties);
   DCHECK(GetAdapter());
 
-  if (property_name == properties->flags.name())
+  if (property_name == properties->flags.name()) {
     NotifyServiceChanged();
-  else if (property_name == properties->value.name()) {
+  } else if (property_name == properties->value.name()) {
     DCHECK_GE(iter->second->num_of_characteristic_value_read_in_progress_, 0);
     if (iter->second->num_of_characteristic_value_read_in_progress_ > 0) {
       --iter->second->num_of_characteristic_value_read_in_progress_;
     } else {
       GetAdapter()->NotifyGattCharacteristicValueChanged(
-          iter->second, properties->value.value());
+          iter->second.get(), properties->value.value());
     }
   }
 }
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h
index 90acbe4..116f2db7 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -101,10 +102,9 @@
   // here since |device_| owns this instance.
   BluetoothDeviceBlueZ* device_;
 
-  // TODO(rkc): Investigate and fix ownership of the characteristic objects in
-  // this map. See crbug.com/604166.
   using CharacteristicMap =
-      std::map<dbus::ObjectPath, BluetoothRemoteGattCharacteristicBlueZ*>;
+      std::map<dbus::ObjectPath,
+               std::unique_ptr<BluetoothRemoteGattCharacteristicBlueZ>>;
 
   // Mapping from GATT characteristic object paths to characteristic objects.
   // owned by this service. Since the BlueZ implementation uses object
diff --git a/device/bluetooth/dbus/fake_bluetooth_device_client.cc b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
index 4b11c3f..1fc3ed8 100644
--- a/device/bluetooth/dbus/fake_bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
@@ -1565,6 +1565,7 @@
 
 void FakeBluetoothDeviceClient::UpdateServiceAndManufacturerData(
     const dbus::ObjectPath& object_path,
+    const std::vector<std::string>& service_uuids,
     const std::unordered_map<std::string, std::vector<uint8_t>>& service_data,
     const std::unordered_map<uint16_t, std::vector<uint8_t>>&
         manufacturer_data) {
@@ -1575,6 +1576,7 @@
   }
   Properties* properties = iter->second.get();
   DCHECK(properties);
+  properties->uuids.set_valid(true);
   properties->service_data.set_valid(true);
   properties->manufacturer_data.set_valid(true);
 
@@ -1582,6 +1584,12 @@
   // caching behavior, merge the new data here with the existing data.
   // TODO(crbug.com/707039): once the BlueZ caching behavior is changed, this
   // needs to be updated as well.
+
+  std::vector<std::string> merged_uuids = service_uuids;
+  merged_uuids.insert(merged_uuids.begin(), properties->uuids.value().begin(),
+                      properties->uuids.value().end());
+  properties->uuids.ReplaceValue(merged_uuids);
+
   std::unordered_map<std::string, std::vector<uint8_t>> merged_service_data =
       service_data;
   merged_service_data.insert(properties->service_data.value().begin(),
diff --git a/device/bluetooth/dbus/fake_bluetooth_device_client.h b/device/bluetooth/dbus/fake_bluetooth_device_client.h
index 2a91399c..cdeaa65 100644
--- a/device/bluetooth/dbus/fake_bluetooth_device_client.h
+++ b/device/bluetooth/dbus/fake_bluetooth_device_client.h
@@ -177,11 +177,13 @@
   // |object_path| to |rssi|, if the fake device exists.
   void UpdateDeviceRSSI(const dbus::ObjectPath& object_path, int16_t rssi);
 
-  // Updates the service and manufacturer data property of fake device with
-  // object path |object_path| to merge |service_data| into the existing data,
-  // if the fake device exists.
+  // Updates service UUIDs, service data, and manufacturer data of the fake
+  // device with the given |object_path|. The |service_uuids| values are
+  // appended, while |service_data| and |manufacturer_data| are merged into the
+  // existing property values. Has no effect if the fake device does not exist.
   void UpdateServiceAndManufacturerData(
       const dbus::ObjectPath& object_path,
+      const std::vector<std::string>& service_uuids,
       const std::unordered_map<std::string, std::vector<uint8_t>>& service_data,
       const std::unordered_map<uint16_t, std::vector<uint8_t>>&
           manufacturer_data);
diff --git a/device/bluetooth/test/bluetooth_test_bluez.cc b/device/bluetooth/test/bluetooth_test_bluez.cc
index 32134dd..7e3ab3d9b 100644
--- a/device/bluetooth/test/bluetooth_test_bluez.cc
+++ b/device/bluetooth/test/bluetooth_test_bluez.cc
@@ -162,7 +162,7 @@
   BluetoothDevice* device = adapter_->GetDevice(device_address);
   if (device) {
     fake_bluetooth_device_client_->UpdateServiceAndManufacturerData(
-        GetDevicePath(device), service_data, manufacturer_data);
+        GetDevicePath(device), service_uuids, service_data, manufacturer_data);
     return device;
   }
 
diff --git a/device/u2f/u2f_ble_discovery.cc b/device/u2f/u2f_ble_discovery.cc
index 58bd07d..1e850c65 100644
--- a/device/u2f/u2f_ble_discovery.cc
+++ b/device/u2f/u2f_ble_discovery.cc
@@ -112,6 +112,16 @@
   }
 }
 
+void U2fBleDiscovery::DeviceChanged(BluetoothAdapter* adapter,
+                                    BluetoothDevice* device) {
+  if (base::ContainsKey(device->GetUUIDs(), U2fServiceUUID()) &&
+      !GetDevice(U2fBleDevice::GetId(device->GetAddress()))) {
+    VLOG(2) << "Discovered U2F service on existing BLE device: "
+            << device->GetAddress();
+    AddDevice(std::make_unique<U2fBleDevice>(device->GetAddress()));
+  }
+}
+
 void U2fBleDiscovery::DeviceRemoved(BluetoothAdapter* adapter,
                                     BluetoothDevice* device) {
   if (base::ContainsKey(device->GetUUIDs(), U2fServiceUUID())) {
diff --git a/device/u2f/u2f_ble_discovery.h b/device/u2f/u2f_ble_discovery.h
index 9e492b4..d354fa8d 100644
--- a/device/u2f/u2f_ble_discovery.h
+++ b/device/u2f/u2f_ble_discovery.h
@@ -39,9 +39,10 @@
 
   // BluetoothAdapter::Observer:
   void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override;
+  void DeviceChanged(BluetoothAdapter* adapter,
+                     BluetoothDevice* device) override;
   void DeviceRemoved(BluetoothAdapter* adapter,
                      BluetoothDevice* device) override;
-
   void OnStopped(bool success);
 
   scoped_refptr<BluetoothAdapter> adapter_;
diff --git a/device/u2f/u2f_ble_discovery_unittest.cc b/device/u2f/u2f_ble_discovery_unittest.cc
index 67ca184..b3fbcfe2 100644
--- a/device/u2f/u2f_ble_discovery_unittest.cc
+++ b/device/u2f/u2f_ble_discovery_unittest.cc
@@ -11,6 +11,7 @@
 #include "build/build_config.h"
 #include "device/bluetooth/test/bluetooth_test.h"
 #include "device/u2f/mock_u2f_discovery.h"
+#include "device/u2f/u2f_ble_device.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -122,4 +123,65 @@
   }
 }
 
+// Simulate the scenario where the BLE device is already known at start-up time,
+// but no service advertisements have been received from the device yet, so we
+// do not know if it is a U2F device or not. As soon as it is discovered that
+// the device supports the U2F service, the observer should be notified of a new
+// U2fBleDevice.
+TEST_F(BluetoothTest, U2fBleDiscoveryFindsUpdatedDevice) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
+  InitWithFakeAdapter();
+
+  SimulateLowEnergyDevice(3);
+
+  U2fBleDiscovery discovery;
+  MockU2fDiscoveryObserver observer;
+  discovery.AddObserver(&observer);
+
+  {
+    base::RunLoop run_loop;
+    auto quit = run_loop.QuitClosure();
+    EXPECT_CALL(observer, DiscoveryStarted(&discovery, true))
+        .WillOnce(ReturnFromAsyncCall(quit));
+
+    discovery.Start();
+    run_loop.Run();
+
+    EXPECT_THAT(discovery.GetDevices(), ::testing::IsEmpty());
+  }
+
+  {
+    base::RunLoop run_loop;
+    auto quit = run_loop.QuitClosure();
+    EXPECT_CALL(observer,
+                DeviceAdded(&discovery,
+                            IdMatches(BluetoothTestBase::kTestDeviceAddress1)))
+        .WillOnce(ReturnFromAsyncCall(quit));
+
+    // This will update properties for device 3.
+    SimulateLowEnergyDevice(7);
+
+    run_loop.Run();
+
+    const auto devices = discovery.GetDevices();
+    ASSERT_THAT(devices, ::testing::SizeIs(1u));
+    EXPECT_EQ(U2fBleDevice::GetId(BluetoothTestBase::kTestDeviceAddress1),
+              devices[0]->GetId());
+  }
+
+  // TODO(crbug/763303): Delete device and check OnDeviceDeleted invocation.
+
+  {
+    base::RunLoop run_loop;
+    auto quit = run_loop.QuitClosure();
+    EXPECT_CALL(observer, DiscoveryStopped(&discovery, true))
+        .WillOnce(ReturnFromAsyncCall(quit));
+    discovery.Stop();
+    run_loop.Run();
+  }
+}
+
 }  // namespace device
diff --git a/docs/old_chromeos_build_instructions.md b/docs/old_chromeos_build_instructions.md
index 5baa515..968002b 100644
--- a/docs/old_chromeos_build_instructions.md
+++ b/docs/old_chromeos_build_instructions.md
@@ -31,13 +31,8 @@
 See [GN Build Configuration](https://www.chromium.org/developers/gn-build-configuration)
 for more information about configuring your build.
 
-If you have not already done so, be sure to set the following to prevent
-'gclient runhooks' from executing 'gyp_chromium':
-
-    export GYP_CHROMIUM_NO_ACTION=1
-
-Some additional options you may wish to set by passing in **--args** to
-**gn gen** or running **gn args out/Default**:
+Some additional options you may wish to set by passing in `--args` to `gn gen`
+or running `gn args out/Default`:
 
     is_component_build = true
     use_goma = true
@@ -59,9 +54,9 @@
 testing it through Chromium Remote Desktop you might face drawing
 problems (e.g. Aura window not painting anything). Possible remedies:
 
-*   --ui-enable-software-compositing --ui-disable-threaded-compositing
-*   --use-gl=osmesa, but it's ultra slow, and you'll have to build
-    osmesa yourself.
+*   `--ui-enable-software-compositing --ui-disable-threaded-compositing`
+*   `--use-gl=osmesa`, but it's ultra slow, and you'll have to build osmesa
+    yourself.
 *   ... or just don't use Remote Desktop. :)
 
 To more closely match the UI used on devices, you can install fonts used
@@ -70,14 +65,14 @@
 To specify a logged in user:
 
 *   For first run, add the following options to the command line:
-    **--user-data-dir=/tmp/chrome --login-manager**
+    `--user-data-dir=/tmp/chrome --login-manager`
 *   Go through the out-of-the-box UX and sign in as
-    **username@gmail.com**
+    **username@gmail.com**.
 *   For subsequent runs, add the following to the command line:
-    **--user-data-dir=/tmp/chrome --login-user=username@gmail.com**.
-*   To run in guest mode instantly, you can run add the arguments
-    **--user-data-dir=/tmp/chrome --bwsi --incognito
-    --login-user='$guest' --login-profile=user**
+    `--user-data-dir=/tmp/chrome --login-user=username@gmail.com`
+*   To run in guest mode instantly, you can run add the arguments:
+    `--user-data-dir=/tmp/chrome --bwsi --incognito --login-user='$guest'
+    --login-profile=user`
 
 Signing in as a specific user is useful for debugging features like sync
 that require a logged in user.
diff --git a/extensions/common/manifest_handlers/content_capabilities_handler.cc b/extensions/common/manifest_handlers/content_capabilities_handler.cc
index 03d84d5..92aad80 100644
--- a/extensions/common/manifest_handlers/content_capabilities_handler.cc
+++ b/extensions/common/manifest_handlers/content_capabilities_handler.cc
@@ -65,7 +65,8 @@
     return false;
 
   int supported_schemes = URLPattern::SCHEME_HTTPS;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kTestType)) {
     // We don't have a suitable HTTPS test server, so this will have to do.
     supported_schemes |= URLPattern::SCHEME_HTTP;
   }
diff --git a/extensions/common/permissions/socket_permission_data.cc b/extensions/common/permissions/socket_permission_data.cc
index 1616a10..18b37a8 100644
--- a/extensions/common/permissions/socket_permission_data.cc
+++ b/extensions/common/permissions/socket_permission_data.cc
@@ -22,7 +22,6 @@
 using content::SocketPermissionRequest;
 using extensions::SocketPermissionData;
 
-const char kColon = ':';
 const char kInvalid[] = "invalid";
 const char kTCPConnect[] = "tcp-connect";
 const char kTCPListen[] = "tcp-listen";
@@ -124,9 +123,8 @@
 bool SocketPermissionData::Parse(const std::string& permission) {
   Reset();
 
-  std::vector<std::string> tokens =
-      base::SplitString(permission, std::string(1, kColon),
-                        base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+  std::vector<std::string> tokens = base::SplitString(
+      permission, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
   if (tokens.empty())
     return false;
 
@@ -146,7 +144,7 @@
   spec_.append(TypeToString(entry_.pattern().type));
   std::string pattern = entry_.GetHostPatternAsString();
   if (!pattern.empty()) {
-    spec_.append(1, kColon).append(pattern);
+    spec_.append(1, ':').append(pattern);
   }
   return spec_;
 }
diff --git a/extensions/renderer/wake_event_page.cc b/extensions/renderer/wake_event_page.cc
index 81e21c2b..4cf79881 100644
--- a/extensions/renderer/wake_event_page.cc
+++ b/extensions/renderer/wake_event_page.cc
@@ -29,7 +29,7 @@
 
 namespace {
 
-base::LazyInstance<WakeEventPage>::DestructorAtExit g_instance =
+base::LazyInstance<WakeEventPage>::DestructorAtExit g_wake_event_page_instance =
     LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
@@ -98,7 +98,7 @@
 
 // static
 WakeEventPage* WakeEventPage::Get() {
-  return g_instance.Pointer();
+  return g_wake_event_page_instance.Pointer();
 }
 
 void WakeEventPage::Init(content::RenderThread* render_thread) {
diff --git a/extensions/renderer/worker_thread_dispatcher.cc b/extensions/renderer/worker_thread_dispatcher.cc
index 6159370..806b11c6 100644
--- a/extensions/renderer/worker_thread_dispatcher.cc
+++ b/extensions/renderer/worker_thread_dispatcher.cc
@@ -26,8 +26,8 @@
 
 namespace {
 
-base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit g_instance =
-    LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<WorkerThreadDispatcher>::DestructorAtExit
+    g_worker_thread_dispatcher_instance = LAZY_INSTANCE_INITIALIZER;
 base::LazyInstance<base::ThreadLocalPointer<extensions::ServiceWorkerData>>::
     DestructorAtExit g_data_tls = LAZY_INSTANCE_INITIALIZER;
 
@@ -43,7 +43,7 @@
 WorkerThreadDispatcher::~WorkerThreadDispatcher() {}
 
 WorkerThreadDispatcher* WorkerThreadDispatcher::Get() {
-  return g_instance.Pointer();
+  return g_worker_thread_dispatcher_instance.Pointer();
 }
 
 void WorkerThreadDispatcher::Init(content::RenderThread* render_thread) {
diff --git a/extensions/test/data/web_view/apitest/main.js b/extensions/test/data/web_view/apitest/main.js
index e5d3ef9..7c4c7ec 100644
--- a/extensions/test/data/web_view/apitest/main.js
+++ b/extensions/test/data/web_view/apitest/main.js
@@ -172,9 +172,6 @@
   var sizeChangeHandler = function(e) {
     switch (step) {
       case 1:
-        // This would be triggered after we set autosize attribute.
-        embedder.test.assertEq(50, e.oldWidth);
-        embedder.test.assertEq(100, e.oldHeight);
         embedder.test.assertTrue(e.newWidth >= 60 && e.newWidth <= 70);
         embedder.test.assertTrue(e.newHeight >= 110 && e.newHeight <= 120);
 
@@ -248,23 +245,19 @@
   webview.maxheight = 200;
 
   var step = 1;
+  var finalWidth = 200;
+  var finalHeight = 50;
   webview.addEventListener('sizechanged', function(e) {
-    switch (step) {
-      case 1:
-        embedder.test.assertEq(200, e.newHeight);
-        // Change the maxheight to verify that we see the change.
-        webview.maxheight = 50;
-        break;
-      case 2:
-        embedder.test.assertEq(200, e.oldHeight);
-        embedder.test.assertEq(50, e.newHeight);
-        embedder.test.succeed();
-        break;
-      default:
-        window.console.log('Unexpected sizechanged event, step = ' + step);
-        embedder.test.fail();
-        break;
-    }
+    embedder.test.assertTrue(e.newHeight >= webview.minheight);
+    embedder.test.assertTrue(e.newHeight <= webview.maxheight);
+    embedder.test.assertTrue(e.newWidth >= webview.minwidth);
+    embedder.test.assertTrue(e.newWidth <= webview.maxwidth);
+    if (step == 1)
+      webview.maxheight = 50;
+
+    // We are done once the size settles on the final width and height.
+    if (e.newHeight == finalHeight && e.newWidth == finalWidth)
+      embedder.test.succeed();
     ++step;
   });
 
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 77657b2..4efedd9 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -114,6 +114,8 @@
     "context_state.h",
     "context_state_autogen.h",
     "context_state_impl_autogen.h",
+    "decoder_client.h",
+    "decoder_context.h",
     "error_state.cc",
     "error_state.h",
     "feature_info.cc",
diff --git a/gpu/command_buffer/service/command_buffer_direct.h b/gpu/command_buffer/service/command_buffer_direct.h
index 99fe010d..f5ac358 100644
--- a/gpu/command_buffer/service/command_buffer_direct.h
+++ b/gpu/command_buffer/service/command_buffer_direct.h
@@ -9,7 +9,7 @@
 #include "gpu/command_buffer/common/command_buffer_id.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/gpu_export.h"
 
 namespace gpu {
@@ -23,7 +23,7 @@
 
 class GPU_EXPORT CommandBufferDirect : public CommandBuffer,
                                        public CommandBufferServiceClient,
-                                       public gles2::GLES2DecoderClient {
+                                       public DecoderClient {
  public:
   using MakeCurrentCallback = base::Callback<bool()>;
 
@@ -52,7 +52,7 @@
   CommandBatchProcessedResult OnCommandBatchProcessed() override;
   void OnParseError() override;
 
-  // GLES2DecoderClient implementation
+  // DecoderClient implementation
   void OnConsoleMessage(int32_t id, const std::string& message) override;
   void CacheShader(const std::string& key, const std::string& shader) override;
   void OnFenceSyncRelease(uint64_t release) override;
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 63bd30f..0b2d243 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -13,6 +13,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
@@ -128,7 +129,7 @@
 }
 
 gpu::ContextResult ContextGroup::Initialize(
-    GLES2Decoder* decoder,
+    DecoderContext* decoder,
     ContextType context_type,
     const DisallowedFeatures& disallowed_features) {
   switch (context_type) {
@@ -529,7 +530,7 @@
 
 namespace {
 
-bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
+bool IsNull(const base::WeakPtr<DecoderContext>& decoder) {
   return !decoder;
 }
 
@@ -559,9 +560,9 @@
     progress_reporter_->ReportProgress();
 }
 
-void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
+void ContextGroup::Destroy(DecoderContext* decoder, bool have_context) {
   decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
-                                 WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
+                                 WeakPtrEquals<DecoderContext>(decoder)),
                   decoders_.end());
   // If we still have contexts do nothing.
   if (HaveContexts()) {
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index 1af2520..bfb0ba54 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -32,12 +32,12 @@
 class TransferBufferManager;
 class ServiceDiscardableManager;
 class ServiceTransferCache;
+class DecoderContext;
 
 namespace gles2 {
 
 class ProgramCache;
 class BufferManager;
-class GLES2Decoder;
 class ImageManager;
 class RenderbufferManager;
 class PathManager;
@@ -54,7 +54,7 @@
     ContextType context_type,
     const DisallowedFeatures& disallowed_features);
 
-// A Context Group helps manage multiple GLES2Decoders that share
+// A Context Group helps manage multiple DecoderContexts that share
 // resources.
 class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> {
  public:
@@ -72,15 +72,15 @@
                const GpuFeatureInfo& gpu_feature_info,
                ServiceDiscardableManager* discardable_manager);
 
-  // This should only be called by GLES2Decoder. This must be paired with a
+  // This should only be called by a DecoderContext. This must be paired with a
   // call to destroy if it succeeds.
-  gpu::ContextResult Initialize(GLES2Decoder* decoder,
+  gpu::ContextResult Initialize(DecoderContext* decoder,
                                 ContextType context_type,
                                 const DisallowedFeatures& disallowed_features);
 
   // Destroys all the resources when called for the last context in the group.
-  // It should only be called by GLES2Decoder.
-  void Destroy(GLES2Decoder* decoder, bool have_context);
+  // It should only be called by DecoderContext.
+  void Destroy(DecoderContext* decoder, bool have_context);
 
   MailboxManager* mailbox_manager() const { return mailbox_manager_; }
 
@@ -306,7 +306,7 @@
 
   gpu::ImageFactory* image_factory_;
 
-  std::vector<base::WeakPtr<gles2::GLES2Decoder>> decoders_;
+  std::vector<base::WeakPtr<DecoderContext>> decoders_;
 
   // Mappings from client side IDs to service side IDs.
   base::hash_map<GLuint, GLsync> syncs_id_map_;
diff --git a/gpu/command_buffer/service/decoder_client.h b/gpu/command_buffer/service/decoder_client.h
new file mode 100644
index 0000000..5397574
--- /dev/null
+++ b/gpu/command_buffer/service/decoder_client.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_DECODER_CLIENT_H_
+#define GPU_COMMAND_BUFFER_SERVICE_DECODER_CLIENT_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+struct SyncToken;
+
+class GPU_EXPORT DecoderClient {
+ public:
+  virtual ~DecoderClient() = default;
+
+  // Prints a message (error/warning) to the console.
+  virtual void OnConsoleMessage(int32_t id, const std::string& message) = 0;
+
+  // Cache a newly linked shader.
+  virtual void CacheShader(const std::string& key,
+                           const std::string& shader) = 0;
+
+  // Called when the decoder releases a fence sync. Allows the client to
+  // reschedule waiting decoders.
+  virtual void OnFenceSyncRelease(uint64_t release) = 0;
+
+  // Called when the decoder needs to wait on a sync token. If the wait is valid
+  // (fence sync is not released yet), the client must unschedule the command
+  // buffer and return true. The client is responsible for rescheduling the
+  // command buffer when the fence is released.  If the wait is a noop (fence is
+  // already released) or invalid, the client must leave the command buffer
+  // scheduled, and return false.
+  virtual bool OnWaitSyncToken(const gpu::SyncToken&) = 0;
+
+  // Called when the decoder needs to be descheduled while waiting for a fence
+  // completion. The client is responsible for descheduling the command buffer
+  // before returning, and then calling PerformPollingWork periodically to test
+  // for the fence completion and possibly reschedule.
+  virtual void OnDescheduleUntilFinished() = 0;
+
+  // Called from PerformPollingWork when the decoder needs to be rescheduled
+  // because the fence completed.
+  virtual void OnRescheduleAfterFinished() = 0;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_DECODER_CLIENT_H_
diff --git a/gpu/command_buffer/service/decoder_context.h b/gpu/command_buffer/service/decoder_context.h
new file mode 100644
index 0000000..04742c00
--- /dev/null
+++ b/gpu/command_buffer/service/decoder_context.h
@@ -0,0 +1,172 @@
+// 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_COMMAND_BUFFER_SERVICE_DECODER_CONTEXT_H_
+#define GPU_COMMAND_BUFFER_SERVICE_DECODER_CONTEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "gpu/command_buffer/common/capabilities.h"
+#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"
+
+namespace gl {
+class GLContext;
+class GLImage;
+class GLSurface;
+}  // namespace gl
+
+namespace gpu {
+class TextureBase;
+struct ContextCreationAttribs;
+
+namespace gles2 {
+class ContextGroup;
+class ErrorState;
+class GpuFenceManager;
+class QueryManager;
+struct ContextState;
+struct DisallowedFeatures;
+}  // namespace gles2
+
+struct Mailbox;
+
+// 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 {
+ public:
+  DecoderContext() = default;
+  ~DecoderContext() override = default;
+
+  //
+  // Methods required by CommandBufferStub.
+  //
+  // Initializes the graphics context. Can create an offscreen
+  // decoder with a frame buffer that can be referenced from the parent.
+  // Takes ownership of GLContext.
+  // Parameters:
+  //  surface: the GL surface to render to.
+  //  context: the GL context to render to.
+  //  offscreen: whether to make the context offscreen or not. When FBO 0 is
+  //      bound, offscreen contexts render to an internal buffer, onscreen ones
+  //      to the surface.
+  //  offscreen_size: the size if the GL context is offscreen.
+  // Returns:
+  //   true if successful.
+  virtual gpu::ContextResult Initialize(
+      const scoped_refptr<gl::GLSurface>& surface,
+      const scoped_refptr<gl::GLContext>& context,
+      bool offscreen,
+      const gles2::DisallowedFeatures& disallowed_features,
+      const ContextCreationAttribs& attrib_helper) = 0;
+
+  // Destroys the graphics context.
+  virtual void Destroy(bool have_context) = 0;
+
+  virtual Capabilities GetCapabilities() = 0;
+
+  // Gets the associated GLContext.
+  virtual gl::GLContext* GetGLContext() = 0;
+
+  // Make this decoder's GL context current.
+  virtual bool MakeCurrent() = 0;
+
+  // Lose this context.
+  virtual void MarkContextLost(error::ContextLostReason reason) = 0;
+
+  // Returns true if the context was lost either by GL_ARB_robustness, forced
+  // context loss or command buffer parse error.
+  virtual bool WasContextLost() const = 0;
+
+  // Returns true if the context was lost specifically by GL_ARB_robustness.
+  virtual bool WasContextLostByRobustnessExtension() const = 0;
+
+  // Updates context lost state and returns true if lost. Most callers can use
+  // WasContextLost() as the GLES2Decoder will update the state internally. But
+  // if making GL calls directly, to the context then this state would not be
+  // updated and the caller can use this to determine if their calls failed due
+  // to context loss.
+  virtual bool CheckResetStatus() = 0;
+
+  virtual void TakeFrontBuffer(const Mailbox& mailbox) = 0;
+  virtual void ReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) = 0;
+
+  // Gets the QueryManager for this context.
+  virtual gles2::QueryManager* GetQueryManager() = 0;
+
+  // Gets the GpuFenceManager for this context.
+  virtual gles2::GpuFenceManager* GetGpuFenceManager() = 0;
+
+  // Returns false if there are no pending queries.
+  virtual bool HasPendingQueries() const = 0;
+
+  // Process any pending queries.
+  virtual void ProcessPendingQueries(bool did_finish) = 0;
+
+  // Returns false if there is no idle work to be made.
+  virtual bool HasMoreIdleWork() const = 0;
+
+  // Perform any idle work that needs to be made.
+  virtual void PerformIdleWork() = 0;
+
+  // Whether there is state that needs to be regularly polled.
+  virtual bool HasPollingWork() const = 0;
+
+  // Perform necessary polling.
+  virtual void PerformPollingWork() = 0;
+
+  //
+  // Methods required by GLStateRestorerImpl.
+  //
+  virtual bool initialized() const = 0;
+  virtual const gles2::ContextState* GetContextState() = 0;
+
+  // Restores all of the decoder GL state.
+  virtual void RestoreState(const gles2::ContextState* prev_state) = 0;
+
+  // Restore States.
+  virtual void RestoreActiveTexture() const = 0;
+  virtual void RestoreAllTextureUnitAndSamplerBindings(
+      const gles2::ContextState* prev_state) const = 0;
+  virtual void RestoreActiveTextureUnitBinding(unsigned int target) const = 0;
+  virtual void RestoreBufferBinding(unsigned int target) = 0;
+  virtual void RestoreBufferBindings() const = 0;
+  virtual void RestoreFramebufferBindings() const = 0;
+  virtual void RestoreRenderbufferBindings() = 0;
+  virtual void RestoreProgramBindings() const = 0;
+  virtual void RestoreTextureState(unsigned service_id) const = 0;
+  virtual void RestoreTextureUnitBindings(unsigned unit) const = 0;
+  virtual void RestoreVertexAttribArray(unsigned index) = 0;
+  virtual void RestoreAllExternalTextureBindingsIfNeeded() = 0;
+
+  //
+  // Methods required by GpuVideoDecodeAccelerator.
+  //
+  // Gets the texture object associated with the client ID.  null is returned on
+  // failure or if the texture has not been bound yet.
+  virtual TextureBase* GetTextureBase(uint32_t client_id) = 0;
+  virtual void BindImage(uint32_t client_texture_id,
+                         uint32_t texture_target,
+                         gl::GLImage* image,
+                         bool can_bind_to_sampler) = 0;
+  virtual base::WeakPtr<DecoderContext> AsWeakPtr() = 0;
+
+  //
+  // Methods required by GLES2DecoderHelper.
+  //
+  virtual gles2::ContextGroup* GetContextGroup() = 0;
+  virtual gles2::ErrorState* GetErrorState() = 0;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_DECODER_CONTEXT_H_
diff --git a/gpu/command_buffer/service/gl_context_virtual.cc b/gpu/command_buffer/service/gl_context_virtual.cc
index a500558..34650f3 100644
--- a/gpu/command_buffer/service/gl_context_virtual.cc
+++ b/gpu/command_buffer/service/gl_context_virtual.cc
@@ -5,8 +5,8 @@
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 
 #include "base/callback.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/gl_state_restorer_impl.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gpu_preference.h"
@@ -16,7 +16,7 @@
 
 GLContextVirtual::GLContextVirtual(gl::GLShareGroup* share_group,
                                    gl::GLContext* shared_context,
-                                   base::WeakPtr<gles2::GLES2Decoder> decoder)
+                                   base::WeakPtr<DecoderContext> decoder)
     : GLContext(share_group),
       shared_context_(shared_context),
       decoder_(decoder) {}
diff --git a/gpu/command_buffer/service/gl_context_virtual.h b/gpu/command_buffer/service/gl_context_virtual.h
index f9768f5..6453333a 100644
--- a/gpu/command_buffer/service/gl_context_virtual.h
+++ b/gpu/command_buffer/service/gl_context_virtual.h
@@ -20,16 +20,14 @@
 }
 
 namespace gpu {
-namespace gles2 {
-class GLES2Decoder;
-}
+class DecoderContext;
 
 // Encapsulates a virtual OpenGL context.
 class GPU_EXPORT GLContextVirtual : public gl::GLContext {
  public:
   GLContextVirtual(gl::GLShareGroup* share_group,
                    gl::GLContext* shared_context,
-                   base::WeakPtr<gles2::GLES2Decoder> decoder);
+                   base::WeakPtr<DecoderContext> decoder);
 
   // Implement GLContext.
   bool Initialize(gl::GLSurface* compatible_surface,
@@ -58,7 +56,7 @@
   void Destroy();
 
   scoped_refptr<gl::GLContext> shared_context_;
-  base::WeakPtr<gles2::GLES2Decoder> decoder_;
+  base::WeakPtr<DecoderContext> decoder_;
 
   DISALLOW_COPY_AND_ASSIGN(GLContextVirtual);
 };
diff --git a/gpu/command_buffer/service/gl_state_restorer_impl.cc b/gpu/command_buffer/service/gl_state_restorer_impl.cc
index 0ddc18daf..aec71ab 100644
--- a/gpu/command_buffer/service/gl_state_restorer_impl.cc
+++ b/gpu/command_buffer/service/gl_state_restorer_impl.cc
@@ -4,15 +4,13 @@
 
 #include "gpu/command_buffer/service/gl_state_restorer_impl.h"
 
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/query_manager.h"
 
 namespace gpu {
 
-GLStateRestorerImpl::GLStateRestorerImpl(
-    base::WeakPtr<gles2::GLES2Decoder> decoder)
-    : decoder_(decoder) {
-}
+GLStateRestorerImpl::GLStateRestorerImpl(base::WeakPtr<DecoderContext> decoder)
+    : decoder_(decoder) {}
 
 GLStateRestorerImpl::~GLStateRestorerImpl() = default;
 
diff --git a/gpu/command_buffer/service/gl_state_restorer_impl.h b/gpu/command_buffer/service/gl_state_restorer_impl.h
index e1a786f..082d526 100644
--- a/gpu/command_buffer/service/gl_state_restorer_impl.h
+++ b/gpu/command_buffer/service/gl_state_restorer_impl.h
@@ -14,35 +14,37 @@
 #include "ui/gl/gl_state_restorer.h"
 
 namespace gpu {
+
+class DecoderContext;
+
 namespace gles2 {
-class GLES2Decoder;
 struct ContextState;
 }
 
-// This class implements a GLStateRestorer that forwards to a GLES2Decoder.
+// This class implements a GLStateRestorer that forwards to a DecoderContext.
 class GPU_EXPORT GLStateRestorerImpl : public gl::GLStateRestorer {
  public:
-   explicit GLStateRestorerImpl(base::WeakPtr<gles2::GLES2Decoder> decoder);
-   ~GLStateRestorerImpl() override;
+  explicit GLStateRestorerImpl(base::WeakPtr<DecoderContext> decoder);
+  ~GLStateRestorerImpl() override;
 
-   bool IsInitialized() override;
-   void RestoreState(const gl::GLStateRestorer* prev_state) override;
-   void RestoreAllTextureUnitAndSamplerBindings() override;
-   void RestoreActiveTexture() override;
-   void RestoreActiveTextureUnitBinding(unsigned int target) override;
-   void RestoreAllExternalTextureBindingsIfNeeded() override;
-   void RestoreFramebufferBindings() override;
-   void RestoreProgramBindings() override;
-   void RestoreBufferBinding(unsigned int target) override;
-   void RestoreVertexAttribArray(unsigned int index) override;
-   void PauseQueries() override;
-   void ResumeQueries() override;
+  bool IsInitialized() override;
+  void RestoreState(const gl::GLStateRestorer* prev_state) override;
+  void RestoreAllTextureUnitAndSamplerBindings() override;
+  void RestoreActiveTexture() override;
+  void RestoreActiveTextureUnitBinding(unsigned int target) override;
+  void RestoreAllExternalTextureBindingsIfNeeded() override;
+  void RestoreFramebufferBindings() override;
+  void RestoreProgramBindings() override;
+  void RestoreBufferBinding(unsigned int target) override;
+  void RestoreVertexAttribArray(unsigned int index) override;
+  void PauseQueries() override;
+  void ResumeQueries() override;
 
  private:
-   const gles2::ContextState* GetContextState() const;
-   base::WeakPtr<gles2::GLES2Decoder> decoder_;
+  const gles2::ContextState* GetContextState() const;
+  base::WeakPtr<DecoderContext> decoder_;
 
-   DISALLOW_COPY_AND_ASSIGN(GLStateRestorerImpl);
+  DISALLOW_COPY_AND_ASSIGN(GLStateRestorerImpl);
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index ca95f2c..0e12ede 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -38,6 +38,7 @@
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/context_state.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/error_state.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
@@ -513,10 +514,6 @@
   return false;
 }
 
-TextureBase* GLES2Decoder::GetTextureBase(uint32_t client_id) {
-  return nullptr;
-}
-
 uint32_t GLES2Decoder::GetAndClearBackbufferClearBitsForTest() {
   return 0;
 }
@@ -529,6 +526,14 @@
 
 GLES2Decoder::~GLES2Decoder() = default;
 
+bool GLES2Decoder::initialized() const {
+  return initialized_;
+}
+
+TextureBase* GLES2Decoder::GetTextureBase(uint32_t client_id) {
+  return nullptr;
+}
+
 void GLES2Decoder::BeginDecoding() {}
 
 void GLES2Decoder::EndDecoding() {}
@@ -541,7 +546,7 @@
 // cmd stuff to outside this class.
 class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
  public:
-  GLES2DecoderImpl(GLES2DecoderClient* client,
+  GLES2DecoderImpl(DecoderClient* client,
                    CommandBufferServiceBase* command_buffer_service,
                    Outputter* outputter,
                    ContextGroup* group);
@@ -559,7 +564,7 @@
                               int* entries_processed);
 
   // Overridden from GLES2Decoder.
-  base::WeakPtr<GLES2Decoder> AsWeakPtr() override;
+  base::WeakPtr<DecoderContext> AsWeakPtr() override;
   gpu::ContextResult Initialize(
       const scoped_refptr<gl::GLSurface>& surface,
       const scoped_refptr<gl::GLContext>& context,
@@ -2307,7 +2312,7 @@
 
   #undef GLES2_CMD_OP
 
-  GLES2DecoderClient* client_;
+  DecoderClient* client_;
 
   // The GL context this decoder renders to on behalf of the client.
   scoped_refptr<gl::GLSurface> surface_;
@@ -3149,7 +3154,7 @@
 }
 
 GLES2Decoder* GLES2Decoder::Create(
-    GLES2DecoderClient* client,
+    DecoderClient* client,
     CommandBufferServiceBase* command_buffer_service,
     Outputter* outputter,
     ContextGroup* group) {
@@ -3161,7 +3166,7 @@
 }
 
 GLES2DecoderImpl::GLES2DecoderImpl(
-    GLES2DecoderClient* client,
+    DecoderClient* client,
     CommandBufferServiceBase* command_buffer_service,
     Outputter* outputter,
     ContextGroup* group)
@@ -3232,7 +3237,7 @@
 
 GLES2DecoderImpl::~GLES2DecoderImpl() = default;
 
-base::WeakPtr<GLES2Decoder> GLES2DecoderImpl::AsWeakPtr() {
+base::WeakPtr<DecoderContext> GLES2DecoderImpl::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 9a07d2a1..d366646 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -23,12 +23,11 @@
 #include "gpu/command_buffer/common/constants.h"
 #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"
 
 namespace gl {
-class GLContext;
 class GLSurface;
-class GLImage;
 }
 
 namespace gfx {
@@ -37,28 +36,21 @@
 
 namespace gpu {
 
-struct ContextCreationAttribs;
-struct Mailbox;
-struct SyncToken;
-class TextureBase;
+class DecoderClient;
 
 namespace gles2 {
 
 class ContextGroup;
-class ErrorState;
 class FeatureInfo;
 class FramebufferManager;
 class GLES2Util;
-class GpuFenceManager;
 class ImageManager;
 class Logger;
 class Outputter;
-class QueryManager;
 class ShaderTranslatorInterface;
 class Texture;
 class TransformFeedbackManager;
 class VertexArrayManager;
-struct ContextState;
 
 struct DisallowedFeatures {
   DisallowedFeatures() = default;
@@ -82,43 +74,9 @@
   bool oes_texture_half_float_linear = false;
 };
 
-class GPU_EXPORT GLES2DecoderClient {
- public:
-  virtual ~GLES2DecoderClient() = default;
-
-  // Prints a message (error/warning) to the console.
-  virtual void OnConsoleMessage(int32_t id, const std::string& message) = 0;
-
-  // Cache a newly linked shader.
-  virtual void CacheShader(const std::string& key,
-                           const std::string& shader) = 0;
-
-  // Called when the decoder releases a fence sync. Allows the client to
-  // reschedule waiting decoders.
-  virtual void OnFenceSyncRelease(uint64_t release) = 0;
-
-  // Called when the decoder needs to wait on a sync token. If the wait is valid
-  // (fence sync is not released yet), the client must unschedule the command
-  // buffer and return true. The client is responsible for rescheduling the
-  // command buffer when the fence is released.  If the wait is a noop (fence is
-  // already released) or invalid, the client must leave the command buffer
-  // scheduled, and return false.
-  virtual bool OnWaitSyncToken(const gpu::SyncToken&) = 0;
-
-  // Called when the decoder needs to be descheduled while waiting for a fence
-  // completion. The client is responsible for descheduling the command buffer
-  // before returning, and then calling PerformPollingWork periodically to test
-  // for the fence completion and possibly reschedule.
-  virtual void OnDescheduleUntilFinished() = 0;
-
-  // Called from PerformPollingWork when the decoder needs to be rescheduled
-  // because the fence completed.
-  virtual void OnRescheduleAfterFinished() = 0;
-};
-
-// This class implements the AsyncAPIInterface interface, decoding GLES2
+// This class implements the DecoderContext interface, decoding GLES2
 // commands and calling GL.
-class GPU_EXPORT GLES2Decoder : public CommonDecoder, public AsyncAPIInterface {
+class GPU_EXPORT GLES2Decoder : public CommonDecoder, public DecoderContext {
  public:
   typedef error::Error Error;
 
@@ -128,16 +86,19 @@
   static const unsigned int kDefaultStencilMask;
 
   // Creates a decoder.
-  static GLES2Decoder* Create(GLES2DecoderClient* client,
+  static GLES2Decoder* Create(DecoderClient* client,
                               CommandBufferServiceBase* command_buffer_service,
                               Outputter* outputter,
                               ContextGroup* group);
 
   ~GLES2Decoder() override;
 
-  bool initialized() const {
-    return initialized_;
-  }
+  // DecoderContext implementation.
+  bool initialized() const override;
+  TextureBase* GetTextureBase(uint32_t client_id) override;
+  void BeginDecoding() override;
+  void EndDecoding() override;
+  base::StringPiece GetLogPrefix() override;
 
   void set_initialized() {
     initialized_ = true;
@@ -163,75 +124,22 @@
 
   Outputter* outputter() const { return outputter_; }
 
-  virtual base::WeakPtr<GLES2Decoder> AsWeakPtr() = 0;
-
-  // Initializes the graphics context. Can create an offscreen
-  // decoder with a frame buffer that can be referenced from the parent.
-  // Takes ownership of GLContext.
-  // Parameters:
-  //  surface: the GL surface to render to.
-  //  context: the GL context to render to.
-  //  offscreen: whether to make the context offscreen or not. When FBO 0 is
-  //      bound, offscreen contexts render to an internal buffer, onscreen ones
-  //      to the surface.
-  //  offscreen_size: the size if the GL context is offscreen.
-  // Returns:
-  //   true if successful.
-  virtual gpu::ContextResult Initialize(
-      const scoped_refptr<gl::GLSurface>& surface,
-      const scoped_refptr<gl::GLContext>& context,
-      bool offscreen,
-      const DisallowedFeatures& disallowed_features,
-      const ContextCreationAttribs& attrib_helper) = 0;
-
-  // Destroys the graphics context.
-  virtual void Destroy(bool have_context) = 0;
-
   // Set the surface associated with the default FBO.
   virtual void SetSurface(const scoped_refptr<gl::GLSurface>& surface) = 0;
   // Releases the surface associated with the GL context.
   // The decoder should not be used until a new surface is set.
   virtual void ReleaseSurface() = 0;
 
-  virtual void TakeFrontBuffer(const Mailbox& mailbox) = 0;
-  virtual void ReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) = 0;
-
   // Resize an offscreen frame buffer.
   virtual bool ResizeOffscreenFramebuffer(const gfx::Size& size) = 0;
 
-  // Make this decoder's GL context current.
-  virtual bool MakeCurrent() = 0;
-
   // Gets the GLES2 Util which holds info.
   virtual GLES2Util* GetGLES2Util() = 0;
 
-  // Gets the associated GLContext.
-  virtual gl::GLContext* GetGLContext() = 0;
-
-  // Gets the associated ContextGroup
-  virtual ContextGroup* GetContextGroup() = 0;
   virtual const FeatureInfo* GetFeatureInfo() const = 0;
 
-  virtual Capabilities GetCapabilities() = 0;
-
-  // Restores all of the decoder GL state.
-  virtual void RestoreState(const ContextState* prev_state) = 0;
-
   // Restore States.
-  virtual void RestoreActiveTexture() const = 0;
-  virtual void RestoreAllTextureUnitAndSamplerBindings(
-      const ContextState* prev_state) const = 0;
-  virtual void RestoreActiveTextureUnitBinding(unsigned int target) const = 0;
-  virtual void RestoreBufferBinding(unsigned int target) = 0;
-  virtual void RestoreBufferBindings() const = 0;
-  virtual void RestoreFramebufferBindings() const = 0;
-  virtual void RestoreRenderbufferBindings() = 0;
   virtual void RestoreGlobalState() const = 0;
-  virtual void RestoreProgramBindings() const = 0;
-  virtual void RestoreTextureState(unsigned service_id) const = 0;
-  virtual void RestoreTextureUnitBindings(unsigned unit) const = 0;
-  virtual void RestoreVertexAttribArray(unsigned index) = 0;
-  virtual void RestoreAllExternalTextureBindingsIfNeeded() = 0;
   virtual void RestoreDeviceWindowRectangles() const = 0;
 
   virtual void ClearAllAttributes() const = 0;
@@ -243,12 +151,6 @@
   virtual size_t GetSavedBackTextureCountForTest() = 0;
   virtual size_t GetCreatedBackTextureCountForTest() = 0;
 
-  // Gets the QueryManager for this context.
-  virtual QueryManager* GetQueryManager() = 0;
-
-  // Gets the GpuFenceManager for this context.
-  virtual GpuFenceManager* GetGpuFenceManager() = 0;
-
   // Gets the FramebufferManager for this context.
   virtual FramebufferManager* GetFramebufferManager() = 0;
 
@@ -261,33 +163,11 @@
   // Gets the ImageManager for this context.
   virtual ImageManager* GetImageManagerForTest() = 0;
 
-  // Returns false if there are no pending queries.
-  virtual bool HasPendingQueries() const = 0;
-
-  // Process any pending queries.
-  virtual void ProcessPendingQueries(bool did_finish) = 0;
-
-  // Returns false if there is no idle work to be made.
-  virtual bool HasMoreIdleWork() const = 0;
-
-  // Perform any idle work that needs to be made.
-  virtual void PerformIdleWork() = 0;
-
-  // Whether there is state that needs to be regularly polled.
-  virtual bool HasPollingWork() const = 0;
-
-  // Perform necessary polling.
-  virtual void PerformPollingWork() = 0;
-
   // Get the service texture ID corresponding to a client texture ID.
   // If no such record is found then return false.
   virtual bool GetServiceTextureId(uint32_t client_texture_id,
                                    uint32_t* service_texture_id);
 
-  // Gets the texture object associated with the client ID.  null is returned on
-  // failure or if the texture has not been bound yet.
-  virtual TextureBase* GetTextureBase(uint32_t client_id);
-
   // Clears a level sub area of a 2D texture.
   // Returns false if a GL error should be generated.
   virtual bool ClearLevel(Texture* texture,
@@ -324,47 +204,17 @@
                             int height,
                             int depth) = 0;
 
-  virtual ErrorState* GetErrorState() = 0;
-
   virtual void WaitForReadPixels(base::Closure callback) = 0;
 
-  // Returns true if the context was lost either by GL_ARB_robustness, forced
-  // context loss or command buffer parse error.
-  virtual bool WasContextLost() const = 0;
-
-  // Returns true if the context was lost specifically by GL_ARB_robustness.
-  virtual bool WasContextLostByRobustnessExtension() const = 0;
-
-  // Lose this context.
-  virtual void MarkContextLost(error::ContextLostReason reason) = 0;
-
-  // Updates context lost state and returns true if lost. Most callers can use
-  // WasContextLost() as the GLES2Decoder will update the state internally. But
-  // if making GL calls directly, to the context then this state would not be
-  // updated and the caller can use this to determine if their calls failed due
-  // to context loss.
-  virtual bool CheckResetStatus() = 0;
-
   virtual Logger* GetLogger() = 0;
 
-  void BeginDecoding() override;
-  void EndDecoding() override;
-
-  virtual const ContextState* GetContextState() = 0;
   virtual scoped_refptr<ShaderTranslatorInterface> GetTranslator(
       unsigned int type) = 0;
 
-  virtual void BindImage(uint32_t client_texture_id,
-                         uint32_t texture_target,
-                         gl::GLImage* image,
-                         bool can_bind_to_sampler) = 0;
-
  protected:
   GLES2Decoder(CommandBufferServiceBase* command_buffer_service,
                Outputter* outputter);
 
-  base::StringPiece GetLogPrefix() override;
-
  private:
   bool initialized_ = false;
   bool debug_ = false;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc b/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
index 3b110a0..8d5a3b2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
@@ -19,7 +19,7 @@
 
 MockGLES2Decoder::~MockGLES2Decoder() = default;
 
-base::WeakPtr<GLES2Decoder> MockGLES2Decoder::AsWeakPtr() {
+base::WeakPtr<DecoderContext> MockGLES2Decoder::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index ca122ca2..60d781a9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -41,7 +41,7 @@
                    Outputter* outputter);
   virtual ~MockGLES2Decoder();
 
-  base::WeakPtr<GLES2Decoder> AsWeakPtr() override;
+  base::WeakPtr<DecoderContext> AsWeakPtr() override;
 
   MOCK_METHOD5(Initialize,
                gpu::ContextResult(const scoped_refptr<gl::GLSurface>& surface,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index ef758a40..c44899fe 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -7,6 +7,7 @@
 #include "base/callback.h"
 #include "base/strings/string_split.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/gpu_fence_manager.h"
@@ -419,7 +420,7 @@
 }
 
 GLES2DecoderPassthroughImpl::GLES2DecoderPassthroughImpl(
-    GLES2DecoderClient* client,
+    DecoderClient* client,
     CommandBufferServiceBase* command_buffer_service,
     Outputter* outputter,
     ContextGroup* group)
@@ -558,7 +559,7 @@
   return result;
 }
 
-base::WeakPtr<GLES2Decoder> GLES2DecoderPassthroughImpl::AsWeakPtr() {
+base::WeakPtr<DecoderContext> GLES2DecoderPassthroughImpl::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
 
@@ -1076,8 +1077,8 @@
 #if defined(USE_EGL)
   // Establish the program binary caching callback.
   if (group_->has_program_cache()) {
-    auto program_callback = base::BindRepeating(
-        &GLES2DecoderClient::CacheShader, base::Unretained(client_));
+    auto program_callback = base::BindRepeating(&DecoderClient::CacheShader,
+                                                base::Unretained(client_));
     angle::SetCacheProgramCallback(program_callback);
   }
 #endif  // defined(USE_EGL)
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index 06aba64b43..12c3feb3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -109,7 +109,7 @@
 
 class GPU_EXPORT GLES2DecoderPassthroughImpl : public GLES2Decoder {
  public:
-  GLES2DecoderPassthroughImpl(GLES2DecoderClient* client,
+  GLES2DecoderPassthroughImpl(DecoderClient* client,
                               CommandBufferServiceBase* command_buffer_service,
                               Outputter* outputter,
                               ContextGroup* group);
@@ -126,7 +126,7 @@
                        int num_entries,
                        int* entries_processed);
 
-  base::WeakPtr<GLES2Decoder> AsWeakPtr() override;
+  base::WeakPtr<DecoderContext> AsWeakPtr() override;
 
   gpu::ContextResult Initialize(
       const scoped_refptr<gl::GLSurface>& surface,
@@ -391,7 +391,7 @@
 
   void ExitCommandProcessingEarly() { commands_to_process_ = 0; }
 
-  GLES2DecoderClient* client_;
+  DecoderClient* client_;
 
   int commands_to_process_;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index 1b1fef6f..154d9611 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -5,6 +5,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h"
 
 #include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/gpu_fence_manager.h"
 #include "gpu/command_buffer/service/gpu_tracer.h"
 #include "ui/gfx/geometry/rect_conversions.h"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index a299404..d37d4e4 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/buffer_manager.h"
 #include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
 #include "gpu/command_buffer/service/gl_context_mock.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
@@ -48,7 +49,7 @@
 class MemoryTracker;
 
 class GLES2DecoderTestBase : public ::testing::TestWithParam<bool>,
-                             public GLES2DecoderClient {
+                             public DecoderClient {
  public:
   GLES2DecoderTestBase();
   ~GLES2DecoderTestBase() override;
@@ -822,7 +823,7 @@
 }
 
 class GLES2DecoderPassthroughTestBase : public testing::Test,
-                                        public GLES2DecoderClient {
+                                        public DecoderClient {
  public:
   GLES2DecoderPassthroughTestBase(ContextType context_type);
   ~GLES2DecoderPassthroughTestBase() override;
diff --git a/gpu/command_buffer/service/logger.cc b/gpu/command_buffer/service/logger.cc
index 7b9d726..0e6e5ed 100644
--- a/gpu/command_buffer/service/logger.cc
+++ b/gpu/command_buffer/service/logger.cc
@@ -8,14 +8,14 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 
 namespace gpu {
 namespace gles2 {
 
 Logger::Logger(const DebugMarkerManager* debug_marker_manager,
-               GLES2DecoderClient* client)
+               DecoderClient* client)
     : debug_marker_manager_(debug_marker_manager),
       client_(client),
       log_message_count_(0),
@@ -58,4 +58,3 @@
 
 }  // namespace gles2
 }  // namespace gpu
-
diff --git a/gpu/command_buffer/service/logger.h b/gpu/command_buffer/service/logger.h
index bb90b72..c6eb167 100644
--- a/gpu/command_buffer/service/logger.h
+++ b/gpu/command_buffer/service/logger.h
@@ -16,17 +16,18 @@
 #include "gpu/gpu_export.h"
 
 namespace gpu {
+
+class DecoderClient;
+
 namespace gles2 {
 
 class DebugMarkerManager;
-class GLES2DecoderClient;
 
 class GPU_EXPORT Logger {
  public:
   static const int kMaxLogMessages = 256;
 
-  Logger(const DebugMarkerManager* debug_marker_manager,
-         GLES2DecoderClient* client);
+  Logger(const DebugMarkerManager* debug_marker_manager, DecoderClient* client);
   ~Logger();
 
   void LogMessage(const char* filename, int line, const std::string& msg);
@@ -43,7 +44,7 @@
  private:
   // Uses the current marker to add information to logs.
   const DebugMarkerManager* debug_marker_manager_;
-  GLES2DecoderClient* client_;
+  DecoderClient* client_;
   std::string this_in_hex_;
 
   int log_message_count_;
@@ -56,4 +57,3 @@
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_LOGGER_H_
-
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index 05680a8..f043b75 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -206,7 +206,7 @@
   (*map)[proto.mapped_name()] = interface_block;
 }
 
-void RunShaderCallback(GLES2DecoderClient* client,
+void RunShaderCallback(DecoderClient* client,
                        GpuProgramProto* proto,
                        std::string sha_string) {
   std::string shader;
@@ -311,7 +311,7 @@
     const LocationMap* bind_attrib_location_map,
     const std::vector<std::string>& transform_feedback_varyings,
     GLenum transform_feedback_buffer_mode,
-    GLES2DecoderClient* client) {
+    DecoderClient* client) {
   if (!ProgramBinaryExtensionsAvailable()) {
     // Early exit if this context can't support program binaries
     return PROGRAM_LOAD_FAILURE;
@@ -398,7 +398,7 @@
     const LocationMap* bind_attrib_location_map,
     const std::vector<std::string>& transform_feedback_varyings,
     GLenum transform_feedback_buffer_mode,
-    GLES2DecoderClient* client) {
+    DecoderClient* client) {
   if (!ProgramBinaryExtensionsAvailable()) {
     // Early exit if this context can't support program binaries
     return;
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index af920b70..c138fed 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -15,7 +15,7 @@
 #include "base/containers/mru_cache.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/program_cache.h"
 
 namespace gpu {
@@ -40,7 +40,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      GLES2DecoderClient* client) override;
+      DecoderClient* client) override;
   void SaveLinkedProgram(
       GLuint program,
       const Shader* shader_a,
@@ -48,7 +48,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      GLES2DecoderClient* client) override;
+      DecoderClient* client) override;
 
   void LoadProgram(const std::string& key, const std::string& program) override;
 
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index cc0d79b..19f2c12f 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -67,8 +67,7 @@
   const char* binary_;
 };
 
-class MemoryProgramCacheTest : public GpuServiceTest,
-                               public GLES2DecoderClient {
+class MemoryProgramCacheTest : public GpuServiceTest, public DecoderClient {
  public:
   static const size_t kCacheSizeBytes = 1024;
   static const bool kDisableGpuDiskCache = false;
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index 1f88ea6..28d0f48 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -129,7 +129,7 @@
                    const LocationMap* bind_attrib_location_map,
                    const std::vector<std::string>& transform_feedback_varyings,
                    GLenum transform_feedback_buffer_mode,
-                   GLES2DecoderClient* client));
+                   DecoderClient* client));
 
   MOCK_METHOD7(SaveLinkedProgram,
                void(GLuint program,
@@ -138,7 +138,7 @@
                     const LocationMap* bind_attrib_location_map,
                     const std::vector<std::string>& transform_feedback_varyings,
                     GLenum transform_feedback_buffer_mode,
-                    GLES2DecoderClient* client));
+                    DecoderClient* client));
   MOCK_METHOD2(LoadProgram, void(const std::string&, const std::string&));
   MOCK_METHOD1(Trim, size_t(size_t));
 
diff --git a/gpu/command_buffer/service/passthrough_program_cache.cc b/gpu/command_buffer/service/passthrough_program_cache.cc
index ea257fa7..a7d8df5 100644
--- a/gpu/command_buffer/service/passthrough_program_cache.cc
+++ b/gpu/command_buffer/service/passthrough_program_cache.cc
@@ -75,7 +75,7 @@
     const LocationMap* bind_attrib_location_map,
     const std::vector<std::string>& transform_feedback_varyings,
     GLenum transform_feedback_buffer_mode,
-    GLES2DecoderClient* client) {
+    DecoderClient* client) {
   NOTREACHED();
   return PROGRAM_LOAD_FAILURE;
 }
@@ -87,7 +87,7 @@
     const LocationMap* bind_attrib_location_map,
     const std::vector<std::string>& transform_feedback_varyings,
     GLenum transform_feedback_buffer_mode,
-    GLES2DecoderClient* client) {
+    DecoderClient* client) {
   NOTREACHED();
 }
 
diff --git a/gpu/command_buffer/service/passthrough_program_cache.h b/gpu/command_buffer/service/passthrough_program_cache.h
index 5f73d041..87f583d 100644
--- a/gpu/command_buffer/service/passthrough_program_cache.h
+++ b/gpu/command_buffer/service/passthrough_program_cache.h
@@ -6,7 +6,7 @@
 #define GPU_COMMAND_BUFFER_SERVICE_PASSTHROUGH_PROGRAM_CACHE_H_
 
 #include "base/macros.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/program_cache.h"
 
 namespace gpu {
@@ -28,7 +28,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      GLES2DecoderClient* client) override;
+      DecoderClient* client) override;
   void SaveLinkedProgram(
       GLuint program,
       const Shader* shader_a,
@@ -36,7 +36,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      GLES2DecoderClient* client) override;
+      DecoderClient* client) override;
 
   void LoadProgram(const std::string& key, const std::string& program) override;
 
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h
index d1db644..45b2f6e1 100644
--- a/gpu/command_buffer/service/program_cache.h
+++ b/gpu/command_buffer/service/program_cache.h
@@ -59,7 +59,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      GLES2DecoderClient* client) = 0;
+      DecoderClient* client) = 0;
 
   // Saves the program into the cache.  If successful, the implementation should
   // call LinkedProgramCacheSuccess.
@@ -70,7 +70,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      GLES2DecoderClient* client) = 0;
+      DecoderClient* client) = 0;
 
   virtual void LoadProgram(const std::string& key,
                            const std::string& program) = 0;
diff --git a/gpu/command_buffer/service/program_cache_unittest.cc b/gpu/command_buffer/service/program_cache_unittest.cc
index ca8087e..2830329 100644
--- a/gpu/command_buffer/service/program_cache_unittest.cc
+++ b/gpu/command_buffer/service/program_cache_unittest.cc
@@ -24,7 +24,7 @@
       const LocationMap* /* bind_attrib_location_map */,
       const std::vector<std::string>& /* transform_feedback_varyings */,
       GLenum /* transform_feedback_buffer_mode */,
-      GLES2DecoderClient* /* client */) override {
+      DecoderClient* /* client */) override {
     return PROGRAM_LOAD_SUCCESS;
   }
   void SaveLinkedProgram(
@@ -34,7 +34,7 @@
       const LocationMap* /* bind_attrib_location_map */,
       const std::vector<std::string>& /* transform_feedback_varyings */,
       GLenum /* transform_feedback_buffer_mode */,
-      GLES2DecoderClient* /* client */) override {}
+      DecoderClient* /* client */) override {}
 
   void LoadProgram(const std::string& /*key*/,
                    const std::string& /* program */) override {}
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index e3eeab1..de1122d 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -25,8 +25,8 @@
 #include "base/time/time.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/feature_info.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/program_cache.h"
 #include "gpu/command_buffer/service/progress_reporter.h"
@@ -1306,7 +1306,7 @@
 
 bool Program::Link(ShaderManager* manager,
                    Program::VaryingsPackingOption varyings_packing_option,
-                   GLES2DecoderClient* client) {
+                   DecoderClient* client) {
   ClearLinkStatus();
 
   if (!AttachedShadersExist()) {
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index a3b8e64..841091ca 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -23,12 +23,12 @@
 
 namespace gpu {
 
+class DecoderClient;
 struct GpuPreferences;
 
 namespace gles2 {
 
 class FeatureInfo;
-class GLES2DecoderClient;
 class ProgramCache;
 class ProgramManager;
 class ProgressReporter;
@@ -327,7 +327,7 @@
   // Performs glLinkProgram and related activities.
   bool Link(ShaderManager* manager,
             VaryingsPackingOption varyings_packing_option,
-            GLES2DecoderClient* client);
+            DecoderClient* client);
 
   // Performs glValidateProgram and related activities.
   void Validate();
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 0e8434f..be862824 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -16,6 +16,7 @@
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
@@ -55,8 +56,7 @@
 
 }  // namespace anonymous
 
-class ProgramManagerTestBase : public GpuServiceTest,
-                               public GLES2DecoderClient {
+class ProgramManagerTestBase : public GpuServiceTest, public DecoderClient {
  protected:
   virtual void SetupProgramManager() {
     manager_.reset(new ProgramManager(
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index dc893e9d..690a6dc 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -11,6 +11,7 @@
 #include "gpu/command_buffer/common/gles2_cmd_ids.h"
 #include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/shader_translator.h"
 #include "ui/gl/gl_context.h"
@@ -49,11 +50,12 @@
 #undef GLES2_CMD_OP
 };
 
-RasterDecoder::RasterDecoder(GLES2DecoderClient* client,
+RasterDecoder::RasterDecoder(DecoderClient* client,
                              CommandBufferServiceBase* command_buffer_service,
                              Outputter* outputter,
                              ContextGroup* group)
-    : GLES2Decoder(command_buffer_service, outputter),
+    : CommonDecoder(command_buffer_service),
+      initialized_(false),
       commands_to_process_(0),
       current_decoder_error_(error::kNoError),
       client_(client),
@@ -62,11 +64,13 @@
       validators_(group_->feature_info()->validators()),
       feature_info_(group_->feature_info()),
       state_(group_->feature_info(), this, &logger_),
+      debug_(false),
+      log_commands_(false),
       weak_ptr_factory_(this) {}
 
 RasterDecoder::~RasterDecoder() {}
 
-base::WeakPtr<GLES2Decoder> RasterDecoder::AsWeakPtr() {
+base::WeakPtr<DecoderContext> RasterDecoder::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
 
@@ -82,7 +86,7 @@
 
   state_.set_api(gl::g_current_gl_context);
 
-  set_initialized();
+  initialized_ = true;
 
   // TODO(backer): Remove temporary hack once we use a separate set of
   // commands. Thread safe because Initialize is always called from CrGpuMain
@@ -106,8 +110,9 @@
     return gpu::ContextResult::kFatalFailure;
   }
 
-  if (group_->gpu_preferences().enable_gpu_debugging)
-    set_debug(true);
+  // FIXME(backer):
+  // if (group_->gpu_preferences().enable_gpu_debugging)
+  //   set_debug(true);
 
   if (group_->gpu_preferences().enable_gpu_command_logging)
     set_log_commands(true);
@@ -128,14 +133,16 @@
   return gpu::ContextResult::kSuccess;
 }
 
-void RasterDecoder::Destroy(bool have_context) {}
+bool RasterDecoder::initialized() const {
+  return initialized_;
+}
 
-void RasterDecoder::SetSurface(const scoped_refptr<gl::GLSurface>& surface) {
+const gles2::ContextState* RasterDecoder::GetContextState() {
   NOTIMPLEMENTED();
+  return nullptr;
 }
-void RasterDecoder::ReleaseSurface() {
-  NOTIMPLEMENTED();
-}
+
+void RasterDecoder::Destroy(bool have_context) {}
 
 void RasterDecoder::TakeFrontBuffer(const Mailbox& mailbox) {
   NOTIMPLEMENTED();
@@ -143,10 +150,6 @@
 void RasterDecoder::ReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) {
   NOTIMPLEMENTED();
 }
-bool RasterDecoder::ResizeOffscreenFramebuffer(const gfx::Size& size) {
-  NOTIMPLEMENTED();
-  return true;
-}
 
 // Make this decoder's GL context current.
 bool RasterDecoder::MakeCurrent() {
@@ -168,25 +171,10 @@
   return true;
 }
 
-GLES2Util* RasterDecoder::GetGLES2Util() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
 gl::GLContext* RasterDecoder::GetGLContext() {
   return context_.get();
 }
 
-ContextGroup* RasterDecoder::GetContextGroup() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-const FeatureInfo* RasterDecoder::GetFeatureInfo() const {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
 Capabilities RasterDecoder::GetCapabilities() {
   gpu::Capabilities caps;
   caps.gpu_rasterization = true;
@@ -229,10 +217,6 @@
   NOTIMPLEMENTED();
 }
 
-void RasterDecoder::RestoreGlobalState() const {
-  NOTIMPLEMENTED();
-}
-
 void RasterDecoder::RestoreProgramBindings() const {
   NOTIMPLEMENTED();
 }
@@ -253,41 +237,6 @@
   NOTIMPLEMENTED();
 }
 
-void RasterDecoder::RestoreDeviceWindowRectangles() const {
-  NOTIMPLEMENTED();
-}
-
-void RasterDecoder::ClearAllAttributes() const {
-  NOTIMPLEMENTED();
-}
-
-void RasterDecoder::RestoreAllAttributes() const {
-  NOTIMPLEMENTED();
-}
-
-void RasterDecoder::SetIgnoreCachedStateForTest(bool ignore) {
-  NOTIMPLEMENTED();
-}
-
-void RasterDecoder::SetForceShaderNameHashingForTest(bool force) {
-  NOTIMPLEMENTED();
-}
-
-uint32_t RasterDecoder::GetAndClearBackbufferClearBitsForTest() {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-size_t RasterDecoder::GetSavedBackTextureCountForTest() {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-size_t RasterDecoder::GetCreatedBackTextureCountForTest() {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
 QueryManager* RasterDecoder::GetQueryManager() {
   NOTIMPLEMENTED();
   return nullptr;
@@ -298,26 +247,6 @@
   return nullptr;
 }
 
-FramebufferManager* RasterDecoder::GetFramebufferManager() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-TransformFeedbackManager* RasterDecoder::GetTransformFeedbackManager() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-VertexArrayManager* RasterDecoder::GetVertexArrayManager() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
-ImageManager* RasterDecoder::GetImageManagerForTest() {
-  NOTIMPLEMENTED();
-  return nullptr;
-}
-
 bool RasterDecoder::HasPendingQueries() const {
   NOTIMPLEMENTED();
   return false;
@@ -345,65 +274,11 @@
   NOTIMPLEMENTED();
 }
 
-bool RasterDecoder::GetServiceTextureId(uint32_t client_texture_id,
-                                        uint32_t* service_texture_id) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 TextureBase* RasterDecoder::GetTextureBase(uint32_t client_id) {
   NOTIMPLEMENTED();
   return nullptr;
 }
 
-bool RasterDecoder::ClearLevel(Texture* texture,
-                               unsigned target,
-                               int level,
-                               unsigned format,
-                               unsigned type,
-                               int xoffset,
-                               int yoffset,
-                               int width,
-                               int height) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool RasterDecoder::ClearCompressedTextureLevel(Texture* texture,
-                                                unsigned target,
-                                                int level,
-                                                unsigned format,
-                                                int width,
-                                                int height) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool RasterDecoder::IsCompressedTextureFormat(unsigned format) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool RasterDecoder::ClearLevel3D(Texture* texture,
-                                 unsigned target,
-                                 int level,
-                                 unsigned format,
-                                 unsigned type,
-                                 int width,
-                                 int height,
-                                 int depth) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-ErrorState* RasterDecoder::GetErrorState() {
-  return state_.GetErrorState();
-}
-
-void RasterDecoder::WaitForReadPixels(base::Closure callback) {
-  NOTIMPLEMENTED();
-}
-
 bool RasterDecoder::WasContextLost() const {
   return false;
 }
@@ -422,12 +297,9 @@
   return false;
 }
 
-Logger* RasterDecoder::GetLogger() {
-  return &logger_;
-}
-
 void RasterDecoder::BeginDecoding() {
-  NOTIMPLEMENTED();
+  // TODO(backer): Add support the tracing commands.
+  gpu_debug_commands_ = log_commands() || debug();
 }
 
 void RasterDecoder::EndDecoding() {
@@ -441,10 +313,11 @@
   return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
 }
 
-error::Error RasterDecoder::DoCommands(unsigned int num_commands,
-                                       const volatile void* buffer,
-                                       int num_entries,
-                                       int* entries_processed) {
+template <bool DebugImpl>
+error::Error RasterDecoder::DoCommandsImpl(unsigned int num_commands,
+                                           const volatile void* buffer,
+                                           int num_entries,
+                                           int* entries_processed) {
   DCHECK(entries_processed);
   commands_to_process_ = num_commands;
   error::Error result = error::kNoError;
@@ -468,6 +341,11 @@
       break;
     }
 
+    if (DebugImpl && log_commands()) {
+      LOG(ERROR) << "[" << logger_.GetLogPrefix() << "]"
+                 << "cmd: " << GetCommandName(command);
+    }
+
     const unsigned int arg_count = size - 1;
     unsigned int command_index = command - kFirstGLES2Command;
     if (command_index < arraysize(command_info)) {
@@ -483,6 +361,15 @@
                      << command_index << ") is NOTIMPLEMENTED";
         } else {
           result = (this->*info.cmd_handler)(immediate_data_size, cmd_data);
+          if (DebugImpl && debug() && !WasContextLost()) {
+            GLenum error;
+            while ((error = api()->glGetErrorFn()) != GL_NO_ERROR) {
+              LOG(ERROR) << "[" << logger_.GetLogPrefix() << "] "
+                         << "GL ERROR: " << GLES2Util::GetStringEnum(error)
+                         << " : " << GetCommandName(command);
+              LOCAL_SET_GL_ERROR(error, "DoCommand", "GL error from driver");
+            }
+          }
         }
       } else {
         result = error::kInvalidArguments;
@@ -513,15 +400,21 @@
   return result;
 }
 
-const ContextState* RasterDecoder::GetContextState() {
-  NOTIMPLEMENTED();
-  return nullptr;
+error::Error RasterDecoder::DoCommands(unsigned int num_commands,
+                                       const volatile void* buffer,
+                                       int num_entries,
+                                       int* entries_processed) {
+  if (gpu_debug_commands_) {
+    return DoCommandsImpl<true>(num_commands, buffer, num_entries,
+                                entries_processed);
+  } else {
+    return DoCommandsImpl<false>(num_commands, buffer, num_entries,
+                                 entries_processed);
+  }
 }
 
-scoped_refptr<ShaderTranslatorInterface> RasterDecoder::GetTranslator(
-    unsigned int type) {
-  NOTIMPLEMENTED();
-  return nullptr;
+base::StringPiece RasterDecoder::GetLogPrefix() {
+  return logger_.GetLogPrefix();
 }
 
 void RasterDecoder::BindImage(uint32_t client_texture_id,
@@ -531,6 +424,14 @@
   NOTIMPLEMENTED();
 }
 
+gles2::ContextGroup* RasterDecoder::GetContextGroup() {
+  return group_.get();
+}
+
+gles2::ErrorState* RasterDecoder::GetErrorState() {
+  return state_.GetErrorState();
+}
+
 void RasterDecoder::OnContextLostError() {
   NOTIMPLEMENTED();
 }
diff --git a/gpu/command_buffer/service/raster_decoder.h b/gpu/command_buffer/service/raster_decoder.h
index b6f44657..1b42cee 100644
--- a/gpu/command_buffer/service/raster_decoder.h
+++ b/gpu/command_buffer/service/raster_decoder.h
@@ -22,10 +22,11 @@
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/common_decoder.h"
 #include "gpu/command_buffer/service/context_state.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/error_state.h"
 #include "gpu/command_buffer/service/feature_info.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gles2_cmd_validation.h"
 #include "gpu/command_buffer/service/logger.h"
 #include "gpu/gpu_export.h"
@@ -33,40 +34,38 @@
 namespace gpu {
 
 class TextureBase;
+class DecoderClient;
 
 namespace raster {
 
 // This class implements the AsyncAPIInterface interface, decoding
 // RasterInterface commands and calling GL.
-class GPU_EXPORT RasterDecoder : public gles2::GLES2Decoder,
+class GPU_EXPORT RasterDecoder : public DecoderContext,
+                                 public CommonDecoder,
                                  public gles2::ErrorStateClient {
  public:
-  RasterDecoder(gles2::GLES2DecoderClient* client,
+  RasterDecoder(DecoderClient* client,
                 CommandBufferServiceBase* command_buffer_service,
                 gles2::Outputter* outputter,
                 gles2::ContextGroup* group);
 
   ~RasterDecoder() override;
 
-  // GLES2Decoder implementation.
-  base::WeakPtr<GLES2Decoder> AsWeakPtr() override;
+  // DecoderContext implementation.
+  base::WeakPtr<DecoderContext> AsWeakPtr() override;
   gpu::ContextResult Initialize(
       const scoped_refptr<gl::GLSurface>& surface,
       const scoped_refptr<gl::GLContext>& context,
       bool offscreen,
       const gles2::DisallowedFeatures& disallowed_features,
       const ContextCreationAttribs& attrib_helper) override;
+  bool initialized() const override;
+  const gles2::ContextState* GetContextState() override;
   void Destroy(bool have_context) override;
-  void SetSurface(const scoped_refptr<gl::GLSurface>& surface) override;
-  void ReleaseSurface() override;
   void TakeFrontBuffer(const Mailbox& mailbox) override;
   void ReturnFrontBuffer(const Mailbox& mailbox, bool is_lost) override;
-  bool ResizeOffscreenFramebuffer(const gfx::Size& size) override;
   bool MakeCurrent() override;
-  gles2::GLES2Util* GetGLES2Util() override;
   gl::GLContext* GetGLContext() override;
-  gles2::ContextGroup* GetContextGroup() override;
-  const gles2::FeatureInfo* GetFeatureInfo() const override;
   Capabilities GetCapabilities() override;
   void RestoreState(const gles2::ContextState* prev_state) override;
   void RestoreActiveTexture() const override;
@@ -77,66 +76,24 @@
   void RestoreBufferBindings() const override;
   void RestoreFramebufferBindings() const override;
   void RestoreRenderbufferBindings() override;
-  void RestoreGlobalState() const override;
   void RestoreProgramBindings() const override;
   void RestoreTextureState(unsigned service_id) const override;
   void RestoreTextureUnitBindings(unsigned unit) const override;
   void RestoreVertexAttribArray(unsigned index) override;
   void RestoreAllExternalTextureBindingsIfNeeded() override;
-  void RestoreDeviceWindowRectangles() const override;
-  void ClearAllAttributes() const override;
-  void RestoreAllAttributes() const override;
-  void SetIgnoreCachedStateForTest(bool ignore) override;
-  void SetForceShaderNameHashingForTest(bool force) override;
-  uint32_t GetAndClearBackbufferClearBitsForTest() override;
-  size_t GetSavedBackTextureCountForTest() override;
-  size_t GetCreatedBackTextureCountForTest() override;
   gles2::QueryManager* GetQueryManager() override;
   gles2::GpuFenceManager* GetGpuFenceManager() override;
-  gles2::FramebufferManager* GetFramebufferManager() override;
-  gles2::TransformFeedbackManager* GetTransformFeedbackManager() override;
-  gles2::VertexArrayManager* GetVertexArrayManager() override;
-  gles2::ImageManager* GetImageManagerForTest() override;
   bool HasPendingQueries() const override;
   void ProcessPendingQueries(bool did_finish) override;
   bool HasMoreIdleWork() const override;
   void PerformIdleWork() override;
   bool HasPollingWork() const override;
   void PerformPollingWork() override;
-  bool GetServiceTextureId(uint32_t client_texture_id,
-                           uint32_t* service_texture_id) override;
   TextureBase* GetTextureBase(uint32_t client_id) override;
-  bool ClearLevel(gles2::Texture* texture,
-                  unsigned target,
-                  int level,
-                  unsigned format,
-                  unsigned type,
-                  int xoffset,
-                  int yoffset,
-                  int width,
-                  int height) override;
-  bool ClearCompressedTextureLevel(gles2::Texture* texture,
-                                   unsigned target,
-                                   int level,
-                                   unsigned format,
-                                   int width,
-                                   int height) override;
-  bool IsCompressedTextureFormat(unsigned format) override;
-  bool ClearLevel3D(gles2::Texture* texture,
-                    unsigned target,
-                    int level,
-                    unsigned format,
-                    unsigned type,
-                    int width,
-                    int height,
-                    int depth) override;
-  gles2::ErrorState* GetErrorState() override;
-  void WaitForReadPixels(base::Closure callback) override;
   bool WasContextLost() const override;
   bool WasContextLostByRobustnessExtension() const override;
   void MarkContextLost(error::ContextLostReason reason) override;
   bool CheckResetStatus() override;
-  gles2::Logger* GetLogger() override;
   void BeginDecoding() override;
   void EndDecoding() override;
   const char* GetCommandName(unsigned int command_id) const;
@@ -144,18 +101,28 @@
                           const volatile void* buffer,
                           int num_entries,
                           int* entries_processed) override;
-  const gles2::ContextState* GetContextState() override;
-  scoped_refptr<gles2::ShaderTranslatorInterface> GetTranslator(
-      unsigned int type) override;
+  base::StringPiece GetLogPrefix() override;
   void BindImage(uint32_t client_texture_id,
                  uint32_t texture_target,
                  gl::GLImage* image,
                  bool can_bind_to_sampler) override;
+  gles2::ContextGroup* GetContextGroup() override;
+  gles2::ErrorState* GetErrorState() override;
 
   // ErrorClientState implementation.
   void OnContextLostError() override;
   void OnOutOfMemoryError() override;
 
+  bool debug() const { return debug_; }
+
+  // Set to true to call glGetError after every command.
+  void set_debug(bool debug) { debug_ = debug; }
+
+  bool log_commands() const { return log_commands_; }
+
+  // Set to true to LOG every command.
+  void set_log_commands(bool log_commands) { log_commands_ = log_commands; }
+
  private:
   gl::GLApi* api() const { return state_.api(); }
 
@@ -174,6 +141,12 @@
   error::Error HandleWaitSyncTokenCHROMIUM(uint32_t immediate_data_size,
                                            const volatile void* cmd_data);
 
+  template <bool DebugImpl>
+  error::Error DoCommandsImpl(unsigned int num_commands,
+                              const volatile void* buffer,
+                              int num_entries,
+                              int* entries_processed);
+
   typedef gpu::gles2::GLES2Decoder::Error (RasterDecoder::*CmdHandler)(
       uint32_t immediate_data_size,
       const volatile void* data);
@@ -190,6 +163,8 @@
   static CommandInfo
       command_info[gles2::kNumCommands - gles2::kFirstGLES2Command];
 
+  bool initialized_;
+
   // Number of commands remaining to be processed in DoCommands().
   int commands_to_process_;
 
@@ -201,7 +176,7 @@
   scoped_refptr<gl::GLSurface> surface_;
   scoped_refptr<gl::GLContext> context_;
 
-  gles2::GLES2DecoderClient* client_;
+  DecoderClient* client_;
 
   gles2::DebugMarkerManager debug_marker_manager_;
   gles2::Logger logger_;
@@ -214,7 +189,11 @@
   // All the state for this context.
   gles2::ContextState state_;
 
-  base::WeakPtrFactory<gles2::GLES2Decoder> weak_ptr_factory_;
+  bool debug_;
+  bool log_commands_;
+  bool gpu_debug_commands_;
+
+  base::WeakPtrFactory<DecoderContext> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RasterDecoder);
 };
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index 69a5c39..de879db 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -28,7 +28,7 @@
 #include "gpu/command_buffer/common/context_result.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/service_discardable_manager.h"
@@ -86,7 +86,7 @@
     : public CommandBuffer,
       public GpuControl,
       public CommandBufferServiceClient,
-      public gles2::GLES2DecoderClient,
+      public DecoderClient,
       public ImageTransportSurfaceDelegate {
  public:
   class Service;
@@ -153,7 +153,7 @@
   CommandBatchProcessedResult OnCommandBatchProcessed() override;
   void OnParseError() override;
 
-  // GLES2DecoderClient implementation:
+  // DecoderClient implementation:
   void OnConsoleMessage(int32_t id, const std::string& message) override;
   void CacheShader(const std::string& key, const std::string& shader) override;
   void OnFenceSyncRelease(uint64_t release) override;
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 79b0b0e..3c3eadb5 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -23,6 +23,7 @@
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 #include "gpu/command_buffer/service/gl_state_restorer_impl.h"
 #include "gpu/command_buffer/service/gpu_fence_manager.h"
@@ -266,7 +267,7 @@
   // messages directed at the command buffer. This ensures that the message
   // handler can assume that the context is current (not necessary for
   // RetireSyncPoint or WaitSyncPoint).
-  if (decoder_.get() &&
+  if (decoder_context_.get() &&
       message.type() != GpuCommandBufferMsg_SetGetBuffer::ID &&
       message.type() != GpuCommandBufferMsg_WaitForTokenInRange::ID &&
       message.type() != GpuCommandBufferMsg_WaitForGetOffsetInRange::ID &&
@@ -315,8 +316,8 @@
 
   // Ensure that any delayed work that was created will be handled.
   if (have_context) {
-    if (decoder_)
-      decoder_->ProcessPendingQueries(false);
+    if (decoder_context_)
+      decoder_context_->ProcessPendingQueries(false);
     ScheduleDelayedWork(
         base::TimeDelta::FromMilliseconds(kHandleMoreWorkPeriodMs));
   }
@@ -354,10 +355,10 @@
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
-  if (decoder_.get() && !MakeCurrent())
+  if (decoder_context_.get() && !MakeCurrent())
     return;
 
-  if (decoder_) {
+  if (decoder_context_) {
     uint32_t current_unprocessed_num =
         channel()->sync_point_manager()->GetUnprocessedOrderNum();
     // We're idle when no messages were processed or scheduled.
@@ -375,11 +376,11 @@
 
     if (is_idle) {
       last_idle_time_ = base::TimeTicks::Now();
-      decoder_->PerformIdleWork();
+      decoder_context_->PerformIdleWork();
     }
 
-    decoder_->ProcessPendingQueries(false);
-    decoder_->PerformPollingWork();
+    decoder_context_->ProcessPendingQueries(false);
+    decoder_context_->PerformPollingWork();
   }
 
   ScheduleDelayedWork(
@@ -396,9 +397,10 @@
 }
 
 void CommandBufferStub::ScheduleDelayedWork(base::TimeDelta delay) {
-  bool has_more_work = decoder_.get() && (decoder_->HasPendingQueries() ||
-                                          decoder_->HasMoreIdleWork() ||
-                                          decoder_->HasPollingWork());
+  bool has_more_work =
+      decoder_context_.get() && (decoder_context_->HasPendingQueries() ||
+                                 decoder_context_->HasMoreIdleWork() ||
+                                 decoder_context_->HasPollingWork());
   if (!has_more_work) {
     last_idle_time_ = base::TimeTicks();
     return;
@@ -425,7 +427,7 @@
   // for more work at the rate idle work is performed. This also ensures
   // that idle work is done as efficiently as possible without any
   // unnecessary delays.
-  if (command_buffer_->scheduled() && decoder_->HasMoreIdleWork()) {
+  if (command_buffer_->scheduled() && decoder_context_->HasMoreIdleWork()) {
     delay = base::TimeDelta();
   }
 
@@ -435,7 +437,7 @@
 }
 
 bool CommandBufferStub::MakeCurrent() {
-  if (decoder_->MakeCurrent())
+  if (decoder_context_->MakeCurrent())
     return true;
   DLOG(ERROR) << "Context lost because MakeCurrent failed.";
   command_buffer_->SetParseError(error::kLostContext);
@@ -476,10 +478,11 @@
   }
 
   bool have_context = false;
-  if (decoder_ && decoder_->GetGLContext()) {
+  if (decoder_context_ && decoder_context_->GetGLContext()) {
     // Try to make the context current regardless of whether it was lost, so we
     // don't leak resources.
-    have_context = decoder_->GetGLContext()->MakeCurrent(surface_.get());
+    have_context =
+        decoder_context_->GetGLContext()->MakeCurrent(surface_.get());
   }
   for (auto& observer : destruction_observers_)
     observer.OnWillDestroyStub();
@@ -491,9 +494,9 @@
   // calls.
   surface_ = nullptr;
 
-  if (decoder_) {
-    decoder_->Destroy(have_context);
-    decoder_.reset();
+  if (decoder_context_) {
+    decoder_context_->Destroy(have_context);
+    decoder_context_.reset();
   }
 
   command_buffer_.reset();
@@ -517,17 +520,17 @@
 
 void CommandBufferStub::OnTakeFrontBuffer(const Mailbox& mailbox) {
   TRACE_EVENT0("gpu", "CommandBufferStub::OnTakeFrontBuffer");
-  if (!decoder_) {
+  if (!decoder_context_) {
     LOG(ERROR) << "Can't take front buffer before initialization.";
     return;
   }
 
-  decoder_->TakeFrontBuffer(mailbox);
+  decoder_context_->TakeFrontBuffer(mailbox);
 }
 
 void CommandBufferStub::OnReturnFrontBuffer(const Mailbox& mailbox,
                                             bool is_lost) {
-  decoder_->ReturnFrontBuffer(mailbox, is_lost);
+  decoder_context_->ReturnFrontBuffer(mailbox, is_lost);
 }
 
 CommandBufferServiceClient::CommandBatchProcessedResult
@@ -643,7 +646,7 @@
   last_flush_id_ = flush_id;
   CommandBuffer::State pre_state = command_buffer_->GetState();
   FastSetActiveURL(active_url_, active_url_hash_, channel_);
-  command_buffer_->Flush(put_offset, decoder_.get());
+  command_buffer_->Flush(put_offset, decoder_context_.get());
   CommandBuffer::State post_state = command_buffer_->GetState();
 
   if (pre_state.get_offset != post_state.get_offset)
@@ -703,8 +706,8 @@
 }
 
 void CommandBufferStub::OnSignalQuery(uint32_t query_id, uint32_t id) {
-  if (decoder_) {
-    gles2::QueryManager* query_manager = decoder_->GetQueryManager();
+  if (decoder_context_) {
+    gles2::QueryManager* query_manager = decoder_context_->GetQueryManager();
     if (query_manager) {
       gles2::QueryManager::Query* query = query_manager->GetQuery(query_id);
       if (query) {
@@ -727,8 +730,8 @@
     return;
   }
 
-  if (decoder_->GetGpuFenceManager()->CreateGpuFenceFromHandle(gpu_fence_id,
-                                                               handle))
+  if (decoder_context_->GetGpuFenceManager()->CreateGpuFenceFromHandle(
+          gpu_fence_id, handle))
     return;
 
   // The insertion failed. This shouldn't happen, force context loss to avoid
@@ -744,7 +747,7 @@
     return;
   }
 
-  auto* manager = decoder_->GetGpuFenceManager();
+  auto* manager = decoder_context_->GetGpuFenceManager();
   gfx::GpuFenceHandle handle;
   if (manager->IsValidGpuFence(gpu_fence_id)) {
     std::unique_ptr<gfx::GpuFence> gpu_fence =
@@ -774,7 +777,7 @@
 
 void CommandBufferStub::OnDescheduleUntilFinished() {
   DCHECK(command_buffer_->scheduled());
-  DCHECK(decoder_->HasPollingWork());
+  DCHECK(decoder_context_->HasPollingWork());
 
   command_buffer_->SetScheduled(false);
   channel_->OnCommandBufferDescheduled(this);
@@ -840,7 +843,7 @@
   }
 
   if (!gpu::IsImageFromGpuMemoryBufferFormatSupported(
-          format, decoder_->GetCapabilities())) {
+          format, decoder_context_->GetCapabilities())) {
     LOG(ERROR) << "Format is not supported.";
     return;
   }
@@ -922,7 +925,8 @@
 
   if (was_lost) {
     bool was_lost_by_robustness =
-        decoder_ && decoder_->WasContextLostByRobustnessExtension();
+        decoder_context_ &&
+        decoder_context_->WasContextLostByRobustnessExtension();
 
     // Work around issues with recovery by allowing a new GPU process to launch.
     if ((was_lost_by_robustness ||
@@ -949,8 +953,8 @@
     return;
 
   command_buffer_->SetContextLostReason(error::kUnknown);
-  if (decoder_)
-    decoder_->MarkContextLost(error::kUnknown);
+  if (decoder_context_)
+    decoder_context_->MarkContextLost(error::kUnknown);
   command_buffer_->SetParseError(error::kLostContext);
 }
 
diff --git a/gpu/ipc/service/command_buffer_stub.h b/gpu/ipc/service/command_buffer_stub.h
index 41a915fc..f8fee65 100644
--- a/gpu/ipc/service/command_buffer_stub.h
+++ b/gpu/ipc/service/command_buffer_stub.h
@@ -22,7 +22,7 @@
 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_client.h"
 #include "gpu/command_buffer/service/sequence_id.h"
 #include "gpu/ipc/common/surface_handle.h"
 #include "gpu/ipc/service/gpu_ipc_service_export.h"
@@ -42,6 +42,7 @@
 struct GpuCommandBufferMsg_CreateImage_Params;
 
 namespace gpu {
+class DecoderContext;
 struct Mailbox;
 struct SyncToken;
 struct WaitForCommandState;
@@ -52,7 +53,7 @@
     : public IPC::Listener,
       public IPC::Sender,
       public CommandBufferServiceClient,
-      public gles2::GLES2DecoderClient,
+      public DecoderClient,
       public base::SupportsWeakPtr<CommandBufferStub> {
  public:
   class DestructionObserver {
@@ -91,7 +92,7 @@
   CommandBatchProcessedResult OnCommandBatchProcessed() override;
   void OnParseError() override;
 
-  // GLES2DecoderClient implementation:
+  // DecoderClient implementation:
   void OnConsoleMessage(int32_t id, const std::string& message) override;
   void CacheShader(const std::string& key, const std::string& shader) override;
   void OnFenceSyncRelease(uint64_t release) override;
@@ -107,7 +108,7 @@
   // Whether there are commands in the buffer that haven't been processed.
   bool HasUnprocessedCommands();
 
-  gles2::GLES2Decoder* decoder() const { return decoder_.get(); }
+  DecoderContext* decoder_context() const { return decoder_context_.get(); }
   GpuChannel* channel() const { return channel_; }
 
   // Unique command buffer ID for this command buffer stub.
@@ -137,6 +138,12 @@
   gles2::MemoryTracker* CreateMemoryTracker(
       const GPUCreateCommandBufferConfig init_params) const;
 
+  // Must be called during Initialize(). Takes ownership to co-ordinate
+  // teardown in Destroy().
+  void set_decoder_context(std::unique_ptr<DecoderContext> decoder_context) {
+    decoder_context_ = std::move(decoder_context);
+  }
+
   // The lifetime of objects of this class is managed by a GpuChannel. The
   // GpuChannels destroy all the CommandBufferStubs that they own when
   // they are destroyed. So a raw pointer is safe.
@@ -153,7 +160,6 @@
   bool use_virtualized_gl_context_;
 
   std::unique_ptr<CommandBufferService> command_buffer_;
-  std::unique_ptr<gles2::GLES2Decoder> decoder_;
 
   scoped_refptr<gl::GLSurface> surface_;
   scoped_refptr<SyncPointClientState> sync_point_client_state_;
@@ -230,6 +236,8 @@
   static void SetContextGpuFeatureInfo(gl::GLContext* context,
                                        const GpuFeatureInfo& gpu_feature_info);
 
+  std::unique_ptr<DecoderContext> decoder_context_;
+
   uint32_t last_flush_id_;
 
   base::ObserverList<DestructionObserver> destruction_observers_;
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index 63a5022..4d45a0a 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -166,7 +166,7 @@
 
   command_buffer_ = std::make_unique<CommandBufferService>(
       this, context_group_->transfer_buffer_manager());
-  decoder_.reset(gles2::GLES2Decoder::Create(
+  std::unique_ptr<gles2::GLES2Decoder> decoder(gles2::GLES2Decoder::Create(
       this, command_buffer_.get(), manager->outputter(), context_group_.get()));
 
   sync_point_client_state_ =
@@ -284,7 +284,7 @@
            gl::GetGLImplementation() == gl::kGLImplementationMockGL ||
            gl::GetGLImplementation() == gl::kGLImplementationStubGL);
     context = base::MakeRefCounted<GLContextVirtual>(
-        share_group_.get(), context.get(), decoder_->AsWeakPtr());
+        share_group_.get(), context.get(), decoder->AsWeakPtr());
     if (!context->Initialize(surface_.get(),
                              GenerateGLContextAttribs(init_params.attribs,
                                                       context_group_.get()))) {
@@ -320,7 +320,7 @@
   }
 
   if (!context->GetGLStateRestorer()) {
-    context->SetGLStateRestorer(new GLStateRestorerImpl(decoder_->AsWeakPtr()));
+    context->SetGLStateRestorer(new GLStateRestorerImpl(decoder->AsWeakPtr()));
   }
 
   if (!context_group_->has_program_cache() &&
@@ -329,17 +329,18 @@
   }
 
   // Initialize the decoder with either the view or pbuffer GLContext.
-  auto result = decoder_->Initialize(surface_, context, offscreen,
-                                     gpu::gles2::DisallowedFeatures(),
-                                     init_params.attribs);
+  auto result = decoder->Initialize(surface_, context, offscreen,
+                                    gpu::gles2::DisallowedFeatures(),
+                                    init_params.attribs);
   if (result != gpu::ContextResult::kSuccess) {
     DLOG(ERROR) << "Failed to initialize decoder.";
     return result;
   }
 
   if (manager->gpu_preferences().enable_gpu_service_logging) {
-    decoder_->set_log_commands(true);
+    decoder->set_log_commands(true);
   }
+  set_decoder_context(std::move(decoder));
 
   const size_t kSharedStateSize = sizeof(CommandBufferSharedState);
   if (!shared_state_shm->Map(kSharedStateSize)) {
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index 281195c..fa01d89 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -542,7 +542,7 @@
 const CommandBufferStub* GpuChannel::GetOneStub() const {
   for (const auto& kv : stubs_) {
     const CommandBufferStub* stub = kv.second.get();
-    if (stub->decoder() && !stub->decoder()->WasContextLost())
+    if (stub->decoder_context() && !stub->decoder_context()->WasContextLost())
       return stub;
   }
   return nullptr;
@@ -595,7 +595,7 @@
     return;
   }
 
-  if (share_group && !share_group->decoder()) {
+  if (share_group && !share_group->decoder_context()) {
     // This should catch test errors where we did not Initialize the
     // share_group's CommandBuffer.
     LOG(ERROR) << "ContextResult::kFatalFailure: "
@@ -603,7 +603,7 @@
     return;
   }
 
-  if (share_group && share_group->decoder()->WasContextLost()) {
+  if (share_group && share_group->decoder_context()->WasContextLost()) {
     // The caller should retry to get a context.
     LOG(ERROR) << "ContextResult::kTransientFailure: "
                   "shared context was already lost";
@@ -647,7 +647,7 @@
   }
 
   *result = ContextResult::kSuccess;
-  *capabilities = stub->decoder()->GetCapabilities();
+  *capabilities = stub->decoder_context()->GetCapabilities();
   stubs_[route_id] = std::move(stub);
 }
 
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index a55eb64..15ca245 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -254,11 +254,11 @@
     const GpuChannel* channel = kv.second.get();
     stub = channel->GetOneStub();
     if (stub) {
-      DCHECK(stub->decoder());
+      DCHECK(stub->decoder_context());
       break;
     }
   }
-  if (!stub || !stub->decoder()->MakeCurrent())
+  if (!stub || !stub->decoder_context()->MakeCurrent())
     return;
   glFinish();
   DidAccessGpu();
diff --git a/gpu/ipc/service/raster_command_buffer_stub.cc b/gpu/ipc/service/raster_command_buffer_stub.cc
index 7eb8506..4e4e8a7 100644
--- a/gpu/ipc/service/raster_command_buffer_stub.cc
+++ b/gpu/ipc/service/raster_command_buffer_stub.cc
@@ -65,6 +65,8 @@
                         stream_id,
                         route_id) {}
 
+RasterCommandBufferStub::~RasterCommandBufferStub() {}
+
 gpu::ContextResult RasterCommandBufferStub::Initialize(
     CommandBufferStub* share_command_buffer_stub,
     const GPUCreateCommandBufferConfig& init_params,
@@ -131,8 +133,8 @@
 
   command_buffer_ = std::make_unique<CommandBufferService>(
       this, context_group_->transfer_buffer_manager());
-  decoder_.reset(new raster::RasterDecoder(
-      this, command_buffer_.get(), manager->outputter(), context_group_.get()));
+  auto decoder = std::make_unique<raster::RasterDecoder>(
+      this, command_buffer_.get(), manager->outputter(), context_group_.get());
 
   sync_point_client_state_ =
       channel_->sync_point_manager()->CreateSyncPointClientState(
@@ -187,7 +189,7 @@
            gl::GetGLImplementation() == gl::kGLImplementationMockGL ||
            gl::GetGLImplementation() == gl::kGLImplementationStubGL);
     context = base::MakeRefCounted<GLContextVirtual>(
-        share_group_.get(), context.get(), decoder_->AsWeakPtr());
+        share_group_.get(), context.get(), decoder->AsWeakPtr());
     if (!context->Initialize(surface_.get(),
                              GenerateGLContextAttribs(init_params.attribs,
                                                       context_group_.get()))) {
@@ -223,7 +225,7 @@
   }
 
   if (!context->GetGLStateRestorer()) {
-    context->SetGLStateRestorer(new GLStateRestorerImpl(decoder_->AsWeakPtr()));
+    context->SetGLStateRestorer(new GLStateRestorerImpl(decoder->AsWeakPtr()));
   }
 
   if (!context_group_->has_program_cache() &&
@@ -232,17 +234,18 @@
   }
 
   // Initialize the decoder with either the view or pbuffer GLContext.
-  auto result = decoder_->Initialize(surface_, context, true /* offscreen */,
-                                     gpu::gles2::DisallowedFeatures(),
-                                     init_params.attribs);
+  auto result = decoder->Initialize(surface_, context, true /* offscreen */,
+                                    gpu::gles2::DisallowedFeatures(),
+                                    init_params.attribs);
   if (result != gpu::ContextResult::kSuccess) {
     DLOG(ERROR) << "Failed to initialize decoder.";
     return result;
   }
 
   if (manager->gpu_preferences().enable_gpu_service_logging) {
-    decoder_->set_log_commands(true);
+    decoder->set_log_commands(true);
   }
+  set_decoder_context(std::move(decoder));
 
   const size_t kSharedStateSize = sizeof(CommandBufferSharedState);
   if (!shared_state_shm->Map(kSharedStateSize)) {
diff --git a/gpu/ipc/service/raster_command_buffer_stub.h b/gpu/ipc/service/raster_command_buffer_stub.h
index 0f82a8fd..dda51238 100644
--- a/gpu/ipc/service/raster_command_buffer_stub.h
+++ b/gpu/ipc/service/raster_command_buffer_stub.h
@@ -18,6 +18,7 @@
                           SequenceId sequence_id,
                           int32_t stream_id,
                           int32_t route_id);
+  ~RasterCommandBufferStub() override;
 
   // This must leave the GL context associated with the newly-created
   // CommandBufferStub current, so the GpuChannel can initialize
diff --git a/gpu/ipc/service/stream_texture_android.cc b/gpu/ipc/service/stream_texture_android.cc
index 8b905d1..bb7e51d5 100644
--- a/gpu/ipc/service/stream_texture_android.cc
+++ b/gpu/ipc/service/stream_texture_android.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/context_state.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/ipc/common/android/scoped_surface_request_conduit.h"
 #include "gpu/ipc/common/gpu_messages.h"
@@ -21,7 +21,6 @@
 namespace gpu {
 
 using gles2::ContextGroup;
-using gles2::GLES2Decoder;
 using gles2::TextureManager;
 using gles2::TextureRef;
 
@@ -29,9 +28,8 @@
 bool StreamTexture::Create(CommandBufferStub* owner_stub,
                            uint32_t client_texture_id,
                            int stream_id) {
-  GLES2Decoder* decoder = owner_stub->decoder();
   TextureManager* texture_manager =
-      decoder->GetContextGroup()->texture_manager();
+      owner_stub->context_group()->texture_manager();
   TextureRef* texture = texture_manager->GetTexture(client_texture_id);
 
   if (texture && (!texture->texture()->target() ||
@@ -104,10 +102,11 @@
 std::unique_ptr<ui::ScopedMakeCurrent> StreamTexture::MakeStubCurrent() {
   std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current;
   bool needs_make_current =
-      !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL);
+      !owner_stub_->decoder_context()->GetGLContext()->IsCurrent(NULL);
   if (needs_make_current) {
     scoped_make_current.reset(new ui::ScopedMakeCurrent(
-        owner_stub_->decoder()->GetGLContext(), owner_stub_->surface()));
+        owner_stub_->decoder_context()->GetGLContext(),
+        owner_stub_->surface()));
   }
   return scoped_make_current;
 }
@@ -130,7 +129,7 @@
     // far as the current context is concerned, but if we temporarily change
     // it, we have to keep the state intact in *that* context also.
     const gles2::ContextState* state =
-        owner_stub_->decoder()->GetContextState();
+        owner_stub_->decoder_context()->GetContextState();
     const gles2::TextureUnit& active_unit =
         state->texture_units[state->active_texture_unit];
     glBindTexture(GL_TEXTURE_EXTERNAL_OES,
@@ -161,7 +160,7 @@
   UpdateTexImage();
 
   TextureManager* texture_manager =
-      owner_stub_->decoder()->GetContextGroup()->texture_manager();
+      owner_stub_->context_group()->texture_manager();
   gles2::Texture* texture =
       texture_manager->GetTextureForServiceId(texture_id_);
   if (texture) {
diff --git a/headless/test/headless_render_browsertest.cc b/headless/test/headless_render_browsertest.cc
index a045db96..1eb107d43 100644
--- a/headless/test/headless_render_browsertest.cc
+++ b/headless/test/headless_render_browsertest.cc
@@ -1208,7 +1208,7 @@
  private:
   GURL GetPageUrl(HeadlessDevToolsClient* client) override {
     // Only first 3 scripts of 4 on the page are whitelisted for execution.
-    // Therefore only 3 linest in the log are expected.
+    // Therefore only 3 lines in the log are expected.
     GetProtocolHandler()->InsertResponse(
         "http://example.com/",
         {"HTTP/1.1 200 OK\r\n"
@@ -1239,4 +1239,93 @@
 };
 HEADLESS_RENDER_BROWSERTEST(ContentSecurityPolicy);
 
+class FrameLoadEvents : public HeadlessRenderTest {
+ private:
+  std::map<std::string, std::string> frame_navigated_;
+  std::map<std::string, std::string> frame_scheduled_;
+
+  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
+    GetProtocolHandler()->InsertResponse(
+        "http://example.com/", HttpRedirect(302, "http://example.com/1"));
+
+    GetProtocolHandler()->InsertResponse("http://example.com/1", HttpOk(R"|(
+<html><frameset>
+ <frame src="http://example.com/frameA/" id="frameA">
+ <frame src="http://example.com/frameB/" id="frameB">
+</frameset></html>
+)|"));
+
+    GetProtocolHandler()->InsertResponse("http://example.com/frameA/",
+                                         HttpOk(R"|(
+<html><head><script>
+ document.location="http://example.com/frameA/1"
+</script></head></html>
+)|"));
+
+    GetProtocolHandler()->InsertResponse("http://example.com/frameB/",
+                                         HttpOk(R"|(
+<html><head><script>
+ document.location="http://example.com/frameB/1"
+</script></head></html>
+)|"));
+
+    GetProtocolHandler()->InsertResponse(
+        "http://example.com/frameA/1",
+        HttpOk("<html><body>FRAME A 1</body></html>"));
+
+    GetProtocolHandler()->InsertResponse("http://example.com/frameB/1",
+                                         HttpOk(R"|(
+<html><body>FRAME B 1
+ <iframe src="http://example.com/frameB/1/iframe/" id="iframe"></iframe>
+</body></html>
+)|"));
+
+    GetProtocolHandler()->InsertResponse("http://example.com/frameB/1/iframe/",
+                                         HttpOk(R"|(
+<html><head><script>
+ document.location="http://example.com/frameB/1/iframe/1"
+</script></head></html>
+)|"));
+
+    GetProtocolHandler()->InsertResponse(
+        "http://example.com/frameB/1/iframe/1",
+        HttpOk("<html><body>IFRAME 1</body><html>"));
+
+    return GURL("http://example.com/");
+  }
+
+  void OnFrameNavigated(const page::FrameNavigatedParams& params) override {
+    frame_navigated_.insert(std::make_pair(params.GetFrame()->GetId(),
+                                           params.GetFrame()->GetUrl()));
+    HeadlessRenderTest::OnFrameNavigated(params);
+  }
+
+  void OnFrameScheduledNavigation(
+      const page::FrameScheduledNavigationParams& params) override {
+    frame_scheduled_.insert(
+        std::make_pair(params.GetFrameId(), params.GetUrl()));
+    HeadlessRenderTest::OnFrameScheduledNavigation(params);
+  }
+
+  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
+    std::vector<std::string> urls;
+    for (const auto& kv : frame_navigated_) {
+      urls.push_back(kv.second);
+    }
+    EXPECT_THAT(urls, UnorderedElementsAre(
+                          "http://example.com/1", "http://example.com/frameA/",
+                          "http://example.com/frameB/",
+                          "http://example.com/frameB/1/iframe/"));
+    urls.clear();
+    for (const auto& kv : frame_scheduled_) {
+      urls.push_back(kv.second);
+    }
+    EXPECT_THAT(urls,
+                UnorderedElementsAre("http://example.com/frameA/1",
+                                     "http://example.com/frameB/1",
+                                     "http://example.com/frameB/1/iframe/1"));
+  }
+};
+HEADLESS_RENDER_BROWSERTEST(FrameLoadEvents);
+
 }  // namespace headless
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder.h b/ios/chrome/browser/metrics/tab_usage_recorder.h
index 75cb753..77f9a568 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder.h
+++ b/ios/chrome/browser/metrics/tab_usage_recorder.h
@@ -232,7 +232,7 @@
                            web::WebState* old_web_state,
                            web::WebState* new_web_state,
                            int active_index,
-                           bool user_action) override;
+                           int reason) override;
 
   // Keep track of when the most recent tab restore begins, to record the time
   // between evicted-tab-reloads.
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder.mm b/ios/chrome/browser/metrics/tab_usage_recorder.mm
index 72ac72cb..145dc63 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder.mm
@@ -503,7 +503,7 @@
                                            web::WebState* old_web_state,
                                            web::WebState* new_web_state,
                                            int active_index,
-                                           bool user_action) {
-  if (user_action)
+                                           int reason) {
+  if (reason & WebStateListObserver::CHANGE_REASON_USER_ACTION)
     RecordTabSwitched(old_web_state, new_web_state);
 }
diff --git a/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.h b/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.h
index e513af26..d1932cb 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.h
+++ b/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.h
@@ -22,7 +22,7 @@
                            web::WebState* old_web_state,
                            web::WebState* new_web_state,
                            int active_index,
-                           bool user_action) override;
+                           int reason) override;
 
   SnapshotCache* snapshot_cache_;
 
diff --git a/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.mm b/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.mm
index 9a969eb..b462cd1 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.mm
+++ b/ios/chrome/browser/snapshots/snapshot_cache_web_state_list_observer.mm
@@ -27,8 +27,8 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int active_index,
-    bool user_action) {
-  if (!user_action)
+    int reason) {
+  if (!(reason & WebStateListObserver::CHANGE_REASON_USER_ACTION))
     return;
 
   NSMutableSet<NSString*>* set = [NSMutableSet set];
diff --git a/ios/chrome/browser/tabs/tab_model_observers_bridge.mm b/ios/chrome/browser/tabs/tab_model_observers_bridge.mm
index e901c8c4..dc5817e 100644
--- a/ios/chrome/browser/tabs/tab_model_observers_bridge.mm
+++ b/ios/chrome/browser/tabs/tab_model_observers_bridge.mm
@@ -83,7 +83,7 @@
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction {
+                     reason:(int)reason {
   if (!newWebState)
     return;
 
diff --git a/ios/chrome/browser/tabs/tab_model_selected_tab_observer.mm b/ios/chrome/browser/tabs/tab_model_selected_tab_observer.mm
index fd15070..72f9a98f 100644
--- a/ios/chrome/browser/tabs/tab_model_selected_tab_observer.mm
+++ b/ios/chrome/browser/tabs/tab_model_selected_tab_observer.mm
@@ -31,7 +31,7 @@
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction {
+                     reason:(int)reason {
   if (oldWebState) {
     // Save state, such as scroll position, ... of the old selected Tab.
     Tab* oldTab = LegacyTabHelper::GetTabForWebState(oldWebState);
diff --git a/ios/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm b/ios/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm
index 5d71807..7e1fb01 100644
--- a/ios/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm
+++ b/ios/chrome/browser/ui/browser_list/browser_list_session_service_impl.mm
@@ -49,7 +49,7 @@
                            web::WebState* old_web_state,
                            web::WebState* new_web_state,
                            int active_index,
-                           bool user_action) override;
+                           int reason) override;
 
   // web::WebStateObserver implementation.
   void NavigationItemCommitted(
@@ -90,7 +90,7 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int active_index,
-    bool user_action) {
+    int reason) {
   if (old_web_state) {
     scoped_observer_.Remove(old_web_state);
     closure_.Run();
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 289c4a6..733c652 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1597,12 +1597,6 @@
   if (IsIPhoneX()) {
     [self setUpViewLayout:NO];
   }
-  if (IsSafeAreaCompatibleToolbarEnabled()) {
-    // TODO(crbug.com/778236): Check if this call can be removed once the
-    // Toolbar is a contained ViewController.
-    [_toolbarCoordinator.toolbarViewController viewSafeAreaInsetsDidChange];
-    [_toolbarCoordinator adjustToolbarHeight];
-  }
 }
 
 - (void)viewDidAppear:(BOOL)animated {
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
index 684e62a1..1857409 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
@@ -454,7 +454,7 @@
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction {
+                     reason:(int)reason {
   if (newWebState) {
     self.webState = newWebState;
     web::NavigationManager* navigationManager =
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h
index 8564e18..1c22279 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h
@@ -37,7 +37,7 @@
                            web::WebState* old_web_state,
                            web::WebState* new_web_state,
                            int active_index,
-                           bool user_action) override;
+                           int reason) override;
 
   // The model passed on construction.
   FullscreenModel* model_;
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
index 01eefab..6fe32cfb 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.mm
@@ -59,6 +59,6 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int active_index,
-    bool user_action) {
+    int reason) {
   web_state_observer_.SetWebState(new_web_state);
 }
diff --git a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
index a5b554a5..60bd2ab 100644
--- a/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
+++ b/ios/chrome/browser/ui/main_content/web_scroll_view_main_content_ui_forwarder.mm
@@ -133,7 +133,7 @@
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction {
+                     reason:(int)reason {
   self.webState = newWebState;
 }
 
diff --git a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
index bb04df8..6cecee4 100644
--- a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
@@ -93,6 +93,8 @@
     "toolbar_button_factory.mm",
     "toolbar_button_tints.h",
     "toolbar_button_tints.mm",
+    "toolbar_button_visibility_configuration.h",
+    "toolbar_button_visibility_configuration.mm",
     "toolbar_component_options.h",
     "toolbar_configuration.h",
     "toolbar_configuration.mm",
@@ -101,6 +103,7 @@
     "toolbar_style.h",
     "toolbar_tools_menu_button.h",
     "toolbar_tools_menu_button.mm",
+    "toolbar_type.h",
   ]
   deps = [
     "//base",
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_button.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_button.mm
index d38ebe90..000767a 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_button.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_button.mm
@@ -46,36 +46,40 @@
 
 - (void)updateHiddenInCurrentSizeClass {
   BOOL newHiddenValue = YES;
-  if (!IsIPadIdiom()) {
-    if (self.visibilityMask &
-        ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled) {
-      newHiddenValue = !self.enabled;
-    } else if (self.visibilityMask & ToolbarComponentVisibilityCompactWidth ||
-               self.visibilityMask & ToolbarComponentVisibilityIPhoneOnly) {
-      newHiddenValue = NO;
-    }
-  } else {
-    switch (self.traitCollection.horizontalSizeClass) {
-      case UIUserInterfaceSizeClassRegular:
-        newHiddenValue =
-            !(self.visibilityMask & ToolbarComponentVisibilityRegularWidth);
-        break;
-      case UIUserInterfaceSizeClassCompact:
-        // First check if the button should be visible only when it's enabled,
-        // if not, check if it should be visible in this case.
-        if (self.visibilityMask &
-            ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled) {
-          newHiddenValue = !self.enabled;
-        } else if (self.visibilityMask &
-                   ToolbarComponentVisibilityCompactWidth) {
-          newHiddenValue = NO;
-        }
-        break;
-      case UIUserInterfaceSizeClassUnspecified:
-      default:
-        break;
-    }
+
+  BOOL isCompactWidth = self.traitCollection.horizontalSizeClass ==
+                        UIUserInterfaceSizeClassCompact;
+  BOOL isCompactHeight =
+      self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact;
+  BOOL isRegularWidth = self.traitCollection.horizontalSizeClass ==
+                        UIUserInterfaceSizeClassRegular;
+  BOOL isRegularHeight =
+      self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular;
+
+  if (isCompactWidth && isCompactHeight) {
+    newHiddenValue = !(self.visibilityMask &
+                       ToolbarComponentVisibilityCompactWidthCompactHeight);
+  } else if (isCompactWidth && isRegularHeight) {
+    newHiddenValue = !(self.visibilityMask &
+                       ToolbarComponentVisibilityCompactWidthRegularHeight);
+  } else if (isRegularWidth && isCompactHeight) {
+    newHiddenValue = !(self.visibilityMask &
+                       ToolbarComponentVisibilityRegularWidthCompactHeight);
+  } else if (isRegularWidth && isRegularHeight) {
+    newHiddenValue = !(self.visibilityMask &
+                       ToolbarComponentVisibilityRegularWidthRegularHeight);
   }
+
+  if (!IsIPadIdiom() &&
+      self.visibilityMask & ToolbarComponentVisibilityIPhoneOnly) {
+    newHiddenValue = NO;
+  }
+  if (isCompactWidth &&
+      (self.visibilityMask &
+       ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled)) {
+    newHiddenValue = !self.enabled;
+  }
+
   if (newHiddenValue != self.hiddenInCurrentSizeClass) {
     self.hiddenInCurrentSizeClass = newHiddenValue;
     [self setHiddenForCurrentStateAndSizeClass];
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h
index 9aa3fbe..91b8c81 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h
@@ -12,6 +12,7 @@
 @protocol ApplicationCommands;
 @protocol BrowserCommands;
 @class ToolbarButton;
+@class ToolbarButtonVisibilityConfiguration;
 @class ToolbarToolsMenuButton;
 @class ToolbarConfiguration;
 
@@ -30,6 +31,9 @@
     ToolbarConfiguration* toolbarConfiguration;
 // Dispatcher used to initialize targets for the buttons.
 @property(nonatomic, weak) id<ApplicationCommands, BrowserCommands> dispatcher;
+// Configuration object for the visibility of the buttons.
+@property(nonatomic, strong)
+    ToolbarButtonVisibilityConfiguration* visibilityConfiguration;
 
 // Back ToolbarButton.
 - (ToolbarButton*)backButton;
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 defa133..58142ce 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button.h"
+#import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h"
 #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"
@@ -42,6 +43,7 @@
 @synthesize toolbarConfiguration = _toolbarConfiguration;
 @synthesize style = _style;
 @synthesize dispatcher = _dispatcher;
+@synthesize visibilityConfiguration = _visibilityConfiguration;
 
 - (instancetype)initWithStyle:(ToolbarStyle)style {
   self = [super init];
@@ -79,6 +81,7 @@
   [backButton addTarget:self.dispatcher
                  action:@selector(goBack)
        forControlEvents:UIControlEventTouchUpInside];
+  backButton.visibilityMask = self.visibilityConfiguration.backButtonVisibility;
   return backButton;
 }
 
@@ -108,6 +111,8 @@
   [forwardButton addTarget:self.dispatcher
                     action:@selector(goForward)
           forControlEvents:UIControlEventTouchUpInside];
+  forwardButton.visibilityMask =
+      self.visibilityConfiguration.forwardButtonVisibility;
   return forwardButton;
 }
 
@@ -136,6 +141,8 @@
                              action:@selector(displayTabSwitcher)
                    forControlEvents:UIControlEventTouchUpInside];
 
+  tabSwitcherStripButton.visibilityMask =
+      self.visibilityConfiguration.tabGridButtonVisibility;
   return tabSwitcherStripButton;
 }
 
@@ -163,6 +170,8 @@
   [toolsMenuButton addTarget:self.dispatcher
                       action:@selector(showToolsMenu)
             forControlEvents:UIControlEventTouchUpInside];
+  toolsMenuButton.visibilityMask =
+      self.visibilityConfiguration.toolsMenuButtonVisibility;
   return toolsMenuButton;
 }
 
@@ -186,6 +195,8 @@
   [shareButton addTarget:self.dispatcher
                   action:@selector(sharePage)
         forControlEvents:UIControlEventTouchUpInside];
+  shareButton.visibilityMask =
+      self.visibilityConfiguration.shareButtonVisibility;
   return shareButton;
 }
 
@@ -211,6 +222,8 @@
   [reloadButton addTarget:self.dispatcher
                    action:@selector(reload)
          forControlEvents:UIControlEventTouchUpInside];
+  reloadButton.visibilityMask =
+      self.visibilityConfiguration.reloadButtonVisibility;
   return reloadButton;
 }
 
@@ -232,6 +245,7 @@
   [stopButton addTarget:self.dispatcher
                  action:@selector(stopLoading)
        forControlEvents:UIControlEventTouchUpInside];
+  stopButton.visibilityMask = self.visibilityConfiguration.stopButtonVisibility;
   return stopButton;
 }
 
@@ -256,6 +270,8 @@
                      action:@selector(bookmarkPage)
            forControlEvents:UIControlEventTouchUpInside];
 
+  bookmarkButton.visibilityMask =
+      self.visibilityConfiguration.bookmarkButtonVisibility;
   return bookmarkButton;
 }
 
@@ -269,6 +285,8 @@
       l10n_util::GetNSString(IDS_IOS_ACCNAME_VOICE_SEARCH);
   [self configureButton:voiceSearchButton width:kToolbarButtonWidth];
   voiceSearchButton.enabled = NO;
+  voiceSearchButton.visibilityMask =
+      self.visibilityConfiguration.voiceSearchButtonVisibility;
   return voiceSearchButton;
 }
 
@@ -289,6 +307,8 @@
                      action:@selector(contractToolbar)
            forControlEvents:UIControlEventTouchUpInside];
 
+  contractButton.visibilityMask =
+      self.visibilityConfiguration.contractButtonVisibility;
   return contractButton;
 }
 
@@ -307,6 +327,8 @@
     locationBarLeadingButton.imageEdgeInsets =
         UIEdgeInsetsMakeDirected(0, kLeadingLocationBarButtonImageInset, 0, 0);
   }
+  locationBarLeadingButton.visibilityMask =
+      self.visibilityConfiguration.locationBarLeadingButtonVisibility;
 
   return locationBarLeadingButton;
 }
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h
new file mode 100644
index 0000000..29b9a9b357
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_BUTTON_VISIBILITY_CONFIGURATION_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_BUTTON_VISIBILITY_CONFIGURATION_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/toolbar/clean/toolbar_component_options.h"
+#import "ios/chrome/browser/ui/toolbar/clean/toolbar_type.h"
+
+// Toolbar button configuration object giving access to visibility mask for each
+// button.
+@interface ToolbarButtonVisibilityConfiguration : NSObject
+
+// Init the toolbar configuration with the desired |type|.
+- (instancetype)initWithType:(ToolbarType)type NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+// Type of this configuration.
+@property(nonatomic, assign) ToolbarType type;
+
+// Configuration for the different buttons.
+@property(nonatomic, readonly) ToolbarComponentVisibility backButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility forwardButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility tabGridButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility toolsMenuButtonVisibility;
+@property(nonatomic, readonly) ToolbarComponentVisibility shareButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility reloadButtonVisibility;
+@property(nonatomic, readonly) ToolbarComponentVisibility stopButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility bookmarkButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility voiceSearchButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility contractButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility omniboxButtonVisibility;
+@property(nonatomic, readonly)
+    ToolbarComponentVisibility locationBarLeadingButtonVisibility;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_BUTTON_VISIBILITY_CONFIGURATION_H_
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.mm
new file mode 100644
index 0000000..40545b8
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.mm
@@ -0,0 +1,165 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation ToolbarButtonVisibilityConfiguration
+
+@synthesize type = _type;
+
+- (instancetype)initWithType:(ToolbarType)type {
+  self = [super init];
+  if (self) {
+    _type = type;
+  }
+  return self;
+}
+
+- (ToolbarComponentVisibility)backButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways;
+    case SECONDARY:
+      return ToolbarComponentVisibilityNone;
+    case LEGACY:
+      return ToolbarComponentVisibilityAlways;
+  }
+}
+
+- (ToolbarComponentVisibility)forwardButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways;
+    case SECONDARY:
+      return ToolbarComponentVisibilityNone;
+    case LEGACY:
+      return ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled |
+             ToolbarComponentVisibilityRegularWidthCompactHeight |
+             ToolbarComponentVisibilityRegularWidthRegularHeight;
+  }
+}
+
+- (ToolbarComponentVisibility)tabGridButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways &
+             !ToolbarComponentVisibilityRegularWidthRegularHeight;
+    case SECONDARY:
+      return ToolbarComponentVisibilityAlways;
+    case LEGACY:
+      return ToolbarComponentVisibilityIPhoneOnly;
+  }
+}
+
+- (ToolbarComponentVisibility)toolsMenuButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways;
+    case SECONDARY:
+      return ToolbarComponentVisibilityAlways;
+    case LEGACY:
+      return ToolbarComponentVisibilityAlways;
+  }
+}
+
+- (ToolbarComponentVisibility)shareButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways &
+             !ToolbarComponentVisibilityCompactWidthRegularHeight;
+    case SECONDARY:
+      return ToolbarComponentVisibilityAlways;
+    case LEGACY:
+      return ToolbarComponentVisibilityRegularWidthCompactHeight |
+             ToolbarComponentVisibilityRegularWidthRegularHeight;
+  }
+}
+
+- (ToolbarComponentVisibility)reloadButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityRegularWidthRegularHeight;
+    case SECONDARY:
+      return ToolbarComponentVisibilityRegularWidthRegularHeight;
+    case LEGACY:
+      return ToolbarComponentVisibilityRegularWidthCompactHeight |
+             ToolbarComponentVisibilityRegularWidthRegularHeight;
+  }
+}
+
+- (ToolbarComponentVisibility)stopButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityRegularWidthRegularHeight;
+    case SECONDARY:
+      return ToolbarComponentVisibilityRegularWidthRegularHeight;
+    case LEGACY:
+      return ToolbarComponentVisibilityRegularWidthCompactHeight |
+             ToolbarComponentVisibilityRegularWidthRegularHeight;
+  }
+}
+
+- (ToolbarComponentVisibility)bookmarkButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways &
+             !ToolbarComponentVisibilityCompactWidthRegularHeight;
+    case SECONDARY:
+      return ToolbarComponentVisibilityAlways;
+    case LEGACY:
+      return ToolbarComponentVisibilityRegularWidthCompactHeight |
+             ToolbarComponentVisibilityRegularWidthRegularHeight;
+  }
+}
+
+- (ToolbarComponentVisibility)voiceSearchButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityRegularWidthRegularHeight;
+    case SECONDARY:
+      return ToolbarComponentVisibilityNone;
+    case LEGACY:
+      return ToolbarComponentVisibilityRegularWidthCompactHeight |
+             ToolbarComponentVisibilityRegularWidthRegularHeight;
+  }
+}
+
+- (ToolbarComponentVisibility)contractButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityNone;
+    case SECONDARY:
+      return ToolbarComponentVisibilityNone;
+    case LEGACY:
+      return ToolbarComponentVisibilityAlways;
+  }
+}
+
+- (ToolbarComponentVisibility)omniboxButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityNone;
+    case SECONDARY:
+      return ToolbarComponentVisibilityAlways;
+    case LEGACY:
+      return ToolbarComponentVisibilityNone;
+  }
+}
+
+- (ToolbarComponentVisibility)locationBarLeadingButtonVisibility {
+  switch (self.type) {
+    case PRIMARY:
+      return ToolbarComponentVisibilityAlways;
+    case SECONDARY:
+      return ToolbarComponentVisibilityNone;
+    case LEGACY:
+      return ToolbarComponentVisibilityAlways;
+  }
+}
+
+@end
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_component_options.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_component_options.h
index 8f84539..f6c4c62 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_component_options.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_component_options.h
@@ -11,17 +11,32 @@
 typedef NS_OPTIONS(NSUInteger, ToolbarComponentVisibility) {
   // Default option, the component will never be visible.
   ToolbarComponentVisibilityNone = 0,
-  // Use this option when the component should always be visible in
-  // CompactWidth.
-  ToolbarComponentVisibilityCompactWidth = 1 << 0,
-  // Use this option when the component should always be visible in
-  // RegularWidth.
-  ToolbarComponentVisibilityRegularWidth = 1 << 1,
+  // Use this option when the component should be visible in CompactWidth x
+  // CompactHeight.
+  ToolbarComponentVisibilityCompactWidthCompactHeight = 1 << 0,
+  // Use this option when the component should be visible in CompactWidth x
+  // CompactHeight.
+  ToolbarComponentVisibilityRegularWidthCompactHeight = 1 << 1,
+  // Use this option when the component should be visible in CompactWidth x
+  // RegularHeight.
+  ToolbarComponentVisibilityCompactWidthRegularHeight = 1 << 2,
+  // Use this option when the component should be visible in
+  // RegularWidth x RegularHeight.
+  ToolbarComponentVisibilityRegularWidthRegularHeight = 1 << 3,
+  // Use this option when the component should alwas be visible.
+  ToolbarComponentVisibilityAlways =
+      (ToolbarComponentVisibilityRegularWidthRegularHeight |
+       ToolbarComponentVisibilityRegularWidthCompactHeight |
+       ToolbarComponentVisibilityCompactWidthCompactHeight |
+       ToolbarComponentVisibilityCompactWidthRegularHeight),
+
+  // TODO(crbug.com/800266): Remove this, only used for non-adaptive toolbar.
   // Use this option when the component should be visible in CompactWidth only
-  // if it's enabled.
-  ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled = 1 << 2,
+  // if it's enabled. Override other CompactWidth settings.
+  ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled = 1 << 4,
+  // TODO(crbug.com/800266): Remove this, only used for non-adaptive toolbar.
   // Use this option when the component should be always visible on iPhone only.
-  ToolbarComponentVisibilityIPhoneOnly = 1 << 3,
+  ToolbarComponentVisibilityIPhoneOnly = 1 << 5,
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_COMPONENT_OPTIONS_H_
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index c36adf4..75cdfd6e 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -35,6 +35,7 @@
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_updater.h"
+#import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_style.h"
@@ -147,6 +148,8 @@
   ToolbarButtonFactory* factory =
       [[ToolbarButtonFactory alloc] initWithStyle:style];
   factory.dispatcher = self.dispatcher;
+  factory.visibilityConfiguration =
+      [[ToolbarButtonVisibilityConfiguration alloc] initWithType:LEGACY];
 
   self.buttonUpdater = [[ToolbarButtonUpdater alloc] init];
   self.buttonUpdater.factory = factory;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm
index cf49258..9045ffbf 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm
@@ -146,7 +146,7 @@
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction {
+                     reason:(int)reason {
   DCHECK_EQ(_webStateList, webStateList);
   self.webState = newWebState;
 }
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_type.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_type.h
new file mode 100644
index 0000000..96da69f3
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_type.h
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_TYPE_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_TYPE_H_
+
+// Enum defining the different styles for the toolbar.
+typedef NS_ENUM(NSInteger, ToolbarType) {
+  // Primary toolbar.
+  PRIMARY = 0,
+  // Secondary toolbar.
+  SECONDARY = 1,
+  // TODO(crbug.com/800266): Remove this.
+  // Non-adaptive toolbar.
+  LEGACY = 2,
+};
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_CLEAN_TOOLBAR_TYPE_H_
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 d4ba662..2b705376 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -311,8 +311,6 @@
 
 - (void)setUpToolbarButtons {
   // Back button.
-  self.view.backButton.visibilityMask = ToolbarComponentVisibilityCompactWidth |
-                                        ToolbarComponentVisibilityRegularWidth;
   UILongPressGestureRecognizer* backHistoryLongPress =
       [[UILongPressGestureRecognizer alloc]
           initWithTarget:self
@@ -321,9 +319,6 @@
   [self addStandardActionsForButton:self.view.backButton];
 
   // Forward button.
-  self.view.forwardButton.visibilityMask =
-      ToolbarComponentVisibilityCompactWidthOnlyWhenEnabled |
-      ToolbarComponentVisibilityRegularWidth;
   UILongPressGestureRecognizer* forwardHistoryLongPress =
       [[UILongPressGestureRecognizer alloc]
           initWithTarget:self
@@ -332,52 +327,33 @@
   [self addStandardActionsForButton:self.view.forwardButton];
 
   // TabSwitcher button.
-  self.view.tabSwitchStripButton.visibilityMask =
-      ToolbarComponentVisibilityIPhoneOnly;
   [self addStandardActionsForButton:self.view.tabSwitchStripButton];
 
   // Tools menu button.
-  self.view.toolsMenuButton.visibilityMask =
-      ToolbarComponentVisibilityCompactWidth |
-      ToolbarComponentVisibilityRegularWidth;
   [self addStandardActionsForButton:self.view.toolsMenuButton];
 
   // Share button.
-  self.view.shareButton.visibilityMask = ToolbarComponentVisibilityRegularWidth;
   [self addStandardActionsForButton:self.view.shareButton];
 
   // Reload button.
-  self.view.reloadButton.visibilityMask =
-      ToolbarComponentVisibilityRegularWidth;
   [self addStandardActionsForButton:self.view.reloadButton];
 
   // Stop button.
-  self.view.stopButton.visibilityMask = ToolbarComponentVisibilityRegularWidth;
   self.view.stopButton.hiddenInCurrentState = YES;
   [self addStandardActionsForButton:self.view.stopButton];
 
   // Voice Search button.
-  self.view.voiceSearchButton.visibilityMask =
-      ToolbarComponentVisibilityRegularWidth;
   self.view.voiceSearchButton.enabled = NO;
   [self addStandardActionsForButton:self.view.voiceSearchButton];
 
   // Bookmark button.
-  self.view.bookmarkButton.visibilityMask =
-      ToolbarComponentVisibilityRegularWidth;
   [self addStandardActionsForButton:self.view.bookmarkButton];
 
   // Contract button.
-  self.view.contractButton.visibilityMask =
-      ToolbarComponentVisibilityCompactWidth |
-      ToolbarComponentVisibilityRegularWidth;
   self.view.contractButton.alpha = 0;
   self.view.contractButton.hidden = YES;
 
   // LocationBar LeadingButton
-  self.view.locationBarLeadingButton.visibilityMask =
-      ToolbarComponentVisibilityCompactWidth |
-      ToolbarComponentVisibilityRegularWidth;
   self.view.locationBarLeadingButton.alpha = 0;
   self.view.locationBarLeadingButton.hidden = YES;
 
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_ui_updater.mm b/ios/chrome/browser/ui/toolbar/legacy_toolbar_ui_updater.mm
index 0ab6e0a1..8e9c50f 100644
--- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_ui_updater.mm
+++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_ui_updater.mm
@@ -127,7 +127,7 @@
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction {
+                     reason:(int)reason {
   DCHECK_EQ(self.webStateList, webStateList);
   self.webState = newWebState;
 }
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 0e5d0f0..140f7fb 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -1919,6 +1919,7 @@
 
 - (void)viewSafeAreaInsetsDidChange {
   [super viewSafeAreaInsetsDidChange];
+  [self adjustToolbarHeight];
   if (!IsIPadIdiom()) {
     if (IsSafeAreaCompatibleToolbarEnabled()) {
       // The clipping view's height is supposed to match the toolbar's height.
diff --git a/ios/chrome/browser/web_state_list/web_state_list.h b/ios/chrome/browser/web_state_list/web_state_list.h
index 1ca7223..acae34b 100644
--- a/ios/chrome/browser/web_state_list/web_state_list.h
+++ b/ios/chrome/browser/web_state_list/web_state_list.h
@@ -156,9 +156,9 @@
   // specified index to null.
   void ClearOpenersReferencing(int index);
 
-  // Notify the observers if the active WebState change.
-  void NotifyIfActiveWebStateChanged(web::WebState* old_web_state,
-                                     bool user_action);
+  // Notify the observers if the active WebState change. |reason| is the value
+  // passed to the WebStateListObservers.
+  void NotifyIfActiveWebStateChanged(web::WebState* old_web_state, int reason);
 
   // Returns the index of the |n|-th WebState (with n > 0) in the sequence of
   // WebStates opened from the specified WebState after |start_index|, or
diff --git a/ios/chrome/browser/web_state_list/web_state_list.mm b/ios/chrome/browser/web_state_list/web_state_list.mm
index bc8d674..402e25d6 100644
--- a/ios/chrome/browser/web_state_list/web_state_list.mm
+++ b/ios/chrome/browser/web_state_list/web_state_list.mm
@@ -227,9 +227,15 @@
   std::unique_ptr<web::WebState> old_web_state =
       web_state_wrappers_[index]->ReplaceWebState(std::move(web_state));
 
-  for (auto& observer : observers_)
+  for (auto& observer : observers_) {
     observer.WebStateReplacedAt(this, old_web_state.get(), web_state_ptr,
                                 index);
+  }
+
+  // When the active WebState is replaced, notify the observers as nearly
+  // all of them needs to treat a replacement as the selection changed.
+  NotifyIfActiveWebStateChanged(old_web_state.get(),
+                                WebStateListObserver::CHANGE_REASON_REPLACED);
 
   delegate_->WebStateDetached(old_web_state.get());
   return old_web_state;
@@ -260,8 +266,10 @@
   for (auto& observer : observers_)
     observer.WebStateDetachedAt(this, web_state, index);
 
-  if (active_web_state_was_closed)
-    NotifyIfActiveWebStateChanged(web_state, false);
+  if (active_web_state_was_closed) {
+    NotifyIfActiveWebStateChanged(web_state,
+                                  WebStateListObserver::CHANGE_REASON_NONE);
+  }
 
   delegate_->WebStateDetached(web_state);
   return detached_web_state;
@@ -288,7 +296,8 @@
   DCHECK(ContainsIndex(index));
   web::WebState* old_web_state = GetActiveWebState();
   active_index_ = index;
-  NotifyIfActiveWebStateChanged(old_web_state, true);
+  NotifyIfActiveWebStateChanged(
+      old_web_state, WebStateListObserver::CHANGE_REASON_USER_ACTION);
 }
 
 void WebStateList::AddObserver(WebStateListObserver* observer) {
@@ -308,14 +317,14 @@
 }
 
 void WebStateList::NotifyIfActiveWebStateChanged(web::WebState* old_web_state,
-                                                 bool user_action) {
+                                                 int reason) {
   web::WebState* new_web_state = GetActiveWebState();
   if (old_web_state == new_web_state)
     return;
 
   for (auto& observer : observers_) {
     observer.WebStateActivatedAt(this, old_web_state, new_web_state,
-                                 active_index_, user_action);
+                                 active_index_, reason);
   }
 }
 
diff --git a/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.h b/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.h
index a179629..0a6c9946 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.h
+++ b/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.h
@@ -28,7 +28,7 @@
                            web::WebState* old_web_state,
                            web::WebState* new_web_state,
                            int active_index,
-                           bool user_action) override;
+                           int reason) override;
 
  private:
   // Counters for metrics.
diff --git a/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.mm b/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.mm
index 14e739a..c65913e 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.mm
+++ b/ios/chrome/browser/web_state_list/web_state_list_metrics_observer.mm
@@ -55,9 +55,9 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int active_index,
-    bool user_action) {
+    int reason) {
   ++activated_web_state_counter_;
-  if (!user_action)
+  if (!(reason & WebStateListObserver::CHANGE_REASON_USER_ACTION))
     return;
 
   base::RecordAction(base::UserMetricsAction("MobileTabSwitched"));
diff --git a/ios/chrome/browser/web_state_list/web_state_list_observer.h b/ios/chrome/browser/web_state_list/web_state_list_observer.h
index 9a1d3f02..3b0d3cfb 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_observer.h
+++ b/ios/chrome/browser/web_state_list/web_state_list_observer.h
@@ -16,6 +16,19 @@
 // Interface for listening to events occurring to WebStateLists.
 class WebStateListObserver {
  public:
+  // Constants used when notifying about changes to active WebState.
+  enum ChangeReason {
+    // Used to indicate that none of the reasons below are responsible for
+    // the active WebState change.
+    CHANGE_REASON_NONE = 0,
+
+    // Used to indicate the active WebState changed because it was replaced.
+    CHANGE_REASON_REPLACED = 1 << 0,
+
+    // Used to indicate the active WebState changed due to a user action.
+    CHANGE_REASON_USER_ACTION = 1 << 1,
+  };
+
   WebStateListObserver();
   virtual ~WebStateListObserver();
 
@@ -63,13 +76,14 @@
 
   // Invoked after |new_web_state| was activated at the specified index. Both
   // WebState are either valid or null (if there was no selection or there is
-  // no selection). If the change is due to an user action, |user_action| will
-  // be true.
+  // no selection). If |reason| has CHANGE_REASON_USER_ACTION set then the
+  // change is due to an user action. If |reason| has CHANGE_REASON_REPLACED
+  // set then the change is caused because the WebState was replaced.
   virtual void WebStateActivatedAt(WebStateList* web_state_list,
                                    web::WebState* old_web_state,
                                    web::WebState* new_web_state,
                                    int active_index,
-                                   bool user_action);
+                                   int reason);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(WebStateListObserver);
diff --git a/ios/chrome/browser/web_state_list/web_state_list_observer.mm b/ios/chrome/browser/web_state_list/web_state_list_observer.mm
index 8f6e6a23..d703654 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_observer.mm
+++ b/ios/chrome/browser/web_state_list/web_state_list_observer.mm
@@ -44,4 +44,4 @@
                                                web::WebState* old_web_state,
                                                web::WebState* new_web_state,
                                                int active_index,
-                                               bool user_action) {}
+                                               int reason) {}
diff --git a/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h b/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h
index 40dad6d..656f363 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h
+++ b/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h
@@ -59,13 +59,14 @@
 
 // Invoked after |newWebState| was activated at the specified index. Both
 // WebState are either valid or null (if there was no selection or there is
-// no selection). If the change is due to an user action, |userAction| will
-// be true.
+// no selection). If |reason| has CHANGE_REASON_USER_ACTION set then the
+// change is due to an user action. If |reason| has CHANGE_REASON_REPLACED
+// set then the change is caused because the WebState was replaced.
 - (void)webStateList:(WebStateList*)webStateList
     didChangeActiveWebState:(web::WebState*)newWebState
                 oldWebState:(web::WebState*)oldWebState
                     atIndex:(int)atIndex
-                 userAction:(BOOL)userAction;
+                     reason:(int)reason;
 
 @end
 
@@ -104,7 +105,7 @@
                            web::WebState* old_web_state,
                            web::WebState* new_web_state,
                            int active_index,
-                           bool user_action) override;
+                           int reason) override;
 
   __weak id<WebStateListObserving> observer_ = nil;
 
diff --git a/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.mm b/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.mm
index 0030957..b4554c7 100644
--- a/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.mm
+++ b/ios/chrome/browser/web_state_list/web_state_list_observer_bridge.mm
@@ -108,9 +108,9 @@
     web::WebState* old_web_state,
     web::WebState* new_web_state,
     int active_index,
-    bool user_action) {
+    int reason) {
   const SEL selector = @selector
-      (webStateList:didChangeActiveWebState:oldWebState:atIndex:userAction:);
+      (webStateList:didChangeActiveWebState:oldWebState:atIndex:reason:);
   if (![observer_ respondsToSelector:selector])
     return;
 
@@ -118,5 +118,5 @@
       didChangeActiveWebState:new_web_state
                   oldWebState:old_web_state
                       atIndex:active_index
-                   userAction:(user_action ? YES : NO)];
+                       reason:reason];
 }
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 5e1fb402..c129c5a 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -546,6 +546,38 @@
   }
 }
 
+if (use_vaapi) {
+  test("jpeg_encode_accelerator_unittest") {
+    deps = [
+      "//base",
+      "//base/test:test_support",
+      "//media:test_support",
+      "//media/gpu",
+      "//media/gpu/ipc/service",
+      "//testing/gtest",
+      "//third_party:jpeg",
+      "//third_party/libyuv",
+      "//ui/base",
+      "//ui/gfx",
+      "//ui/gfx:test_support",
+      "//ui/gfx/geometry",
+      "//ui/gl",
+      "//ui/gl:test_support",
+    ]
+    configs += [ "//third_party/libyuv:libyuv_config" ]
+    sources = [
+      "jpeg_encode_accelerator_unittest.cc",
+      "video_accelerator_unittest_helpers.h",
+    ]
+    if (use_x11) {
+      deps += [ "//ui/gfx/x" ]
+    }
+    if (use_ozone) {
+      deps += [ "//ui/ozone" ]
+    }
+  }
+}
+
 if (use_v4l2_codec || use_vaapi) {
   test("jpeg_decode_accelerator_unittest") {
     deps = [
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 3c7921372..e9ced5c 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -29,7 +29,7 @@
 namespace {
 
 bool MakeContextCurrent(gpu::CommandBufferStub* stub) {
-  return stub && stub->decoder()->MakeCurrent();
+  return stub && stub->decoder_context()->MakeCurrent();
 }
 
 }  // namespace
@@ -133,7 +133,7 @@
   if (!MakeContextCurrent(stub_))
     return nullptr;
   stub_->AddDestructionObserver(this);
-  decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder());
+  decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context());
   return SurfaceTextureGLOwnerImpl::Create();
 }
 
@@ -188,7 +188,7 @@
   if (!MakeContextCurrent(stub_))
     return;
 
-  gpu::gles2::ContextGroup* group = stub_->decoder()->GetContextGroup();
+  gpu::gles2::ContextGroup* group = stub_->decoder_context()->GetContextGroup();
   if (!group)
     return;
   gpu::gles2::TextureManager* texture_manager = group->texture_manager();
diff --git a/media/gpu/gles2_decoder_helper.cc b/media/gpu/gles2_decoder_helper.cc
index 62d061af..10b86f90 100644
--- a/media/gpu/gles2_decoder_helper.cc
+++ b/media/gpu/gles2_decoder_helper.cc
@@ -9,7 +9,7 @@
 #include "base/threading/thread_checker.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "ui/gl/gl_context.h"
@@ -18,7 +18,7 @@
 
 class GLES2DecoderHelperImpl : public GLES2DecoderHelper {
  public:
-  explicit GLES2DecoderHelperImpl(gpu::gles2::GLES2Decoder* decoder)
+  explicit GLES2DecoderHelperImpl(gpu::DecoderContext* decoder)
       : decoder_(decoder) {}
 
   bool MakeContextCurrent() override {
@@ -107,7 +107,7 @@
   }
 
  private:
-  gpu::gles2::GLES2Decoder* decoder_;
+  gpu::DecoderContext* decoder_;
   THREAD_CHECKER(thread_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(GLES2DecoderHelperImpl);
@@ -115,7 +115,7 @@
 
 // static
 std::unique_ptr<GLES2DecoderHelper> GLES2DecoderHelper::Create(
-    gpu::gles2::GLES2Decoder* decoder) {
+    gpu::DecoderContext* decoder) {
   if (!decoder)
     return nullptr;
   return base::MakeUnique<GLES2DecoderHelperImpl>(decoder);
diff --git a/media/gpu/gles2_decoder_helper.h b/media/gpu/gles2_decoder_helper.h
index 60f8dfae..5f6befc 100644
--- a/media/gpu/gles2_decoder_helper.h
+++ b/media/gpu/gles2_decoder_helper.h
@@ -15,21 +15,21 @@
 #include "ui/gl/gl_bindings.h"
 
 namespace gpu {
+class DecoderContext;
 struct Mailbox;
 namespace gles2 {
-class GLES2Decoder;
 class TextureRef;
 }  // namespace gles2
 }  // namespace gpu
 
 namespace media {
 
-// Utility methods to simplify working with a gpu::gles2::GLES2Decoder from
+// Utility methods to simplify working with a gpu::DecoderContext from
 // inside VDAs.
 class MEDIA_GPU_EXPORT GLES2DecoderHelper {
  public:
   static std::unique_ptr<GLES2DecoderHelper> Create(
-      gpu::gles2::GLES2Decoder* decoder);
+      gpu::DecoderContext* decoder);
 
   virtual ~GLES2DecoderHelper() {}
 
diff --git a/media/gpu/ipc/service/gpu_video_decode_accelerator.cc b/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
index 96b8d379..e9a76ce 100644
--- a/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
+++ b/media/gpu/ipc/service/gpu_video_decode_accelerator.cc
@@ -40,7 +40,7 @@
     return nullptr;
   }
 
-  return stub->decoder()->GetGLContext();
+  return stub->decoder_context()->GetGLContext();
 }
 
 static bool MakeDecoderContextCurrent(
@@ -50,7 +50,7 @@
     return false;
   }
 
-  if (!stub->decoder()->MakeCurrent()) {
+  if (!stub->decoder_context()->MakeCurrent()) {
     DLOG(ERROR) << "Failed to MakeCurrent()";
     return false;
   }
@@ -68,7 +68,7 @@
     return false;
   }
 
-  gpu::gles2::GLES2Decoder* command_decoder = stub->decoder();
+  gpu::DecoderContext* command_decoder = stub->decoder_context();
   command_decoder->BindImage(client_texture_id, texture_target, image.get(),
                              can_bind_to_sampler);
   return true;
@@ -77,7 +77,7 @@
 static gpu::gles2::ContextGroup* GetContextGroup(
     const base::WeakPtr<gpu::CommandBufferStub>& stub) {
   if (!stub) {
-    DLOG(ERROR) << "Stub is gone; no GLES2Decoder.";
+    DLOG(ERROR) << "Stub is gone; no DecoderContext.";
     return nullptr;
   }
 
@@ -399,9 +399,9 @@
     return;
   }
 
-  gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder();
+  gpu::DecoderContext* decoder_context = stub_->decoder_context();
   gpu::gles2::TextureManager* texture_manager =
-      command_decoder->GetContextGroup()->texture_manager();
+      stub_->context_group()->texture_manager();
 
   std::vector<PictureBuffer> buffers;
   std::vector<std::vector<scoped_refptr<gpu::gles2::TextureRef>>> textures;
@@ -423,7 +423,7 @@
     }
     for (size_t j = 0; j < textures_per_buffer_; j++) {
       gpu::TextureBase* texture_base =
-          command_decoder->GetTextureBase(buffer_texture_ids[j]);
+          decoder_context->GetTextureBase(buffer_texture_ids[j]);
       if (!texture_base) {
         DLOG(ERROR) << "Failed to find texture id " << buffer_texture_ids[j];
         NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT);
@@ -533,7 +533,7 @@
   for (auto texture_ref : it->second) {
     GLenum target = texture_ref->texture()->target();
     gpu::gles2::TextureManager* texture_manager =
-        stub_->decoder()->GetContextGroup()->texture_manager();
+        stub_->context_group()->texture_manager();
     texture_manager->SetLevelCleared(texture_ref.get(), target, 0, true);
   }
   uncleared_textures_.erase(it);
diff --git a/media/gpu/jpeg_encode_accelerator_unittest.cc b/media/gpu/jpeg_encode_accelerator_unittest.cc
new file mode 100644
index 0000000..1d841f7
--- /dev/null
+++ b/media/gpu/jpeg_encode_accelerator_unittest.cc
@@ -0,0 +1,653 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This has to be included first.
+// See http://code.google.com/p/googletest/issues/detail?id=371
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <memory>
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "media/base/test_data_util.h"
+#include "media/filters/jpeg_parser.h"
+#include "media/gpu/features.h"
+#include "media/gpu/vaapi/vaapi_jpeg_encode_accelerator.h"
+#include "media/gpu/video_accelerator_unittest_helpers.h"
+#include "media/video/jpeg_encode_accelerator.h"
+#include "third_party/libyuv/include/libyuv.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+
+#if BUILDFLAG(USE_VAAPI)
+#include "media/gpu/vaapi/vaapi_wrapper.h"
+#endif
+
+namespace media {
+namespace {
+
+// Default test image file.
+const base::FilePath::CharType kDefaultYuvFilename[] =
+    FILE_PATH_LITERAL("bali_640x360_P420.yuv:640x360");
+// Whether to save encode results to files. Output files will be saved
+// in the same directory with unittest. File name is like input file but
+// changing the extension to "jpg".
+bool g_save_to_file = false;
+
+const double kMeanDiffThreshold = 7.0;
+const int kJpegDefaultQuality = 90;
+
+// Environment to create test data for all test cases.
+class JpegEncodeAcceleratorTestEnvironment;
+JpegEncodeAcceleratorTestEnvironment* g_env;
+
+struct TestImageFile {
+  TestImageFile(const base::FilePath::StringType& filename,
+                gfx::Size visible_size)
+      : filename(filename), visible_size(visible_size) {}
+
+  base::FilePath::StringType filename;
+
+  // The input content of |filename|.
+  std::string data_str;
+
+  gfx::Size visible_size;
+  size_t output_size;
+};
+
+enum class ClientState {
+  CREATED,
+  INITIALIZED,
+  ENCODE_PASS,
+  ERROR,
+};
+
+class JpegClient : public JpegEncodeAccelerator::Client {
+ public:
+  JpegClient(const std::vector<TestImageFile*>& test_image_files,
+             ClientStateNotification<ClientState>* note);
+  ~JpegClient() override;
+  void CreateJpegEncoder();
+  void DestroyJpegEncoder();
+  void StartEncode(int32_t bitstream_buffer_id);
+
+  // JpegEncodeAccelerator::Client implementation.
+  void VideoFrameReady(int video_frame_id,
+                       size_t encoded_picture_size) override;
+  void NotifyError(int video_frame_id,
+                   JpegEncodeAccelerator::Status status) override;
+
+ private:
+  void PrepareMemory(int32_t bitstream_buffer_id);
+  void SetState(ClientState new_state);
+  void SaveToFile(TestImageFile* image_file, size_t hw_size, size_t sw_size);
+  bool CompareHardwareAndSoftwareResults(int width,
+                                         int height,
+                                         size_t hw_encoded_size,
+                                         size_t sw_encoded_size);
+
+  // Calculate mean absolute difference of hardware and software encode results
+  // for verifying the similarity.
+  double GetMeanAbsoluteDifference(uint8_t* hw_yuv_result,
+                                   uint8_t* sw_yuv_result,
+                                   size_t yuv_size);
+
+  // Generate software encode result and populate it into |sw_out_shm_|.
+  bool GetSoftwareEncodeResult(int width,
+                               int height,
+                               size_t* sw_encoded_size,
+                               base::TimeDelta* sw_encode_time);
+
+  // JpegClient doesn't own |test_image_files_|.
+  const std::vector<TestImageFile*>& test_image_files_;
+
+  // A map that stores HW encoding start timestamp for each video frame id.
+  std::map<int, base::TimeTicks> video_frame_id_to_start_time_;
+
+  std::map<int, TestImageFile*> video_frame_id_to_image_;
+
+  std::unique_ptr<JpegEncodeAccelerator> encoder_;
+  ClientState state_;
+
+  // Used to notify another thread about the state. JpegClient does not own
+  // this.
+  ClientStateNotification<ClientState>* note_;
+
+  // Output buffer prepared for JpegEncodeAccelerator.
+  std::unique_ptr<BitstreamBuffer> encoded_buffer_;
+
+  // Mapped memory of input file.
+  std::unique_ptr<base::SharedMemory> in_shm_;
+  // Mapped memory of output buffer from hardware encoder.
+  std::unique_ptr<base::SharedMemory> hw_out_shm_;
+  // Mapped memory of output buffer from software encoder.
+  std::unique_ptr<base::SharedMemory> sw_out_shm_;
+
+  DISALLOW_COPY_AND_ASSIGN(JpegClient);
+};
+
+JpegClient::JpegClient(const std::vector<TestImageFile*>& test_image_files,
+                       ClientStateNotification<ClientState>* note)
+    : test_image_files_(test_image_files),
+      video_frame_id_to_image_(),
+      state_(ClientState::CREATED),
+      note_(note) {}
+
+JpegClient::~JpegClient() {}
+
+void JpegClient::CreateJpegEncoder() {
+  encoder_ = nullptr;
+
+#if BUILDFLAG(USE_VAAPI)
+  encoder_ = base::MakeUnique<VaapiJpegEncodeAccelerator>(
+      base::ThreadTaskRunnerHandle::Get());
+#endif
+
+  if (!encoder_) {
+    LOG(ERROR) << "Failed to create JpegEncodeAccelerator.";
+    SetState(ClientState::ERROR);
+    return;
+  }
+
+  JpegEncodeAccelerator::Status status = encoder_->Initialize(this);
+  if (status != JpegEncodeAccelerator::ENCODE_OK) {
+    LOG(ERROR) << "JpegEncodeAccelerator::Initialize() failed: " << status;
+    SetState(ClientState::ERROR);
+    return;
+  }
+  SetState(ClientState::INITIALIZED);
+}
+
+void JpegClient::DestroyJpegEncoder() {
+  encoder_.reset();
+}
+
+void JpegClient::VideoFrameReady(int video_frame_id, size_t hw_encoded_size) {
+  base::TimeTicks hw_encode_end = base::TimeTicks::Now();
+  base::TimeDelta elapsed_hw =
+      hw_encode_end - video_frame_id_to_start_time_[video_frame_id];
+
+  TestImageFile* test_image = video_frame_id_to_image_[video_frame_id];
+  size_t sw_encoded_size = 0;
+  base::TimeDelta elapsed_sw;
+  LOG_ASSERT(GetSoftwareEncodeResult(test_image->visible_size.width(),
+                                     test_image->visible_size.height(),
+                                     &sw_encoded_size, &elapsed_sw));
+
+  LOG(INFO) << "HW encode elapsed time: " << elapsed_hw.InMicroseconds()
+            << " SW encode elapsed time: " << elapsed_sw.InMicroseconds();
+
+  if (g_save_to_file) {
+    SaveToFile(test_image, hw_encoded_size, sw_encoded_size);
+  }
+
+  if (!CompareHardwareAndSoftwareResults(test_image->visible_size.width(),
+                                         test_image->visible_size.height(),
+                                         hw_encoded_size, sw_encoded_size)) {
+    SetState(ClientState::ERROR);
+  } else {
+    SetState(ClientState::ENCODE_PASS);
+  }
+
+  encoded_buffer_.reset(nullptr);
+}
+
+bool JpegClient::GetSoftwareEncodeResult(int width,
+                                         int height,
+                                         size_t* sw_encoded_size,
+                                         base::TimeDelta* sw_encode_time) {
+  base::TimeTicks sw_encode_start = base::TimeTicks::Now();
+  int y_stride = width;
+  int u_stride = width / 2;
+  int v_stride = u_stride;
+  uint8_t* yuv_src = static_cast<uint8_t*>(in_shm_->memory());
+  const int kBytesPerPixel = 4;
+  std::vector<uint8_t> rgba_buffer(width * height * kBytesPerPixel);
+  std::vector<uint8_t> encoded;
+  libyuv::I420ToABGR(yuv_src, y_stride, yuv_src + y_stride * height, u_stride,
+                     yuv_src + y_stride * height + u_stride * height / 2,
+                     v_stride, rgba_buffer.data(), width * kBytesPerPixel,
+                     width, height);
+
+  SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
+                                       kOpaque_SkAlphaType);
+  SkPixmap src(info, &rgba_buffer[0], width * kBytesPerPixel);
+  if (!gfx::JPEGCodec::Encode(src, kJpegDefaultQuality, &encoded)) {
+    return false;
+  }
+
+  memcpy(sw_out_shm_->memory(), encoded.data(), encoded.size());
+  *sw_encoded_size = encoded.size();
+  *sw_encode_time = base::TimeTicks::Now() - sw_encode_start;
+  return true;
+}
+
+bool JpegClient::CompareHardwareAndSoftwareResults(int width,
+                                                   int height,
+                                                   size_t hw_encoded_size,
+                                                   size_t sw_encoded_size) {
+  size_t yuv_size = width * height * 3 / 2;
+  uint8_t* hw_yuv_result = new uint8_t[yuv_size];
+  int y_stride = width;
+  int u_stride = width / 2;
+  int v_stride = u_stride;
+  if (libyuv::ConvertToI420(
+          static_cast<const uint8*>(hw_out_shm_->memory()), hw_encoded_size,
+          hw_yuv_result, y_stride, hw_yuv_result + y_stride * height, u_stride,
+          hw_yuv_result + y_stride * height + u_stride * height / 2, v_stride,
+          0, 0, width, height, width, height, libyuv::kRotate0,
+          libyuv::FOURCC_MJPG)) {
+    LOG(ERROR) << "Convert HW encoded result to YUV failed";
+  }
+
+  uint8_t* sw_yuv_result = new uint8_t[yuv_size];
+  if (libyuv::ConvertToI420(
+          static_cast<const uint8*>(sw_out_shm_->memory()), sw_encoded_size,
+          sw_yuv_result, y_stride, sw_yuv_result + y_stride * height, u_stride,
+          sw_yuv_result + y_stride * height + u_stride * height / 2, v_stride,
+          0, 0, width, height, width, height, libyuv::kRotate0,
+          libyuv::FOURCC_MJPG)) {
+    LOG(ERROR) << "Convert SW encoded result to YUV failed";
+  }
+
+  double difference =
+      GetMeanAbsoluteDifference(hw_yuv_result, sw_yuv_result, yuv_size);
+  delete[] hw_yuv_result;
+  delete[] sw_yuv_result;
+
+  if (difference > kMeanDiffThreshold) {
+    LOG(ERROR) << "HW and SW encode results are not similar enough. diff = "
+               << difference;
+    return false;
+  } else {
+    return true;
+  }
+}
+
+double JpegClient::GetMeanAbsoluteDifference(uint8_t* hw_yuv_result,
+                                             uint8_t* sw_yuv_result,
+                                             size_t yuv_size) {
+  double total_difference = 0;
+  for (size_t i = 0; i < yuv_size; i++)
+    total_difference += std::abs(hw_yuv_result[i] - sw_yuv_result[i]);
+  return total_difference / yuv_size;
+}
+
+void JpegClient::NotifyError(int video_frame_id,
+                             JpegEncodeAccelerator::Status status) {
+  LOG(ERROR) << "Notifying of error " << status << " for video frame id "
+             << video_frame_id;
+  SetState(ClientState::ERROR);
+  encoded_buffer_.reset(nullptr);
+}
+
+void JpegClient::PrepareMemory(int32_t bitstream_buffer_id) {
+  TestImageFile* image_file = test_image_files_[bitstream_buffer_id];
+
+  size_t input_size = image_file->data_str.size();
+  if (!in_shm_.get() || input_size > in_shm_->mapped_size()) {
+    in_shm_.reset(new base::SharedMemory);
+    LOG_ASSERT(in_shm_->CreateAndMapAnonymous(input_size));
+  }
+  memcpy(in_shm_->memory(), image_file->data_str.data(), input_size);
+
+  if (!hw_out_shm_.get() ||
+      image_file->output_size > hw_out_shm_->mapped_size()) {
+    hw_out_shm_.reset(new base::SharedMemory);
+    LOG_ASSERT(hw_out_shm_->CreateAndMapAnonymous(image_file->output_size));
+  }
+  memset(hw_out_shm_->memory(), 0, image_file->output_size);
+
+  if (!sw_out_shm_.get() ||
+      image_file->output_size > sw_out_shm_->mapped_size()) {
+    sw_out_shm_.reset(new base::SharedMemory);
+    LOG_ASSERT(sw_out_shm_->CreateAndMapAnonymous(image_file->output_size));
+  }
+  memset(sw_out_shm_->memory(), 0, image_file->output_size);
+}
+
+void JpegClient::SetState(ClientState new_state) {
+  DVLOG(2) << "Changing state "
+           << static_cast<std::underlying_type<ClientState>::type>(state_)
+           << "->"
+           << static_cast<std::underlying_type<ClientState>::type>(new_state);
+  note_->Notify(new_state);
+  state_ = new_state;
+}
+
+void JpegClient::SaveToFile(TestImageFile* image_file,
+                            size_t hw_size,
+                            size_t sw_size) {
+  DCHECK_NE(nullptr, image_file);
+
+  base::FilePath in_filename(image_file->filename);
+  base::FilePath out_filename = in_filename.ReplaceExtension(".jpg");
+  ASSERT_EQ(
+      static_cast<int>(hw_size),
+      base::WriteFile(out_filename, static_cast<char*>(hw_out_shm_->memory()),
+                      hw_size));
+
+  ASSERT_EQ(
+      static_cast<int>(sw_size),
+      base::WriteFile(out_filename.InsertBeforeExtension("_sw"),
+                      static_cast<char*>(sw_out_shm_->memory()), sw_size));
+}
+
+void JpegClient::StartEncode(int32_t bitstream_buffer_id) {
+  DCHECK_LT(static_cast<size_t>(bitstream_buffer_id), test_image_files_.size());
+  TestImageFile* image_file = test_image_files_[bitstream_buffer_id];
+
+  image_file->output_size =
+      encoder_->GetMaxCodedBufferSize(image_file->visible_size);
+  PrepareMemory(bitstream_buffer_id);
+
+  base::SharedMemoryHandle dup_handle;
+  dup_handle = base::SharedMemory::DuplicateHandle(hw_out_shm_->handle());
+  encoded_buffer_ = base::MakeUnique<BitstreamBuffer>(
+      bitstream_buffer_id, dup_handle, image_file->output_size);
+  scoped_refptr<VideoFrame> input_frame_ = VideoFrame::WrapExternalSharedMemory(
+      PIXEL_FORMAT_I420, image_file->visible_size,
+      gfx::Rect(image_file->visible_size), image_file->visible_size,
+      static_cast<uint8_t*>(in_shm_->memory()), image_file->data_str.size(),
+      in_shm_->handle(), 0, base::TimeDelta());
+
+  LOG_ASSERT(input_frame_.get());
+
+  video_frame_id_to_image_[input_frame_->unique_id()] = image_file;
+  video_frame_id_to_start_time_[input_frame_->unique_id()] =
+      base::TimeTicks::Now();
+  encoder_->Encode(input_frame_, kJpegDefaultQuality, *encoded_buffer_);
+}
+
+class JpegEncodeAcceleratorTestEnvironment : public ::testing::Environment {
+ public:
+  JpegEncodeAcceleratorTestEnvironment(
+      const base::FilePath::CharType* yuv_filenames) {
+    user_yuv_files_ = yuv_filenames ? yuv_filenames : kDefaultYuvFilename;
+  }
+  void SetUp() override;
+  void TearDown() override;
+
+  // Read image from |filename| to |image_data|.
+  void ReadTestYuvImage(base::FilePath& filename, TestImageFile* image_data);
+
+  // Returns a file path for a file in what name specified or media/test/data
+  // directory.  If the original file path is existed, returns it first.
+  base::FilePath GetOriginalOrTestDataFilePath(const std::string& name);
+
+  // Parsed data from command line.
+  std::vector<std::unique_ptr<TestImageFile>> image_data_user_;
+
+  // Parsed data of |test_1280x720_yuv_file_|.
+  std::unique_ptr<TestImageFile> image_data_1280x720_white_;
+  // Parsed data of |test_640x368_yuv_file_|.
+  std::unique_ptr<TestImageFile> image_data_640x368_black_;
+  // Parsed data of |test_640x360_yuv_file_|.
+  std::unique_ptr<TestImageFile> image_data_640x360_black_;
+
+ private:
+  // Create black or white test image with |width| and |height| size.
+  void CreateTestYuvImage(int width,
+                          int height,
+                          bool is_black,
+                          base::FilePath* filename);
+
+  const base::FilePath::CharType* user_yuv_files_;
+
+  // Programatically generated YUV files.
+  base::FilePath test_1280x720_yuv_file_;
+  base::FilePath test_640x368_yuv_file_;
+  base::FilePath test_640x360_yuv_file_;
+};
+
+void JpegEncodeAcceleratorTestEnvironment::SetUp() {
+  CreateTestYuvImage(1280, 720, false, &test_1280x720_yuv_file_);
+  CreateTestYuvImage(640, 368, true, &test_640x368_yuv_file_);
+  CreateTestYuvImage(640, 360, true, &test_640x360_yuv_file_);
+
+  image_data_1280x720_white_.reset(
+      new TestImageFile(test_1280x720_yuv_file_.value(), gfx::Size(1280, 720)));
+  ASSERT_NO_FATAL_FAILURE(ReadTestYuvImage(test_1280x720_yuv_file_,
+                                           image_data_1280x720_white_.get()));
+
+  image_data_640x368_black_.reset(
+      new TestImageFile(test_640x368_yuv_file_.value(), gfx::Size(640, 368)));
+  ASSERT_NO_FATAL_FAILURE(ReadTestYuvImage(test_640x368_yuv_file_,
+                                           image_data_640x368_black_.get()));
+
+  image_data_640x360_black_.reset(
+      new TestImageFile(test_640x360_yuv_file_.value(), gfx::Size(640, 360)));
+  ASSERT_NO_FATAL_FAILURE(ReadTestYuvImage(test_640x360_yuv_file_,
+                                           image_data_640x360_black_.get()));
+
+  // |user_yuv_files_| may include many files and use ';' as delimiter.
+  std::vector<base::FilePath::StringType> files =
+      base::SplitString(user_yuv_files_, base::FilePath::StringType(1, ';'),
+                        base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  for (const auto& file : files) {
+    std::vector<base::FilePath::StringType> filename_and_size =
+        base::SplitString(file, base::FilePath::StringType(1, ':'),
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    ASSERT_EQ(2u, filename_and_size.size());
+    base::FilePath::StringType filename(filename_and_size[0]);
+
+    std::vector<base::FilePath::StringType> image_resolution =
+        base::SplitString(filename_and_size[1],
+                          base::FilePath::StringType(1, 'x'),
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    ASSERT_EQ(2u, image_resolution.size());
+    int width = 0, height = 0;
+    ASSERT_TRUE(base::StringToInt(image_resolution[0], &width));
+    ASSERT_TRUE(base::StringToInt(image_resolution[1], &height));
+
+    gfx::Size image_size(width, height);
+    ASSERT_TRUE(!image_size.IsEmpty());
+
+    base::FilePath input_file = GetOriginalOrTestDataFilePath(filename);
+    auto image_data = base::MakeUnique<TestImageFile>(filename, image_size);
+    ASSERT_NO_FATAL_FAILURE(ReadTestYuvImage(input_file, image_data.get()));
+    image_data_user_.push_back(std::move(image_data));
+  }
+}
+
+void JpegEncodeAcceleratorTestEnvironment::TearDown() {
+  base::DeleteFile(test_1280x720_yuv_file_, false);
+  base::DeleteFile(test_640x368_yuv_file_, false);
+  base::DeleteFile(test_640x360_yuv_file_, false);
+}
+
+void JpegEncodeAcceleratorTestEnvironment::CreateTestYuvImage(
+    int width,
+    int height,
+    bool is_black,
+    base::FilePath* filename) {
+  std::vector<uint8_t> buffer(width * height * 3 / 2);
+
+  size_t size = width * height;
+  // Fill in Y values.
+  memset(buffer.data(), is_black ? 0 : 255, size);
+  // FIll in U and V values.
+  memset(buffer.data() + size, 128, size / 2);
+  LOG_ASSERT(base::CreateTemporaryFile(filename));
+  EXPECT_TRUE(base::AppendToFile(
+      *filename, reinterpret_cast<char*>(buffer.data()), buffer.size()));
+}
+
+void JpegEncodeAcceleratorTestEnvironment::ReadTestYuvImage(
+    base::FilePath& input_file,
+    TestImageFile* image_data) {
+  ASSERT_TRUE(base::ReadFileToString(input_file, &image_data->data_str));
+
+  // This is just a placeholder. We will compute the real output size when we
+  // have encoder instance.
+  image_data->output_size =
+      VideoFrame::AllocationSize(PIXEL_FORMAT_I420, image_data->visible_size);
+}
+
+base::FilePath
+JpegEncodeAcceleratorTestEnvironment::GetOriginalOrTestDataFilePath(
+    const std::string& name) {
+  base::FilePath original_file_path = base::FilePath(name);
+  base::FilePath return_file_path = GetTestDataFilePath(name);
+
+  if (PathExists(original_file_path))
+    return_file_path = original_file_path;
+
+  VLOG(3) << "Use file path " << return_file_path.value();
+  return return_file_path;
+}
+
+class JpegEncodeAcceleratorTest : public ::testing::Test {
+ protected:
+  JpegEncodeAcceleratorTest() {}
+
+  void TestEncode(size_t num_concurrent_encoders);
+
+  // This is needed to allow the usage of methods in post_task.h in
+  // JpegEncodeAccelerator implementations.
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+  // The elements of |test_image_files_| are owned by
+  // JpegEncodeAcceleratorTestEnvironment.
+  std::vector<TestImageFile*> test_image_files_;
+  std::vector<ClientState> expected_status_;
+
+ protected:
+  DISALLOW_COPY_AND_ASSIGN(JpegEncodeAcceleratorTest);
+};
+
+void JpegEncodeAcceleratorTest::TestEncode(size_t num_concurrent_encoders) {
+  LOG_ASSERT(test_image_files_.size() >= expected_status_.size());
+  base::Thread encoder_thread("EncoderThread");
+  ASSERT_TRUE(encoder_thread.Start());
+
+  std::vector<std::unique_ptr<ClientStateNotification<ClientState>>> notes;
+  std::vector<std::unique_ptr<JpegClient>> clients;
+
+  for (size_t i = 0; i < num_concurrent_encoders; i++) {
+    notes.push_back(base::MakeUnique<ClientStateNotification<ClientState>>());
+    clients.push_back(
+        base::MakeUnique<JpegClient>(test_image_files_, notes.back().get()));
+    encoder_thread.task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&JpegClient::CreateJpegEncoder,
+                                  base::Unretained(clients.back().get())));
+    ASSERT_EQ(notes[i]->Wait(), ClientState::INITIALIZED);
+  }
+
+  for (size_t index = 0; index < test_image_files_.size(); index++) {
+    for (size_t i = 0; i < num_concurrent_encoders; i++) {
+      encoder_thread.task_runner()->PostTask(
+          FROM_HERE, base::BindOnce(&JpegClient::StartEncode,
+                                    base::Unretained(clients[i].get()), index));
+    }
+    if (index < expected_status_.size()) {
+      for (size_t i = 0; i < num_concurrent_encoders; i++) {
+        ASSERT_EQ(notes[i]->Wait(), expected_status_[index]);
+      }
+    }
+  }
+
+  for (size_t i = 0; i < num_concurrent_encoders; i++) {
+    encoder_thread.task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&JpegClient::DestroyJpegEncoder,
+                                  base::Unretained(clients[i].get())));
+  }
+  encoder_thread.Stop();
+}
+
+TEST_F(JpegEncodeAcceleratorTest, SimpleEncode) {
+  for (auto& image : g_env->image_data_user_) {
+    test_image_files_.push_back(image.get());
+    expected_status_.push_back(ClientState::ENCODE_PASS);
+  }
+  TestEncode(1);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, MultipleEncoders) {
+  for (auto& image : g_env->image_data_user_) {
+    test_image_files_.push_back(image.get());
+    expected_status_.push_back(ClientState::ENCODE_PASS);
+  }
+  TestEncode(3);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, ResolutionChange) {
+  test_image_files_.push_back(g_env->image_data_640x368_black_.get());
+  test_image_files_.push_back(g_env->image_data_1280x720_white_.get());
+  test_image_files_.push_back(g_env->image_data_640x368_black_.get());
+  for (size_t i = 0; i < test_image_files_.size(); i++)
+    expected_status_.push_back(ClientState::ENCODE_PASS);
+  TestEncode(1);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignment) {
+  test_image_files_.push_back(g_env->image_data_640x360_black_.get());
+  expected_status_.push_back(ClientState::ENCODE_PASS);
+  TestEncode(1);
+}
+
+}  // namespace
+}  // namespace media
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  base::CommandLine::Init(argc, argv);
+  base::ShadowingAtExitManager at_exit_manager;
+
+  // Needed to enable DVLOG through --vmodule.
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  LOG_ASSERT(logging::InitLogging(settings));
+
+  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  DCHECK(cmd_line);
+
+  const base::FilePath::CharType* yuv_filenames = nullptr;
+  base::CommandLine::SwitchMap switches = cmd_line->GetSwitches();
+  for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
+       it != switches.end(); ++it) {
+    // yuv_filenames can include one or many files and use ';' as delimiter.
+    // For each file, it should follow the format "[filename]:[width]x[height]".
+    // For example, "lake.yuv:4160x3120".
+    if (it->first == "yuv_filenames") {
+      yuv_filenames = it->second.c_str();
+      continue;
+    }
+    if (it->first == "save_to_file") {
+      media::g_save_to_file = true;
+      continue;
+    }
+    if (it->first == "v" || it->first == "vmodule")
+      continue;
+    if (it->first == "h" || it->first == "help")
+      continue;
+    LOG(ERROR) << "Unexpected switch: " << it->first << ":" << it->second;
+    return -EINVAL;
+  }
+#if BUILDFLAG(USE_VAAPI)
+  media::VaapiWrapper::PreSandboxInitialization();
+#endif
+
+  media::g_env = reinterpret_cast<media::JpegEncodeAcceleratorTestEnvironment*>(
+      testing::AddGlobalTestEnvironment(
+          new media::JpegEncodeAcceleratorTestEnvironment(yuv_filenames)));
+
+  return RUN_ALL_TESTS();
+}
diff --git a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
index 6c28b5a..220620d 100644
--- a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
@@ -20,6 +20,9 @@
 #include "media/base/video_frame.h"
 #include "media/gpu/vaapi/vaapi_jpeg_encoder.h"
 
+#define VLOGF(level) VLOG(level) << __func__ << "(): "
+#define DVLOGF(level) DVLOG(level) << __func__ << "(): "
+
 namespace media {
 
 namespace {
@@ -96,6 +99,7 @@
 
 void VaapiJpegEncodeAccelerator::Encoder::EncodeTask(
     std::unique_ptr<EncodeRequest> request) {
+  DVLOGF(4);
   TRACE_EVENT0("jpeg", "EncodeTask");
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -104,7 +108,7 @@
   std::vector<VASurfaceID> va_surfaces;
   if (!vaapi_wrapper_->CreateSurfaces(VA_RT_FORMAT_YUV420, input_size, 1,
                                       &va_surfaces)) {
-    VLOG(1) << "Failed to create VA surface";
+    VLOGF(1) << "Failed to create VA surface";
     notify_error_cb_.Run(video_frame_id, PLATFORM_FAILURE);
     return;
   }
@@ -112,7 +116,7 @@
 
   if (!vaapi_wrapper_->UploadVideoFrameToSurface(request->video_frame,
                                                  va_surface_id)) {
-    VLOG(1) << "Failed to upload video frame to VA surface";
+    VLOGF(1) << "Failed to upload video frame to VA surface";
     notify_error_cb_.Run(video_frame_id, PLATFORM_FAILURE);
     return;
   }
@@ -127,7 +131,7 @@
     VABufferID output_buffer_id;
     if (!vaapi_wrapper_->CreateCodedBuffer(max_coded_buffer_size,
                                            &output_buffer_id)) {
-      VLOG(1) << "Failed to create VA buffer for encoding output";
+      VLOGF(1) << "Failed to create VA buffer for encoding output";
       notify_error_cb_.Run(video_frame_id, PLATFORM_FAILURE);
       return;
     }
@@ -137,7 +141,7 @@
 
   if (!jpeg_encoder_->Encode(input_size, request->quality, va_surface_id,
                              cached_output_buffer_id_)) {
-    VLOG(1) << "Encode JPEG failed";
+    VLOGF(1) << "Encode JPEG failed";
     notify_error_cb_.Run(video_frame_id, PLATFORM_FAILURE);
     return;
   }
@@ -149,7 +153,7 @@
           cached_output_buffer_id_, va_surface_id,
           static_cast<uint8_t*>(request->shm->memory()), request->shm->size(),
           &encoded_size)) {
-    VLOG(1) << "Failed to retrieve output image from VA coded buffer";
+    VLOGF(1) << "Failed to retrieve output image from VA coded buffer";
     notify_error_cb_.Run(video_frame_id, PLATFORM_FAILURE);
   }
 
@@ -161,12 +165,13 @@
     : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       io_task_runner_(std::move(io_task_runner)),
       weak_this_factory_(this) {
+  VLOGF(2);
   weak_this_ = weak_this_factory_.GetWeakPtr();
 }
 
 VaapiJpegEncodeAccelerator::~VaapiJpegEncodeAccelerator() {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DVLOG(1) << "Destroying VaapiJpegEncodeAccelerator";
+  VLOGF(2) << "Destroying VaapiJpegEncodeAccelerator";
 
   weak_this_factory_.InvalidateWeakPtrs();
   encoder_task_runner_->DeleteSoon(FROM_HERE, std::move(encoder_));
@@ -175,13 +180,15 @@
 void VaapiJpegEncodeAccelerator::NotifyError(int video_frame_id,
                                              Status status) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DLOG(ERROR) << "Notifying error: " << status;
+  VLOGF(1) << "video_frame_id=" << video_frame_id << ", status=" << status;
   DCHECK(client_);
   client_->NotifyError(video_frame_id, status);
 }
 
 void VaapiJpegEncodeAccelerator::VideoFrameReady(int video_frame_id,
                                                  size_t encoded_picture_size) {
+  DVLOGF(4) << "video_frame_id=" << video_frame_id
+            << ", size=" << encoded_picture_size;
   DCHECK(task_runner_->BelongsToCurrentThread());
   ReportToUMA(VAJEAEncoderResult::VAAPI_SUCCESS);
 
@@ -190,9 +197,11 @@
 
 JpegEncodeAccelerator::Status VaapiJpegEncodeAccelerator::Initialize(
     JpegEncodeAccelerator::Client* client) {
+  VLOGF(2);
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   if (!VaapiWrapper::IsJpegEncodeSupported()) {
+    VLOGF(1) << "Jpeg encoder is not supported.";
     return HW_JPEG_ENCODE_NOT_SUPPORTED;
   }
 
@@ -202,14 +211,14 @@
       base::Bind(&ReportToUMA, VAJEAEncoderResult::VAAPI_ERROR));
 
   if (!vaapi_wrapper) {
-    VLOG(1) << "Failed initializing VAAPI";
+    VLOGF(1) << "Failed initializing VAAPI";
     return PLATFORM_FAILURE;
   }
 
   encoder_task_runner_ = base::CreateSingleThreadTaskRunnerWithTraits(
       {base::MayBlock(), base::TaskPriority::USER_BLOCKING});
   if (!encoder_task_runner_) {
-    VLOG(1) << "Failed to create encoder task runner.";
+    VLOGF(1) << "Failed to create encoder task runner.";
     return THREAD_CREATION_FAILED;
   }
 
@@ -232,6 +241,7 @@
     scoped_refptr<media::VideoFrame> video_frame,
     int quality,
     const BitstreamBuffer& bitstream_buffer) {
+  DVLOGF(4);
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
   int video_frame_id = video_frame->unique_id();
@@ -239,7 +249,7 @@
 
   // TODO(shenghao): support other YUV formats.
   if (video_frame->format() != VideoPixelFormat::PIXEL_FORMAT_I420) {
-    VLOG(1) << "Unsupported input format: " << video_frame->format();
+    VLOGF(1) << "Unsupported input format: " << video_frame->format();
     task_runner_->PostTask(
         FROM_HERE, base::Bind(&VaapiJpegEncodeAccelerator::NotifyError,
                               weak_this_, video_frame_id, INVALID_ARGUMENT));
@@ -249,7 +259,7 @@
   // SharedMemoryRegion will take ownership of the |bitstream_buffer.handle()|.
   auto shm = std::make_unique<SharedMemoryRegion>(bitstream_buffer, false);
   if (!shm->Map()) {
-    VLOG(1) << "Failed to map output buffer";
+    VLOGF(1) << "Failed to map output buffer";
     task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&VaapiJpegEncodeAccelerator::NotifyError, weak_this_,
diff --git a/media/midi/midi_manager.cc b/media/midi/midi_manager.cc
index b3899e3..b8a67622 100644
--- a/media/midi/midi_manager.cc
+++ b/media/midi/midi_manager.cc
@@ -84,26 +84,30 @@
 #endif
 
 void MidiManager::Shutdown() {
+  Finalize();
+
+  base::AutoLock auto_lock(lock_);
+  if (session_thread_runner_)
+    DCHECK(session_thread_runner_->BelongsToCurrentThread());
+
+  finalized_ = true;
+
   UMA_HISTOGRAM_ENUMERATION("Media.Midi.ResultOnShutdown", result_,
                             static_cast<Sample>(Result::MAX) + 1);
-  bool shutdown_synchronously = false;
-  {
-    base::AutoLock auto_lock(lock_);
-    if (session_thread_runner_) {
-      if (session_thread_runner_->BelongsToCurrentThread()) {
-        shutdown_synchronously = true;
-      } else {
-        session_thread_runner_->PostTask(
-            FROM_HERE, base::BindOnce(&MidiManager::ShutdownOnSessionThread,
-                                      base::Unretained(this)));
-      }
-      session_thread_runner_ = nullptr;
-    } else {
-      finalized_ = true;
-    }
-  }
-  if (shutdown_synchronously)
-    ShutdownOnSessionThread();
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "Media.Midi.SendReceiveUsage",
+      data_sent_ ? (data_received_ ? SendReceiveUsage::SENT_AND_RECEIVED
+                                   : SendReceiveUsage::SENT)
+                 : (data_received_ ? SendReceiveUsage::RECEIVED
+                                   : SendReceiveUsage::NO_USE),
+      static_cast<Sample>(SendReceiveUsage::MAX) + 1);
+
+  // Detach all clients so that they do not call MidiManager methods any more.
+  for (auto* client : clients_)
+    client->Detach();
+
+  session_thread_runner_ = nullptr;
 }
 
 void MidiManager::StartSession(MidiManagerClient* client) {
@@ -113,6 +117,8 @@
 
   {
     base::AutoLock auto_lock(lock_);
+    DCHECK(!finalized_);
+
     if (clients_.find(client) != clients_.end() ||
         pending_clients_.find(client) != pending_clients_.end()) {
       // Should not happen. But just in case the renderer is compromised.
@@ -120,12 +126,6 @@
       return;
     }
 
-    // Do not accept a new request if Shutdown() was already called.
-    if (finalized_) {
-      client->CompleteStartSession(Result::INITIALIZATION_ERROR);
-      return;
-    }
-
     if (initialization_state_ == InitializationState::COMPLETED) {
       // Platform dependent initialization was already finished for previously
       // initialized clients.
@@ -219,13 +219,13 @@
       } else {
         session_thread_runner_->PostTask(
             FROM_HERE,
-            base::BindOnce(&MidiManager::CompleteInitializationInternal,
+            base::BindOnce(&MidiManager::CompleteInitializationOnSessionThread,
                            base::Unretained(this), result));
       }
     }
   }
   if (complete_asynchronously)
-    CompleteInitializationInternal(result);
+    CompleteInitializationOnSessionThread(result);
 }
 
 void MidiManager::AddInputPort(const MidiPortInfo& info) {
@@ -271,15 +271,16 @@
     client->ReceiveMidiData(port_index, data, length, timestamp);
 }
 
-void MidiManager::CompleteInitializationInternal(Result result) {
+void MidiManager::CompleteInitializationOnSessionThread(Result result) {
   TRACE_EVENT0("midi", "MidiManager::CompleteInitialization");
   ReportUsage(Usage::INITIALIZED);
+
+  base::AutoLock auto_lock(lock_);
   UMA_HISTOGRAM_ENUMERATION("Media.Midi.InputPorts", input_ports_.size(),
                             kMaxUmaDevices + 1);
   UMA_HISTOGRAM_ENUMERATION("Media.Midi.OutputPorts", output_ports_.size(),
                             kMaxUmaDevices + 1);
 
-  base::AutoLock auto_lock(lock_);
   DCHECK(clients_.empty());
   DCHECK_EQ(initialization_state_, InitializationState::STARTED);
   initialization_state_ = InitializationState::COMPLETED;
@@ -304,22 +305,4 @@
     client->AddOutputPort(info);
 }
 
-void MidiManager::ShutdownOnSessionThread() {
-  Finalize();
-  base::AutoLock auto_lock(lock_);
-  finalized_ = true;
-
-  // Detach all clients so that they do not call MidiManager methods any more.
-  for (auto* client : clients_)
-    client->Detach();
-
-  UMA_HISTOGRAM_ENUMERATION(
-      "Media.Midi.SendReceiveUsage",
-      data_sent_ ? (data_received_ ? SendReceiveUsage::SENT_AND_RECEIVED
-                                   : SendReceiveUsage::SENT)
-                 : (data_received_ ? SendReceiveUsage::RECEIVED
-                                   : SendReceiveUsage::NO_USE),
-      static_cast<Sample>(SendReceiveUsage::MAX) + 1);
-}
-
 }  // namespace midi
diff --git a/media/midi/midi_manager.h b/media/midi/midi_manager.h
index 694d64c..d72e939 100644
--- a/media/midi/midi_manager.h
+++ b/media/midi/midi_manager.h
@@ -74,9 +74,12 @@
   virtual void Detach() = 0;
 };
 
-// Manages access to all MIDI hardware.
-// *** Note ***: If dynamic instantiation feature is enabled, all MidiManager
-// methods will be called on Chrome_IOThread. See comments on Shutdown() too.
+// Manages access to all MIDI hardware. MidiManager runs on the I/O thread.
+//
+// Note: We will eventually remove utility functions that are shared among
+// platform dependent MidiManager inheritances such as MidiManagerClient
+// management. MidiService should provide such shareable utility functions as
+// it does TaskService.
 class MIDI_EXPORT MidiManager {
  public:
   static const size_t kMaxPendingClientCount = 128;
@@ -84,15 +87,10 @@
   explicit MidiManager(MidiService* service);
   virtual ~MidiManager();
 
-  // The constructor and the destructor will be called on the CrBrowserMain
-  // thread.
   static MidiManager* Create(MidiService* service);
 
-  // Called on the CrBrowserMain thread to notify the Chrome_IOThread will stop
-  // and the instance will be destructed on the CrBrowserMain thread soon.
-  // *** Note ***: If dynamic instantiation feature is enabled, MidiService
-  // calls this on Chrome_IOThread and ShutdownOnSessionThread() will be called
-  // synchronously so that MidiService can destruct MidiManager synchronously.
+  // Shuts down this manager. This function is split from the destructor
+  // because it calls a virtual function.
   void Shutdown();
 
   // A client calls StartSession() to receive and send MIDI data.
@@ -101,8 +99,6 @@
   // CompleteStartSession() is called with mojom::Result::OK if the session is
   // started. Otherwise CompleteStartSession() is called with a proper
   // mojom::Result code.
-  // StartSession() and EndSession() can be called on the Chrome_IOThread.
-  // CompleteStartSession() will be invoked on the same Chrome_IOThread.
   void StartSession(MidiManagerClient* client);
 
   // A client calls EndSession() to stop receiving MIDI data.
@@ -135,9 +131,8 @@
 
   // Initializes the platform dependent MIDI system. MidiManager class has a
   // default implementation that synchronously calls CompleteInitialization()
-  // with mojom::Result::NOT_SUPPORTED on the caller thread. A derived class for
-  // a specific platform should override this method correctly.
-  // This method is called on Chrome_IOThread thread inside StartSession().
+  // with mojom::Result::NOT_SUPPORTED. A derived class for a specific platform
+  // should override this method correctly.
   // Platform dependent initialization can be processed synchronously or
   // asynchronously. When the initialization is completed,
   // CompleteInitialization() should be called with |result|.
@@ -145,18 +140,18 @@
   // mojom::Result.
   virtual void StartInitialization();
 
-  // Finalizes the platform dependent MIDI system. Called on Chrome_IOThread
-  // thread and the thread will stop immediately after this call.
-  // Platform dependent resources that were allocated on the Chrome_IOThread
-  // should be disposed inside this method.
+  // Finalizes the platform dependent MIDI system. After this method call,
+  // destructor will be called immediately and the I/O thread may stop.
   virtual void Finalize() {}
 
   // Called from a platform dependent implementation of StartInitialization().
-  // It invokes CompleteInitializationInternal() on the thread that calls
+  // The method can be called on any thread, and it invokes
+  // CompleteInitializationOnSessionThread() on the thread that ran
   // StartSession() and distributes |result| to MIDIManagerClient objects in
   // |pending_clients_|.
   void CompleteInitialization(mojom::Result result);
 
+  // The following methods can be called on any thread.
   void AddInputPort(const MidiPortInfo& info);
   void AddOutputPort(const MidiPortInfo& info);
   void SetInputPortState(uint32_t port_index, mojom::PortState state);
@@ -194,16 +189,14 @@
     COMPLETED,
   };
 
-  void CompleteInitializationInternal(mojom::Result result);
+  void CompleteInitializationOnSessionThread(mojom::Result result);
   void AddInitialPorts(MidiManagerClient* client);
-  void ShutdownOnSessionThread();
 
   // Keeps track of all clients who wish to receive MIDI data.
-  typedef std::set<MidiManagerClient*> ClientSet;
-  ClientSet clients_;
+  std::set<MidiManagerClient*> clients_;
 
   // Keeps track of all clients who are waiting for CompleteStartSession().
-  ClientSet pending_clients_;
+  std::set<MidiManagerClient*> pending_clients_;
 
   // Keeps a SingleThreadTaskRunner of the thread that calls StartSession in
   // order to invoke CompleteStartSession() on the thread.
@@ -227,9 +220,7 @@
   bool data_sent_;
   bool data_received_;
 
-  // Protects access to |clients_|, |pending_clients_|,
-  // |session_thread_runner_|, |initialization_state_|, |finalize_|, |result_|,
-  // |input_ports_|, |output_ports_|, |data_sent_| and |data_received_|.
+  // Protects members above.
   base::Lock lock_;
 
   // MidiService outlives MidiManager.
diff --git a/media/midi/midi_manager_unittest.cc b/media/midi/midi_manager_unittest.cc
index ee01bcf..aa29661 100644
--- a/media/midi/midi_manager_unittest.cc
+++ b/media/midi/midi_manager_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/system_monitor/system_monitor.h"
@@ -30,18 +31,24 @@
 class FakeMidiManager : public MidiManager {
  public:
   explicit FakeMidiManager(MidiService* service)
-      : MidiManager(service),
-        start_initialization_is_called_(false),
-        finalize_is_called_(false) {}
-  ~FakeMidiManager() override = default;
+      : MidiManager(service), weak_factory_(this) {}
+
+  ~FakeMidiManager() override { DCHECK_EQ(initialized_, finalized_); }
+
+  base::WeakPtr<FakeMidiManager> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
 
   // MidiManager implementation.
   void StartInitialization() override {
-    start_initialization_is_called_ = true;
+    DCHECK(!initialized_);
+    initialized_ = true;
   }
-
-  void Finalize() override { finalize_is_called_ = true; }
-
+  void Finalize() override {
+    DCHECK(initialized_);
+    DCHECK(!finalized_);
+    finalized_ = true;
+  }
   void DispatchSendMidiData(MidiManagerClient* client,
                             uint32_t port_index,
                             const std::vector<uint8_t>& data,
@@ -60,40 +67,55 @@
     return pending_clients_size_for_testing();
   }
 
-  bool start_initialization_is_called_;
-  bool finalize_is_called_;
+  bool IsInitialized() const { return initialized_; }
 
  private:
+  bool initialized_ = false;
+  bool finalized_ = false;
+
+  base::WeakPtrFactory<FakeMidiManager> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(FakeMidiManager);
 };
 
 class FakeMidiManagerFactory : public MidiService::ManagerFactory {
  public:
-  FakeMidiManagerFactory() = default;
+  FakeMidiManagerFactory() : weak_factory_(this) {}
   ~FakeMidiManagerFactory() override = default;
+
   std::unique_ptr<MidiManager> Create(MidiService* service) override {
     std::unique_ptr<FakeMidiManager> manager =
         std::make_unique<FakeMidiManager>(service);
-    // |manaegr| will be owned by the caller MidiService instance, and valid
-    // while the MidiService instance is running.
-    // MidiService::Shutdown() or destructor will destruct it, and |manager_|
-    // get to be invalid after that.
-    manager_ = manager.get();
+    manager_ = manager->GetWeakPtr();
     return manager;
   }
-  FakeMidiManager* GetCreatedManager() {
-    DCHECK(manager_);
+
+  base::WeakPtr<FakeMidiManagerFactory> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  base::WeakPtr<FakeMidiManager> manager() {
+#if defined(OS_MACOSX)
+    // To avoid Core MIDI issues, MidiManager won't be destructed on macOS.
+    // See https://crbug.com/718140.
+    if (!manager_ ||
+        (!manager_->GetClientCount() && !manager_->GetPendingClientCount())) {
+      return nullptr;
+    }
+#endif
     return manager_;
   }
 
  private:
-  FakeMidiManager* manager_ = nullptr;
+  base::WeakPtr<FakeMidiManager> manager_ = nullptr;
+  base::WeakPtrFactory<FakeMidiManagerFactory> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerFactory);
 };
 
 class FakeMidiManagerClient : public MidiManagerClient {
  public:
-  FakeMidiManagerClient()
-      : result_(Result::NOT_SUPPORTED), wait_for_result_(true) {}
+  FakeMidiManagerClient() = default;
   ~FakeMidiManagerClient() override = default;
 
   // MidiManagerClient implementation.
@@ -101,13 +123,11 @@
   void AddOutputPort(const MidiPortInfo& info) override {}
   void SetInputPortState(uint32_t port_index, PortState state) override {}
   void SetOutputPortState(uint32_t port_index, PortState state) override {}
-
   void CompleteStartSession(Result result) override {
     EXPECT_TRUE(wait_for_result_);
     result_ = result;
     wait_for_result_ = false;
   }
-
   void ReceiveMidiData(uint32_t port_index,
                        const uint8_t* data,
                        size_t size,
@@ -126,8 +146,8 @@
   }
 
  private:
-  Result result_;
-  bool wait_for_result_;
+  Result result_ = Result::NOT_SUPPORTED;
+  bool wait_for_result_ = true;
 
   DISALLOW_COPY_AND_ASSIGN(FakeMidiManagerClient);
 };
@@ -137,53 +157,66 @@
   MidiManagerTest() : message_loop_(std::make_unique<base::MessageLoop>()) {
     std::unique_ptr<FakeMidiManagerFactory> factory =
         std::make_unique<FakeMidiManagerFactory>();
-    factory_ = factory.get();
+    factory_ = factory->GetWeakPtr();
     service_ = std::make_unique<MidiService>(std::move(factory));
-    manager_ = factory_->GetCreatedManager();
   }
+
   ~MidiManagerTest() override {
-    manager_->Shutdown();
+    service_->Shutdown();
     base::RunLoop run_loop;
     run_loop.RunUntilIdle();
-    EXPECT_EQ(manager_->start_initialization_is_called_,
-              manager_->finalize_is_called_);
   }
 
  protected:
   void StartTheFirstSession(FakeMidiManagerClient* client) {
-    EXPECT_FALSE(manager_->start_initialization_is_called_);
-    EXPECT_EQ(0U, manager_->GetClientCount());
-    EXPECT_EQ(0U, manager_->GetPendingClientCount());
-    manager_->StartSession(client);
-    EXPECT_EQ(0U, manager_->GetClientCount());
-    EXPECT_EQ(1U, manager_->GetPendingClientCount());
-    EXPECT_TRUE(manager_->start_initialization_is_called_);
-    EXPECT_EQ(0U, manager_->GetClientCount());
-    EXPECT_EQ(1U, manager_->GetPendingClientCount());
-    EXPECT_TRUE(manager_->start_initialization_is_called_);
+    DCHECK(factory_);
+
+    EXPECT_FALSE(factory_->manager());
+    service_->StartSession(client);
+    ASSERT_TRUE(factory_->manager());
+    EXPECT_TRUE(factory_->manager()->IsInitialized());
+    EXPECT_EQ(0U, factory_->manager()->GetClientCount());
+    EXPECT_EQ(1U, factory_->manager()->GetPendingClientCount());
   }
 
   void StartTheNthSession(FakeMidiManagerClient* client, size_t nth) {
-    EXPECT_EQ(nth != 1, manager_->start_initialization_is_called_);
-    EXPECT_EQ(0U, manager_->GetClientCount());
-    EXPECT_EQ(nth - 1, manager_->GetPendingClientCount());
+    DCHECK(factory_);
+    DCHECK_NE(1U, nth);
 
-    // StartInitialization() should not be called for the second and later
-    // sessions.
-    manager_->start_initialization_is_called_ = false;
-    manager_->StartSession(client);
-    EXPECT_EQ(nth == 1, manager_->start_initialization_is_called_);
-    manager_->start_initialization_is_called_ = true;
+    ASSERT_TRUE(factory_->manager());
+    EXPECT_TRUE(factory_->manager()->IsInitialized());
+    EXPECT_EQ(0U, factory_->manager()->GetClientCount());
+    EXPECT_EQ(nth - 1U, factory_->manager()->GetPendingClientCount());
+    service_->StartSession(client);
+    EXPECT_EQ(nth, factory_->manager()->GetPendingClientCount());
+  }
+
+  void StartSession(FakeMidiManagerClient* client) {
+    service_->StartSession(client);
   }
 
   void EndSession(FakeMidiManagerClient* client, size_t before, size_t after) {
-    EXPECT_EQ(before, manager_->GetClientCount());
-    EXPECT_TRUE(manager_->EndSession(client));
-    EXPECT_EQ(after, manager_->GetClientCount());
+    DCHECK(factory_);
+
+    ASSERT_TRUE(factory_->manager());
+    EXPECT_EQ(before, factory_->manager()->GetClientCount());
+    EXPECT_TRUE(service_->EndSession(client));
+    if (after) {
+      ASSERT_TRUE(factory_->manager());
+      EXPECT_EQ(after, factory_->manager()->GetClientCount());
+    } else {
+      EXPECT_FALSE(factory_->manager());
+    }
   }
 
-  void CompleteInitialization(Result result) {
-    manager_->CallCompleteInitialization(result);
+  bool CompleteInitialization(Result result) {
+    DCHECK(factory_);
+
+    if (!factory_->manager())
+      return false;
+
+    factory_->manager()->CallCompleteInitialization(result);
+    return true;
   }
 
   void RunLoopUntilIdle() {
@@ -191,49 +224,48 @@
     run_loop.RunUntilIdle();
   }
 
- protected:
-  FakeMidiManager* manager_;  // Owned by |service_|.
-  FakeMidiManagerFactory* factory_;  // Owned by |service_|.
-  std::unique_ptr<MidiService> service_;
+  base::WeakPtr<FakeMidiManagerFactory> factory() { return factory_; }
 
  private:
   std::unique_ptr<base::MessageLoop> message_loop_;
+  base::WeakPtr<FakeMidiManagerFactory> factory_;
+  std::unique_ptr<MidiService> service_;
 
   DISALLOW_COPY_AND_ASSIGN(MidiManagerTest);
 };
 
 TEST_F(MidiManagerTest, StartAndEndSession) {
-  std::unique_ptr<FakeMidiManagerClient> client;
-  client.reset(new FakeMidiManagerClient);
+  std::unique_ptr<FakeMidiManagerClient> client =
+      std::make_unique<FakeMidiManagerClient>();
 
   StartTheFirstSession(client.get());
-  CompleteInitialization(Result::OK);
+  EXPECT_TRUE(CompleteInitialization(Result::OK));
   EXPECT_EQ(Result::OK, client->WaitForResult());
   EndSession(client.get(), 1U, 0U);
 }
 
 TEST_F(MidiManagerTest, StartAndEndSessionWithError) {
-  std::unique_ptr<FakeMidiManagerClient> client;
-  client.reset(new FakeMidiManagerClient);
+  std::unique_ptr<FakeMidiManagerClient> client =
+      std::make_unique<FakeMidiManagerClient>();
 
   StartTheFirstSession(client.get());
-  CompleteInitialization(Result::INITIALIZATION_ERROR);
+  EXPECT_TRUE(CompleteInitialization(Result::INITIALIZATION_ERROR));
   EXPECT_EQ(Result::INITIALIZATION_ERROR, client->WaitForResult());
   EndSession(client.get(), 1U, 0U);
 }
 
 TEST_F(MidiManagerTest, StartMultipleSessions) {
-  std::unique_ptr<FakeMidiManagerClient> client1;
-  std::unique_ptr<FakeMidiManagerClient> client2;
-  std::unique_ptr<FakeMidiManagerClient> client3;
-  client1.reset(new FakeMidiManagerClient);
-  client2.reset(new FakeMidiManagerClient);
-  client3.reset(new FakeMidiManagerClient);
+  std::unique_ptr<FakeMidiManagerClient> client1 =
+      std::make_unique<FakeMidiManagerClient>();
+  std::unique_ptr<FakeMidiManagerClient> client2 =
+      std::make_unique<FakeMidiManagerClient>();
+  std::unique_ptr<FakeMidiManagerClient> client3 =
+      std::make_unique<FakeMidiManagerClient>();
 
   StartTheFirstSession(client1.get());
   StartTheNthSession(client2.get(), 2);
   StartTheNthSession(client3.get(), 3);
-  CompleteInitialization(Result::OK);
+  EXPECT_TRUE(CompleteInitialization(Result::OK));
   EXPECT_EQ(Result::OK, client1->WaitForResult());
   EXPECT_EQ(Result::OK, client2->WaitForResult());
   EXPECT_EQ(Result::OK, client3->WaitForResult());
@@ -242,26 +274,23 @@
   EndSession(client3.get(), 1U, 0U);
 }
 
-// TODO(toyoshim): Add a test for a MidiManagerClient that has multiple
-// sessions with multiple client_id.
-
 TEST_F(MidiManagerTest, TooManyPendingSessions) {
   // Push as many client requests for starting session as possible.
   std::vector<std::unique_ptr<FakeMidiManagerClient>> many_existing_clients;
   many_existing_clients.resize(MidiManager::kMaxPendingClientCount);
-  for (size_t i = 0; i < MidiManager::kMaxPendingClientCount; ++i) {
+  many_existing_clients[0] = std::make_unique<FakeMidiManagerClient>();
+  StartTheFirstSession(many_existing_clients[0].get());
+  for (size_t i = 1; i < MidiManager::kMaxPendingClientCount; ++i) {
     many_existing_clients[i] = std::make_unique<FakeMidiManagerClient>();
     StartTheNthSession(many_existing_clients[i].get(), i + 1);
   }
-  EXPECT_TRUE(manager_->start_initialization_is_called_);
+  ASSERT_TRUE(factory()->manager());
+  EXPECT_TRUE(factory()->manager()->IsInitialized());
 
   // Push the last client that should be rejected for too many pending requests.
-  std::unique_ptr<FakeMidiManagerClient> additional_client(
-      new FakeMidiManagerClient);
-  manager_->start_initialization_is_called_ = false;
-  manager_->StartSession(additional_client.get());
-  EXPECT_FALSE(manager_->start_initialization_is_called_);
-  manager_->start_initialization_is_called_ = true;
+  std::unique_ptr<FakeMidiManagerClient> additional_client =
+      std::make_unique<FakeMidiManagerClient>();
+  StartSession(additional_client.get());
   EXPECT_EQ(Result::INITIALIZATION_ERROR, additional_client->result());
 
   // Other clients still should not receive a result.
@@ -270,7 +299,7 @@
     EXPECT_EQ(Result::NOT_SUPPORTED, many_existing_clients[i]->result());
 
   // The Result::OK should be distributed to other clients.
-  CompleteInitialization(Result::OK);
+  EXPECT_TRUE(CompleteInitialization(Result::OK));
   for (size_t i = 0; i < many_existing_clients.size(); ++i)
     EXPECT_EQ(Result::OK, many_existing_clients[i]->WaitForResult());
 
@@ -283,27 +312,29 @@
 TEST_F(MidiManagerTest, AbortSession) {
   // A client starting a session can be destructed while an asynchronous
   // initialization is performed.
-  std::unique_ptr<FakeMidiManagerClient> client;
-  client.reset(new FakeMidiManagerClient);
+  std::unique_ptr<FakeMidiManagerClient> client =
+      std::make_unique<FakeMidiManagerClient>();
 
   StartTheFirstSession(client.get());
   EndSession(client.get(), 0, 0);
   client.reset();
 
   // Following function should not call the destructed |client| function.
-  CompleteInitialization(Result::OK);
+  EXPECT_FALSE(CompleteInitialization(Result::OK));
   base::RunLoop run_loop;
   run_loop.RunUntilIdle();
 }
 
-TEST_F(MidiManagerTest, CreateMidiManager) {
+TEST_F(MidiManagerTest, CreatePlatformMidiManager) {
   // SystemMonitor is needed on Windows.
   base::SystemMonitor system_monitor;
 
-  std::unique_ptr<FakeMidiManagerClient> client(
-      std::make_unique<FakeMidiManagerClient>());
+  std::unique_ptr<FakeMidiManagerClient> client =
+      std::make_unique<FakeMidiManagerClient>();
 
-  std::unique_ptr<MidiService> service(std::make_unique<MidiService>());
+  // Use own MidiService instance to construct a real platform dependent
+  // MidiManager instance.
+  std::unique_ptr<MidiService> service = std::make_unique<MidiService>();
   service->StartSession(client.get());
 
   Result result = client->WaitForResult();
@@ -324,9 +355,6 @@
   run_loop.RunUntilIdle();
 }
 
-// TODO(toyoshim): Add multi-threaded unit tests to check races around
-// StartInitialization(), CompleteInitialization(), and Finalize().
-
 }  // namespace
 
 }  // namespace midi
diff --git a/media/midi/midi_manager_usb_unittest.cc b/media/midi/midi_manager_usb_unittest.cc
index d23434e..70ebed3 100644
--- a/media/midi/midi_manager_usb_unittest.cc
+++ b/media/midi/midi_manager_usb_unittest.cc
@@ -227,7 +227,7 @@
     service_ = std::make_unique<MidiService>(std::move(factory));
   }
   ~MidiManagerUsbTest() override {
-    manager()->Shutdown();
+    service_->Shutdown();
     base::RunLoop run_loop;
     run_loop.RunUntilIdle();
 
@@ -240,10 +240,10 @@
  protected:
   void Initialize() {
     client_.reset(new FakeMidiManagerClient(&logger_));
-    manager()->StartSession(client_.get());
+    service_->StartSession(client_.get());
   }
 
-  void Finalize() { manager()->EndSession(client_.get()); }
+  void Finalize() { service_->EndSession(client_.get()); }
 
   bool IsInitializationCallbackInvoked() {
     return client_->complete_start_session_;
diff --git a/media/midi/midi_service.cc b/media/midi/midi_service.cc
index 6ecd858..59b155f 100644
--- a/media/midi/midi_service.cc
+++ b/media/midi/midi_service.cc
@@ -30,23 +30,11 @@
   return delay;
 }
 
-MidiService::MidiService(void)
-    : MidiService(std::make_unique<ManagerFactory>(), true) {}
+MidiService::MidiService() : MidiService(std::make_unique<ManagerFactory>()) {}
 
-// TODO(toyoshim): Stop enforcing to disable dynamic instantiation mode for
-// testing once the mode is enabled by default.
 MidiService::MidiService(std::unique_ptr<ManagerFactory> factory)
-    : MidiService(std::move(factory), false) {}
-
-MidiService::MidiService(std::unique_ptr<ManagerFactory> factory,
-                         bool enable_dynamic_instantiation)
     : manager_factory_(std::move(factory)),
-      task_service_(std::make_unique<TaskService>()),
-      is_dynamic_instantiation_enabled_(enable_dynamic_instantiation) {
-  base::AutoLock lock(lock_);
-  if (!is_dynamic_instantiation_enabled_)
-    manager_ = manager_factory_->Create(this);
-}
+      task_service_(std::make_unique<TaskService>()) {}
 
 MidiService::~MidiService() {
   base::AutoLock lock(lock_);
@@ -60,9 +48,11 @@
 void MidiService::Shutdown() {
   base::AutoLock lock(lock_);
   if (manager_) {
-    manager_->Shutdown();
-    if (is_dynamic_instantiation_enabled_)
-      manager_destructor_runner_->DeleteSoon(FROM_HERE, std::move(manager_));
+    DCHECK(manager_destructor_runner_);
+    manager_destructor_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&MidiManager::Shutdown,
+                                  base::Unretained(manager_.get())));
+    manager_destructor_runner_->DeleteSoon(FROM_HERE, std::move(manager_));
     manager_destructor_runner_ = nullptr;
   }
 }
@@ -70,35 +60,36 @@
 void MidiService::StartSession(MidiManagerClient* client) {
   base::AutoLock lock(lock_);
   if (!manager_) {
-    DCHECK(is_dynamic_instantiation_enabled_);
     manager_ = manager_factory_->Create(this);
-    if (!manager_destructor_runner_)
-      manager_destructor_runner_ = base::ThreadTaskRunnerHandle::Get();
+    DCHECK(!manager_destructor_runner_);
+    manager_destructor_runner_ = base::ThreadTaskRunnerHandle::Get();
   }
   manager_->StartSession(client);
 }
 
-void MidiService::EndSession(MidiManagerClient* client) {
+bool MidiService::EndSession(MidiManagerClient* client) {
   base::AutoLock lock(lock_);
 
   // |client| does not seem to be valid.
   if (!manager_ || !manager_->EndSession(client))
-    return;
+    return false;
 
 // Do not destruct MidiManager on macOS to avoid a Core MIDI issue that
 // MIDIClientCreate starts failing with the OSStatus -50 after repeated calls
 // of MIDIClientDispose. It rarely happens, but once it starts, it will never
 // get back to be sane. See https://crbug.com/718140.
 #if !defined(OS_MACOSX)
-  if (is_dynamic_instantiation_enabled_ && !manager_->HasOpenSession()) {
+  if (!manager_->HasOpenSession()) {
     // MidiManager for each platform should be able to shutdown correctly even
-    // if following Shutdown() call happens in the middle of
-    // StartInitialization() to support the dynamic instantiation feature.
+    // if following destruction happens in the middle of StartInitialization().
     manager_->Shutdown();
     manager_.reset();
+    DCHECK(manager_destructor_runner_);
+    DCHECK(manager_destructor_runner_->BelongsToCurrentThread());
     manager_destructor_runner_ = nullptr;
   }
 #endif
+  return true;
 }
 
 void MidiService::DispatchSendMidiData(MidiManagerClient* client,
diff --git a/media/midi/midi_service.h b/media/midi/midi_service.h
index 711968b..a2233e6 100644
--- a/media/midi/midi_service.h
+++ b/media/midi/midi_service.h
@@ -40,14 +40,8 @@
   // Converts Web MIDI timestamp to base::TimeDelta dealy for PostDelayedTask.
   static base::TimeDelta TimestampToTimeDeltaDelay(double timestamp);
 
-  // Use the first constructor for production code.
   MidiService();
-  // ManagerFactory can be specified in the constructor for testing.  If the
-  // factory is specified, Dynamic instantiation mode is disabled.  MidiManager
-  // will be created immediately, and won't be destructed until MidiService
-  // dies.
-  // TODO(toyoshim): Adopt dynamic instantiation mode once the mode is enabled
-  // by default.
+  // Customized ManagerFactory can be specified in the constructor for testing.
   explicit MidiService(std::unique_ptr<ManagerFactory> factory);
   ~MidiService();
 
@@ -59,7 +53,8 @@
   void StartSession(MidiManagerClient* client);
 
   // A client calls EndSession() to stop receiving MIDI data.
-  void EndSession(MidiManagerClient* client);
+  // Returns false if |client| did not start a session.
+  bool EndSession(MidiManagerClient* client);
 
   // A client calls DispatchSendMidiData() to send MIDI data.
   void DispatchSendMidiData(MidiManagerClient* client,
@@ -81,14 +76,12 @@
   TaskService* task_service() { return task_service_.get(); }
 
  private:
-  MidiService(std::unique_ptr<ManagerFactory> factory,
-              bool enable_dynamic_instantiation);
-
+  // ManagerFactory passed in the constructor.
   std::unique_ptr<ManagerFactory> manager_factory_;
 
-  // Holds MidiManager instance. If the dynamic instantiation feature is
-  // enabled, the MidiManager would be constructed and destructed on the I/O
-  // thread, and all MidiManager methods would be called on the I/O thread.
+  // Holds MidiManager instance. The MidiManager is constructed and destructed
+  // on the I/O thread, and all MidiManager methods should be called on the I/O
+  // thread.
   std::unique_ptr<MidiManager> manager_;
 
   // Holds TaskService instance.
@@ -97,10 +90,6 @@
   // TaskRunner to destruct |manager_| on the right thread.
   scoped_refptr<base::SingleThreadTaskRunner> manager_destructor_runner_;
 
-  // A flag to indicate if the dynamic instantiation feature is supported and
-  // actually enabled.
-  const bool is_dynamic_instantiation_enabled_;
-
   // Protects all members above.
   base::Lock lock_;
 
diff --git a/media/midi/task_service.cc b/media/midi/task_service.cc
index c07b5ff..bfa4e1b 100644
--- a/media/midi/task_service.cc
+++ b/media/midi/task_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 
@@ -65,6 +66,8 @@
   // But invoked tasks might be still running here. To ensure no task runs on
   // quitting this method, wait for all tasks to complete.
   base::AutoLock tasks_in_flight_auto_lock(tasks_in_flight_lock_);
+  // TODO(https://crbug.com/796830): Remove sync operations on the I/O thread.
+  base::ScopedAllowBaseSyncPrimitives allow_wait;
   while (tasks_in_flight_ > 0)
     no_tasks_in_flight_cv_.Wait();
 
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 2f4891f..b9c778e 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -34,10 +34,11 @@
 IdentityManager::CreateAccessTokenFetcherForPrimaryAccount(
     const std::string& oauth_consumer_name,
     const OAuth2TokenService::ScopeSet& scopes,
-    PrimaryAccountAccessTokenFetcher::TokenCallback callback) {
+    PrimaryAccountAccessTokenFetcher::TokenCallback callback,
+    PrimaryAccountAccessTokenFetcher::Mode mode) {
   return base::MakeUnique<PrimaryAccountAccessTokenFetcher>(
       oauth_consumer_name, signin_manager_, token_service_, scopes,
-      std::move(callback));
+      std::move(callback), mode);
 }
 
 void IdentityManager::RemoveAccessTokenFromCache(
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 888418a..e575b784 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -50,7 +50,8 @@
   CreateAccessTokenFetcherForPrimaryAccount(
       const std::string& oauth_consumer_name,
       const OAuth2TokenService::ScopeSet& scopes,
-      PrimaryAccountAccessTokenFetcher::TokenCallback callback);
+      PrimaryAccountAccessTokenFetcher::TokenCallback callback,
+      PrimaryAccountAccessTokenFetcher::Mode mode);
 
   // If an entry exists in the Identity Service's cache corresponding to the
   // given information, removes that entry; in this case, the next access token
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index e57fc12..97339411 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -254,7 +254,8 @@
                         const std::string& access_token) {});
   std::unique_ptr<PrimaryAccountAccessTokenFetcher> token_fetcher =
       identity_manager()->CreateAccessTokenFetcherForPrimaryAccount(
-          "dummy_consumer", scopes, std::move(callback));
+          "dummy_consumer", scopes, std::move(callback),
+          PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
   EXPECT_TRUE(token_fetcher);
 }
 
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher.cc b/services/identity/public/cpp/primary_account_access_token_fetcher.cc
index c017bff9..e4775237 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher.cc
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher.cc
@@ -16,7 +16,8 @@
     SigninManagerBase* signin_manager,
     OAuth2TokenService* token_service,
     const OAuth2TokenService::ScopeSet& scopes,
-    TokenCallback callback)
+    TokenCallback callback,
+    Mode mode)
     : OAuth2TokenService::Consumer(oauth_consumer_name),
       signin_manager_(signin_manager),
       token_service_(token_service),
@@ -24,7 +25,9 @@
       callback_(std::move(callback)),
       waiting_for_sign_in_(false),
       waiting_for_refresh_token_(false),
-      access_token_retried_(false) {
+      access_token_retried_(false),
+      mode_(mode),
+      weak_factory_(this) {
   Start();
 }
 
@@ -38,6 +41,11 @@
 }
 
 void PrimaryAccountAccessTokenFetcher::Start() {
+  if (mode_ == Mode::kImmediate) {
+    ScheduleStartAccessTokenRequest();
+    return;
+  }
+
   if (signin_manager_->IsAuthenticated()) {
     // Already signed in: Make sure we have a refresh token, then get the access
     // token.
@@ -53,6 +61,7 @@
 }
 
 void PrimaryAccountAccessTokenFetcher::WaitForRefreshToken() {
+  DCHECK_EQ(Mode::kWaitUntilAvailable, mode_);
   DCHECK(signin_manager_->IsAuthenticated());
   DCHECK(!waiting_for_refresh_token_);
 
@@ -72,10 +81,12 @@
 void PrimaryAccountAccessTokenFetcher::ScheduleStartAccessTokenRequest() {
   // Fire off the request asynchronously to mimic the asynchronous flow that
   // will occur when this request is going through the Identity Service.
+  // NOTE: Posting the task using a WeakPtr is necessary as this instance
+  // might die before the posted task runs (https://crbug.com/800263).
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&PrimaryAccountAccessTokenFetcher::StartAccessTokenRequest,
-                     base::Unretained(this)));
+                     weak_factory_.GetWeakPtr()));
 }
 
 void PrimaryAccountAccessTokenFetcher::StartAccessTokenRequest() {
@@ -90,6 +101,7 @@
 void PrimaryAccountAccessTokenFetcher::GoogleSigninSucceeded(
     const std::string& account_id,
     const std::string& username) {
+  DCHECK_EQ(Mode::kWaitUntilAvailable, mode_);
   DCHECK(waiting_for_sign_in_);
   DCHECK(!waiting_for_refresh_token_);
   DCHECK(signin_manager_->IsAuthenticated());
@@ -101,6 +113,7 @@
 
 void PrimaryAccountAccessTokenFetcher::GoogleSigninFailed(
     const GoogleServiceAuthError& error) {
+  DCHECK_EQ(Mode::kWaitUntilAvailable, mode_);
   DCHECK(waiting_for_sign_in_);
   DCHECK(!waiting_for_refresh_token_);
   waiting_for_sign_in_ = false;
@@ -111,6 +124,7 @@
 
 void PrimaryAccountAccessTokenFetcher::OnRefreshTokenAvailable(
     const std::string& account_id) {
+  DCHECK_EQ(Mode::kWaitUntilAvailable, mode_);
   DCHECK(waiting_for_refresh_token_);
   DCHECK(!waiting_for_sign_in_);
 
@@ -125,6 +139,7 @@
 }
 
 void PrimaryAccountAccessTokenFetcher::OnRefreshTokensLoaded() {
+  DCHECK_EQ(Mode::kWaitUntilAvailable, mode_);
   DCHECK(waiting_for_refresh_token_);
   DCHECK(!waiting_for_sign_in_);
   DCHECK(!access_token_request_);
@@ -168,7 +183,7 @@
   // so only retry if there (still) is a valid refresh token.
   // NOTE: Maybe we should retry for all transient errors here, so that clients
   // don't have to.
-  if (!access_token_retried_ &&
+  if (mode_ == Mode::kWaitUntilAvailable && !access_token_retried_ &&
       error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED &&
       token_service_->RefreshTokenIsAvailable(
           signin_manager_->GetAuthenticatedAccountId())) {
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher.h b/services/identity/public/cpp/primary_account_access_token_fetcher.h
index c841bd6..dbc68d5 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher.h
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -33,6 +34,14 @@
       base::OnceCallback<void(const GoogleServiceAuthError& error,
                               const std::string& access_token)>;
 
+  // Specifies how this instance should behave:
+  // |kImmediate|: Makes one-shot immediate request.
+  // |kWaitUntilAvailable|: Waits for the primary account to be available
+  // before making the request.
+  // Note that using |kWaitUntilAvailable| can result in waiting forever
+  // if the user is not signed in and doesn't sign in.
+  enum class Mode { kImmediate, kWaitUntilAvailable };
+
   // Instantiates a fetcher and immediately starts the process of obtaining an
   // OAuth2 access token for the given |scopes|. The |callback| is called once
   // the request completes (successful or not). If the
@@ -42,7 +51,8 @@
                                    SigninManagerBase* signin_manager,
                                    OAuth2TokenService* token_service,
                                    const OAuth2TokenService::ScopeSet& scopes,
-                                   TokenCallback callback);
+                                   TokenCallback callback,
+                                   Mode mode);
 
   ~PrimaryAccountAccessTokenFetcher() override;
 
@@ -82,6 +92,10 @@
   // When a token request gets canceled, we want to retry once.
   bool access_token_retried_;
 
+  Mode mode_;
+
+  base::WeakPtrFactory<PrimaryAccountAccessTokenFetcher> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PrimaryAccountAccessTokenFetcher);
 };
 
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc b/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
index 77dbaf5..cc4fac0 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
@@ -38,6 +38,21 @@
 
 namespace identity {
 
+namespace {
+void OnAccessTokenFetchComplete(base::OnceClosure done_closure,
+                                const GoogleServiceAuthError& expected_error,
+                                const std::string& expected_access_token,
+                                const GoogleServiceAuthError& error,
+                                const std::string& access_token) {
+  EXPECT_EQ(expected_error, error);
+  if (expected_error == GoogleServiceAuthError::AuthErrorNone())
+    EXPECT_EQ(expected_access_token, access_token);
+
+  std::move(done_closure).Run();
+}
+
+}  // namespace
+
 class PrimaryAccountAccessTokenFetcherTest
     : public testing::Test,
       public OAuth2TokenService::DiagnosticsObserver {
@@ -78,11 +93,12 @@
   }
 
   std::unique_ptr<PrimaryAccountAccessTokenFetcher> CreateFetcher(
-      PrimaryAccountAccessTokenFetcher::TokenCallback callback) {
+      PrimaryAccountAccessTokenFetcher::TokenCallback callback,
+      PrimaryAccountAccessTokenFetcher::Mode mode) {
     std::set<std::string> scopes{"scope"};
     return base::MakeUnique<PrimaryAccountAccessTokenFetcher>(
         "test_consumer", signin_manager_.get(), &token_service_, scopes,
-        std::move(callback));
+        std::move(callback), mode);
   }
 
   FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
@@ -120,7 +136,7 @@
   base::OnceClosure on_access_token_request_callback_;
 };
 
-TEST_F(PrimaryAccountAccessTokenFetcherTest, ShouldReturnAccessToken) {
+TEST_F(PrimaryAccountAccessTokenFetcherTest, OneShotShouldReturnAccessToken) {
   TestTokenCallback callback;
 
   base::RunLoop run_loop;
@@ -131,7 +147,35 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(), PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+
+  run_loop.Run();
+
+  // Once the access token request is fulfilled, we should get called back with
+  // the access token.
+  EXPECT_CALL(callback,
+              Run(GoogleServiceAuthError::AuthErrorNone(), "access token"));
+  token_service()->IssueAllTokensForAccount(
+      "account", "access token",
+      base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(PrimaryAccountAccessTokenFetcherTest,
+       WaitAndRetryShouldReturnAccessToken) {
+  TestTokenCallback callback;
+
+  base::RunLoop run_loop;
+  set_on_access_token_request_callback(run_loop.QuitClosure());
+
+  SignIn("account");
+  token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
+
+  // Signed in and refresh token already exists, so this should result in a
+  // request for an access token.
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   run_loop.Run();
 
@@ -155,7 +199,8 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(), PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
 
   run_loop.Run();
 
@@ -168,12 +213,74 @@
       base::Time::Now() + base::TimeDelta::FromHours(1));
 }
 
-TEST_F(PrimaryAccountAccessTokenFetcherTest, ShouldNotReturnWhenSignedOut) {
+TEST_F(PrimaryAccountAccessTokenFetcherTest, ShouldNotRequestIfDestroyedEarly) {
+  TestTokenCallback callback;
+
+  base::RunLoop run_loop;
+  set_on_access_token_request_callback(
+      base::BindOnce([]() { EXPECT_TRUE(false); }));
+
+  SignIn("account");
+  token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
+
+  // Signed in and refresh token already exists, so this should result in
+  // posting a task to make a request for an access token.
+  auto fetcher = CreateFetcher(
+      callback.Get(), PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+
+  // Destroy the fetcher immediately.
+  fetcher.reset();
+
+  // No access token request should occur (i.e., the posted task should not
+  // actually execute).
+  run_loop.RunUntilIdle();
+
+  // Now fulfilling the access token request should have no effect.
+  token_service()->IssueAllTokensForAccount(
+      "account", "access token",
+      base::Time::Now() + base::TimeDelta::FromHours(1));
+}
+
+TEST_F(PrimaryAccountAccessTokenFetcherTest, OneShotCallsBackWhenSignedOut) {
+  base::RunLoop run_loop;
+
+  // Signed out -> we should get called back.
+  auto fetcher = CreateFetcher(
+      base::BindOnce(&OnAccessTokenFetchComplete, run_loop.QuitClosure(),
+                     GoogleServiceAuthError(
+                         GoogleServiceAuthError::State::USER_NOT_SIGNED_UP),
+                     ""),
+      PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+
+  run_loop.Run();
+}
+
+TEST_F(PrimaryAccountAccessTokenFetcherTest,
+       OneShotCallsBackWhenNoRefreshToken) {
+  base::RunLoop run_loop;
+
+  SignIn("account");
+
+  // Signed in, but there is no refresh token -> we should get called back.
+  auto fetcher = CreateFetcher(
+      base::BindOnce(&OnAccessTokenFetchComplete, run_loop.QuitClosure(),
+                     GoogleServiceAuthError(
+                         GoogleServiceAuthError::State::USER_NOT_SIGNED_UP),
+                     ""),
+      PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+
+  run_loop.Run();
+}
+
+TEST_F(PrimaryAccountAccessTokenFetcherTest,
+       WaitAndRetryNoCallbackWhenSignedOut) {
   TestTokenCallback callback;
 
   // Signed out -> the fetcher should wait for a sign-in which never happens
   // in this test, so we shouldn't get called back.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 }
 
 // Tests related to waiting for sign-in don't apply on ChromeOS (it doesn't have
@@ -187,7 +294,9 @@
   TestTokenCallback callback;
 
   // Not signed in, so this should wait for a sign-in to complete.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   SignIn("account");
 
@@ -214,7 +323,9 @@
 
   // A sign-in is currently in progress, so this should wait for the sign-in to
   // complete.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   SignIn("account");
   token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
@@ -237,7 +348,9 @@
 
   // A sign-in is currently in progress, so this should wait for the sign-in to
   // complete.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   // The fetcher should detect the failed sign-in and call us with an empty
   // access token.
@@ -262,7 +375,9 @@
 
   // Signed in, but there is no refresh token -> we should not get called back
   // (yet).
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   // Getting a refresh token should result in a request for an access token.
   token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
@@ -288,7 +403,9 @@
   token_service()->GetDelegate()->UpdateCredentials("account 2", "refresh");
 
   // The fetcher should wait for the correct refresh token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   // A refresh token for yet another account shouldn't matter either.
   token_service()->GetDelegate()->UpdateCredentials("account 3", "refresh");
@@ -302,7 +419,9 @@
 
   // Signed in, but there is no refresh token -> we should not get called back
   // (yet).
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   // Getting a refresh token for some other account should have no effect.
   token_service()->GetDelegate()->UpdateCredentials("different account",
@@ -319,7 +438,35 @@
 }
 
 TEST_F(PrimaryAccountAccessTokenFetcherTest,
-       ShouldRetryCanceledAccessTokenRequest) {
+       OneShotCanceledAccessTokenRequest) {
+  base::RunLoop run_loop;
+  set_on_access_token_request_callback(run_loop.QuitClosure());
+
+  SignIn("account");
+  token_service()->GetDelegate()->UpdateCredentials("account", "refresh token");
+
+  base::RunLoop run_loop2;
+
+  // Signed in and refresh token already exists, so this should result in a
+  // request for an access token.
+  auto fetcher = CreateFetcher(
+      base::BindOnce(
+          &OnAccessTokenFetchComplete, run_loop2.QuitClosure(),
+          GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED), ""),
+      PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+
+  run_loop.Run();
+
+  // A canceled access token request should result in a callback.
+  token_service()->IssueErrorForAllPendingRequestsForAccount(
+      "account",
+      GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+
+  run_loop2.Run();
+}
+
+TEST_F(PrimaryAccountAccessTokenFetcherTest,
+       WaitAndRetryCanceledAccessTokenRequest) {
   base::RunLoop run_loop;
   set_on_access_token_request_callback(run_loop.QuitClosure());
 
@@ -330,7 +477,9 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   run_loop.Run();
 
@@ -366,7 +515,9 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   run_loop.Run();
 
@@ -406,7 +557,9 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   run_loop.Run();
 
@@ -437,7 +590,9 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   run_loop.Run();
 
@@ -465,7 +620,9 @@
 
   // Signed in and refresh token already exists, so this should result in a
   // request for an access token.
-  auto fetcher = CreateFetcher(callback.Get());
+  auto fetcher = CreateFetcher(
+      callback.Get(),
+      PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
 
   run_loop.Run();
 
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 080bc65..24b8ebc 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -3208,23 +3208,6 @@
       },
       {
         "args": [
-          "--use-gpu-in-tests",
-          "--no-xvfb"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": false,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6613",
-              "os": "Ubuntu"
-            }
-          ]
-        },
-        "test": "gl_unittests",
-        "use_xvfb": false
-      },
-      {
-        "args": [
           "--use-gpu-in-tests"
         ],
         "swarming": {
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index cfcc442..e2d3cb47 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -145,7 +145,7 @@
 crbug.com/591099 animations/animation-ready-reject-script-forbidden.html [ Timeout ]
 crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ]
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ]
-crbug.com/591099 animations/interpolation/height-interpolation.html [ Crash ]
+crbug.com/591099 animations/interpolation/height-interpolation.html [ Crash Pass ]
 crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
@@ -2166,7 +2166,7 @@
 crbug.com/714962 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-right-overflow.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-right-table.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-004.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats/floats-zero-height-wrap-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats/floats-zero-height-wrap-002.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/CSS2/linebox/inline-formatting-context-015.xht [ Failure ]
 crbug.com/714962 external/wpt/css/CSS2/linebox/vertical-align-baseline-005a.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-percents-001.xht [ Failure ]
@@ -2203,7 +2203,7 @@
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-002-inline.html [ Crash Pass ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-002-none.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-text-inherit.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-display/display-flow-root-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-display/display-flow-root-001.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-003.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-flexbox/position-absolute-005.html [ Failure ]
@@ -2569,10 +2569,10 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-013.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-015.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-017.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-019.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-019.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-021.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-023.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-025.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-025.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-027.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-029.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-031.xht [ Failure ]
@@ -2590,13 +2590,13 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-055.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-057.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-059.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-061.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-061.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-063.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-065.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-067.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-069.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-071.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-073.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-073.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-075.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-077.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-079.xht [ Failure Pass ]
@@ -2607,7 +2607,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-089.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-091.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-093.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-095.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-095.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-097.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-103.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-105.xht [ Failure Pass ]
@@ -2619,9 +2619,9 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-117.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-119.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-121.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-123.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-123.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-125.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-127.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-127.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-129.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-131.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-133.xht [ Failure Pass ]
@@ -2636,7 +2636,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-151.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-153.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-155.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-157.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-157.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-159.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-161.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-163.xht [ Failure ]
@@ -2664,15 +2664,15 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-207.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-209.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-211.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-213.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-213.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-215.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-217.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-219.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-221.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-223.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-223.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-225.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-227.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-229.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-229.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-004.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-006.xht [ Failure ]
@@ -2770,7 +2770,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-194.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-196.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-198.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-200.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-200.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-202.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-204.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-206.xht [ Failure ]
@@ -2782,7 +2782,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-218.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-220.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-222.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-224.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-224.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-226.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-228.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/block-flow-direction-vrl-002.xht [ Failure ]
@@ -2898,8 +2898,8 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-008.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-010.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-012.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-014.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-016.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-014.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-016.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-018.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vlr-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vrl-006.xht [ Failure ]
@@ -3025,7 +3025,7 @@
 crbug.com/591099 external/wpt/editing/run/outdent.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/removeformat.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/strikethrough.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/subscript.html [ Timeout ]
+crbug.com/591099 external/wpt/editing/run/subscript.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/superscript.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/underline.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/api-invalid-label.html [ Timeout ]
@@ -3405,7 +3405,7 @@
 crbug.com/591099 fast/backgrounds/size/backgroundSize20.html [ Failure ]
 crbug.com/591099 fast/backgrounds/size/backgroundSize21.html [ Failure ]
 crbug.com/591099 fast/backgrounds/size/backgroundSize22.html [ Failure ]
-crbug.com/591099 fast/backgrounds/size/contain-and-cover-zoomed.html [ Failure ]
+crbug.com/591099 fast/backgrounds/size/contain-and-cover-zoomed.html [ Failure Pass ]
 crbug.com/591099 fast/backgrounds/size/contain-and-cover.html [ Failure ]
 crbug.com/591099 fast/backgrounds/size/zero.html [ Failure ]
 crbug.com/591099 fast/backgrounds/svg-as-mask.html [ Failure ]
@@ -3422,7 +3422,7 @@
 crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Crash ]
 crbug.com/591099 fast/block/float/003.html [ Failure ]
 crbug.com/714962 fast/block/float/015.html [ Failure ]
-crbug.com/591099 fast/block/float/018.html [ Failure ]
+crbug.com/591099 fast/block/float/018.html [ Failure Pass ]
 crbug.com/714962 fast/block/float/021.html [ Failure ]
 crbug.com/591099 fast/block/float/022.html [ Failure ]
 crbug.com/714962 fast/block/float/025.html [ Failure ]
@@ -3445,7 +3445,7 @@
 crbug.com/714962 fast/block/float/intruding-float-remove-from-sibling-block-on-absolute-position2.html [ Failure ]
 crbug.com/714962 fast/block/float/intruding-float-remove-from-sibling-block-on-fixed-position.html [ Failure ]
 crbug.com/714962 fast/block/float/intruding-float-remove-from-sibling-block-on-fixed-position2.html [ Failure ]
-crbug.com/591099 fast/block/float/logical-bottom-exceeds-layoutunit-max.html [ Failure ]
+crbug.com/591099 fast/block/float/logical-bottom-exceeds-layoutunit-max.html [ Failure Pass ]
 crbug.com/591099 fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
 crbug.com/591099 fast/block/float/negative-margin-on-element-avoiding-floats.html [ Failure ]
 crbug.com/591099 fast/block/float/nopaint-after-layer-destruction.html [ Failure ]
@@ -3503,7 +3503,7 @@
 crbug.com/591099 fast/block/positioning/move-with-auto-width.html [ Failure ]
 crbug.com/714962 fast/block/positioning/offsetLeft-offsetTop-multicolumn.html [ Failure ]
 crbug.com/591099 fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html [ Crash ]
-crbug.com/591099 fast/block/positioning/positioned-movement-layout-when-height-changes.html [ Crash ]
+crbug.com/591099 fast/block/positioning/positioned-movement-layout-when-height-changes.html [ Crash Pass ]
 crbug.com/591099 fast/block/positioning/rel-positioned-inline-changes-width.html [ Crash ]
 crbug.com/591099 fast/block/positioning/relative-overflow-replaced.html [ Failure ]
 crbug.com/591099 fast/block/positioning/rtl-static-positioning.html [ Failure ]
@@ -3512,7 +3512,7 @@
 crbug.com/591099 fast/block/positioning/vertical-lr/001.html [ Failure ]
 crbug.com/591099 fast/block/positioning/vertical-rl/001.html [ Failure ]
 crbug.com/591099 fast/block/positioning/vertical-rl/002.html [ Failure ]
-crbug.com/591099 fast/block/scrollbar-wider-than-border-box.html [ Failure ]
+crbug.com/591099 fast/block/scrollbar-wider-than-border-box.html [ Failure Pass ]
 crbug.com/591099 fast/body-propagation/background-color/001-xhtml.xhtml [ Failure ]
 crbug.com/591099 fast/body-propagation/background-color/001.html [ Failure ]
 crbug.com/591099 fast/body-propagation/background-color/002-xhtml.xhtml [ Failure ]
@@ -3640,7 +3640,7 @@
 crbug.com/591099 fast/box-shadow/spread.html [ Failure ]
 crbug.com/591099 fast/box-shadow/transform-fringing.html [ Failure ]
 crbug.com/591099 fast/box-sizing/replaced.html [ Failure Pass ]
-crbug.com/714962 fast/canvas-api/canvas-scroll-path-into-view.html [ Failure ]
+crbug.com/714962 fast/canvas-api/canvas-scroll-path-into-view.html [ Failure Pass ]
 crbug.com/591099 fast/canvas-api/fallback-content.html [ Crash ]
 crbug.com/591099 fast/canvas-api/toDataURL-supportedTypes.html [ Failure ]
 crbug.com/591099 fast/canvas/canvas-createImageBitmap-drawImage.html [ Timeout ]
@@ -3794,7 +3794,7 @@
 crbug.com/591099 fast/css-grid-layout/implicit-position-dynamic-change.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/maximize-tracks-definite-indefinite-height.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/maximize-tracks-definite-indefinite-width.html [ Failure ]
-crbug.com/714962 fast/css-grid-layout/min-width-height-auto-overflow.html [ Failure ]
+crbug.com/714962 fast/css-grid-layout/min-width-height-auto-overflow.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/minmax-fixed-logical-height-only.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/minmax-fixed-logical-width-only.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/minmax-max-content-resolution-columns.html [ Failure ]
@@ -3825,10 +3825,10 @@
 crbug.com/591099 fast/css-intrinsic-dimensions/fixed-height-stf-img-block-child-percent-height.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fixed-height-stf-img-inline-child-percent-height.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-css-tables.html [ Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/height-flexbox.html [ Failure ]
+crbug.com/591099 fast/css-intrinsic-dimensions/height-flexbox.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned-replaced.html [ Crash ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Crash ]
-crbug.com/591099 fast/css-intrinsic-dimensions/height.html [ Failure ]
+crbug.com/591099 fast/css-intrinsic-dimensions/height.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/indefinite-percent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/multicol.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/resize-inside-percent-width-overflow-hidden.html [ Failure ]
@@ -4104,7 +4104,7 @@
 crbug.com/591099 fast/css/simple-selector-chain-parsing.html [ Failure ]
 crbug.com/591099 fast/css/sticky/inline-sticky-abspos-child.html [ Failure ]
 crbug.com/714962 fast/css/sticky/replaced-sticky.html [ Failure ]
-crbug.com/714962 fast/css/sticky/sticky-both-sides-bottom-right-constrained.html [ Failure ]
+crbug.com/714962 fast/css/sticky/sticky-both-sides-bottom-right-constrained.html [ Failure Pass ]
 crbug.com/591099 fast/css/sticky/sticky-top-overflow-scroll-by-fragment.html [ Failure ]
 crbug.com/591099 fast/css/style-outside-head.html [ Failure ]
 crbug.com/591099 fast/css/style-parsed-outside-head.html [ Failure ]
@@ -4206,7 +4206,7 @@
 crbug.com/591099 fast/dom/HTMLDocument/activeElement.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLDocument/document-write-variadic.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLDocument/frameless-location-bugzilla10837.html [ Failure ]
-crbug.com/591099 fast/dom/HTMLDocument/object-by-name-or-id.html [ Crash ]
+crbug.com/591099 fast/dom/HTMLDocument/object-by-name-or-id.html [ Crash Pass ]
 crbug.com/591099 fast/dom/HTMLElement/bdo.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLImageElement/image-alt-text.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLLinkElement/pending-stylesheet-count.html [ Failure ]
@@ -4499,7 +4499,7 @@
 crbug.com/714962 fast/events/touch/gesture/gesture-tap-input-after-composition.html [ Failure ]
 crbug.com/714962 fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure ]
 crbug.com/714962 fast/events/touch/gesture/gesture-tap-result.html [ Failure ]
-crbug.com/591099 fast/events/touch/gesture/touch-gesture-scroll-iframe-past-extent.html [ Failure ]
+crbug.com/591099 fast/events/touch/gesture/touch-gesture-scroll-iframe-past-extent.html [ Failure Pass ]
 crbug.com/591099 fast/events/touch/touch-action-range-input-crash.html [ Crash ]
 crbug.com/591099 fast/events/touch/touch-action-range-input-csp.html [ Crash ]
 crbug.com/591099 fast/events/touch/touch-action-range-input.html [ Crash ]
@@ -4566,7 +4566,7 @@
 crbug.com/714962 fast/forms/calendar-picker/month-picker-mouse-operations.html [ Failure ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-appearance-step.html [ Failure ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-appearance.html [ Failure ]
-crbug.com/591099 fast/forms/calendar-picker/week-picker-key-operations.html [ Timeout ]
+crbug.com/591099 fast/forms/calendar-picker/week-picker-key-operations.html [ Pass Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-mouse-operations.html [ Failure ]
 crbug.com/591099 fast/forms/caret-rtl.html [ Failure ]
 crbug.com/591099 fast/forms/checkbox/checkbox-appearance-basic.html [ Failure ]
@@ -5678,7 +5678,7 @@
 crbug.com/714962 fast/overflow/overflow-stacking.html [ Failure ]
 crbug.com/714962 fast/overflow/overflow-text-hit-testing.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
-crbug.com/591099 fast/overflow/overflow-visible-should-ignore-scroll.html [ Failure ]
+crbug.com/591099 fast/overflow/overflow-visible-should-ignore-scroll.html [ Failure Pass ]
 crbug.com/591099 fast/overflow/overflow-with-local-background-attachment.html [ Failure ]
 crbug.com/714962 fast/overflow/overflow-x-y.html [ Failure ]
 crbug.com/591099 fast/overflow/recompute-overflow-of-layout-root-container.html [ Failure ]
@@ -5710,6 +5710,8 @@
 crbug.com/591099 fast/pagination/modal-dialog.html [ Crash ]
 crbug.com/591099 fast/pagination/multicol.html [ Failure ]
 crbug.com/591099 fast/pagination/paged-x-column-gap.html [ Failure ]
+crbug.com/591099 fast/pagination/repeating-thead-tfoot-paged-x.html [ Failure ]
+crbug.com/591099 fast/pagination/repeating-thead-tfoot-paged-y.html [ Failure ]
 crbug.com/591099 fast/pagination/short-pages-tall-content.html [ Timeout ]
 crbug.com/591099 fast/pagination/viewport-x-vertical-rl-ltr.html [ Failure ]
 crbug.com/591099 fast/pagination/viewport-x-vertical-rl-rtl.html [ Failure ]
@@ -5818,7 +5820,7 @@
 crbug.com/591099 fast/ruby/rubyDOM-remove-text1.html [ Failure ]
 crbug.com/591099 fast/ruby/rubyDOM-remove-text2.html [ Failure ]
 crbug.com/591099 fast/ruby/select-ruby.html [ Failure ]
-crbug.com/714962 fast/scroll-behavior/scroll-iframe-into-view-twice.html [ Failure ]
+crbug.com/714962 fast/scroll-behavior/scroll-iframe-into-view-twice.html [ Failure Pass ]
 crbug.com/714962 fast/scroll-behavior/scroll-over-resizer.html [ Failure ]
 crbug.com/591099 fast/scrolling/content-box-smaller-than-scrollbar.html [ Failure ]
 crbug.com/591099 fast/scrolling/fractional-scroll-offset-fixed-position-non-composited.html [ Crash ]
@@ -6464,7 +6466,6 @@
 crbug.com/591099 fragmentation/float-margin-top.html [ Failure ]
 crbug.com/591099 fragmentation/float-pushed-to-next-fragmentainer-by-floats.html [ Failure ]
 crbug.com/591099 fragmentation/forced-break-clearance-unsplittable-content.html [ Failure ]
-crbug.com/591099 fragmentation/forced-break-inside-float.html [ Failure ]
 crbug.com/591099 fragmentation/fragmented-rowspan-alignment.html [ Failure ]
 crbug.com/591099 fragmentation/fragmented-rowspan.html [ Failure ]
 crbug.com/591099 fragmentation/fragmented-table-cell.html [ Failure ]
@@ -6686,7 +6687,7 @@
 crbug.com/591099 http/tests/csspaint/invalidation-content-image.html [ Timeout ]
 crbug.com/591099 http/tests/devtools/animation/animation-KeyframeEffectReadOnly-crash.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/animation/animation-group-matching-animations.js [ Crash Pass ]
-crbug.com/714962 http/tests/devtools/animation/animation-group-matching-transitions.js [ Crash ]
+crbug.com/714962 http/tests/devtools/animation/animation-group-matching-transitions.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/animation/animation-timeline.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/animation/animation-web-anim-negative-start-time.js [ Crash Pass ]
@@ -6742,19 +6743,19 @@
 crbug.com/714962 http/tests/devtools/elements/insert-node.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/inspect-pseudo-element.js [ Timeout ]
 crbug.com/714962 http/tests/devtools/elements/modify-chardata.js [ Crash ]
-crbug.com/591099 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/create-shadow-root.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/inspect-deep-shadow-element.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/shadow-distribution.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/shadow-host-display-modes.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/add-new-rule-inline-style-csp.js [ Crash ]
-crbug.com/591099 http/tests/devtools/elements/styles-1/add-new-rule-keyboard.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/styles-1/add-new-rule-keyboard.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/styles-1/add-new-rule-with-style-after-body.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/commit-selector-mark-matching.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/commit-selector.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/edit-inspector-stylesheet.js [ Crash ]
-crbug.com/591099 http/tests/devtools/elements/styles-1/edit-media-text.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/styles-1/edit-media-text.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/edit-value-inside-property.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/styles-1/edit-value-url-with-color.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/styles-2/force-pseudo-state.js [ Crash Pass ]
@@ -6778,12 +6779,12 @@
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-then-change.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-then-delete.js [ Crash ]
-crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-then-enable-overriden-ua.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-disable-then-enable.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-4/disable-last-property-without-semicolon.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles-4/styles-formatting.js [ Crash ]
-crbug.com/591099 http/tests/devtools/elements/styles-4/styles-iframe.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/styles-4/styles-iframe.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/styles-4/styles-live-locations-leak.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Crash ]
@@ -6791,6 +6792,7 @@
 crbug.com/591099 http/tests/devtools/elements/styles-4/undo-add-rule-crash.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles/cancel-upon-invalid-property.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/styles/selector-line-deprecated.js [ Crash Pass ]
+crbug.com/591099 http/tests/devtools/elements/styles/selector-line-sourcemap-header-deprecated.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/styles/stylesheet-tracking.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles/undo-after-cancelled-editing.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/styles/undo-change-property.js [ Crash Pass ]
@@ -7965,6 +7967,7 @@
 crbug.com/591099 printing/fixed-positioned-headers-and-footers-larger-than-page.html [ Failure ]
 crbug.com/591099 printing/fixed-positioned-headers-and-footers.html [ Failure ]
 crbug.com/714962 printing/fixed-positioned-scrolled.html [ Failure ]
+crbug.com/591099 printing/fixed-positioned.html [ Failure ]
 crbug.com/591099 printing/forced-break-tree-dump-only.html [ Failure ]
 crbug.com/591099 printing/iframe-print.html [ Failure ]
 crbug.com/591099 printing/list-item-with-empty-first-line.html [ Failure ]
@@ -7995,6 +7998,7 @@
 crbug.com/591099 printing/tfoot-repeats-at-bottom-of-each-page.html [ Failure ]
 crbug.com/591099 printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ Failure ]
 crbug.com/591099 printing/thead-repeats-at-top-of-each-page.html [ Failure ]
+crbug.com/591099 printing/thead-under-multicol.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
 crbug.com/714962 scrollbars/basic-scrollbar.html [ Failure ]
 crbug.com/714962 scrollbars/border-box-rect-clips-scrollbars.html [ Failure ]
@@ -9001,7 +9005,7 @@
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-input-after-composition.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-result.html [ Failure ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/gesture/touch-gesture-scroll-iframe-past-extent.html [ Failure ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/gesture/touch-gesture-scroll-iframe-past-extent.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/touch-action-range-input-crash.html [ Crash ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/touch-action-range-input-csp.html [ Crash ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/touch-action-range-input.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index eba5a299..9ce974d5 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -277,6 +277,7 @@
 crbug.com/697735 external/wpt/editing/run/unlink.html [ Slow ]
 crbug.com/584807 printing/webgl-oversized-printing.html [ Slow ]
 crbug.com/584807 virtual/threaded/printing/webgl-oversized-printing.html [ Slow ]
+crbug.com/584807 virtual/spv175/printing/webgl-oversized-printing.html [ Slow ]
 
 crbug.com/592183 external/wpt/webusb/usbDevice.https.html [ Slow ]
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index d4df380..e9f447e6 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1318,6 +1318,8 @@
 # Printing Layout broken in these tests.
 crbug.com/377696 printing/setPrinting.html [ Skip ]
 crbug.com/377696 printing/width-overflow.html [ Skip ]
+crbug.com/377696 virtual/spv175/printing/setPrinting.html [ Skip ]
+crbug.com/377696 virtual/spv175/printing/width-overflow.html [ Skip ]
 
 crbug.com/658305 css3/filters/buffer-offset.html [ Failure Pass ]
 crbug.com/658305 css3/filters/effect-all-on-background-hw.html [ Failure Pass ]
@@ -3052,13 +3054,6 @@
 
 crbug.com/v8/4958 http/tests/devtools/console/console-format-es6.js [ NeedsManualRebaseline Timeout ]
 
-# For V8 roll
-crbug.com/v8/7172 fast/events/window-onerror-10.html [ NeedsManualRebaseline ]
-crbug.com/v8/7172 fast/frames/sandboxed-iframe-forms.html [ NeedsManualRebaseline ]
-crbug.com/v8/7172 http/tests/devtools/domdebugger/domdebugger-getEventListeners.js [ NeedsManualRebaseline ]
-crbug.com/v8/7172 security/lazy-event-listener.html [ NeedsManualRebaseline ]
-crbug.com/v8/7172 virtual/mouseevent_fractional/fast/events/window-onerror-10.html [ NeedsManualRebaseline ]
-
 # http/tests/devtools/console/console-format-es6.js and its virtual counterpart needs attention, but is listed as NeedsManualRebaseline directly above for all platforms
 # crbug.com/749738 [ Win7 Debug ] http/tests/devtools/console/console-format-es6.js [ Timeout ]
 crbug.com/749738 [ Win7 Debug ] http/tests/devtools/editor/text-editor-word-jumps.js [ Timeout ]
@@ -3556,3 +3551,6 @@
 # Sheriff failures 2018-01-08
 # This test fails consistently on Nexus4 - see bug for info.
 crbug.com/799814 [ Android ] fast/beacon/beacon-basic.html [ Pass Failure ]
+
+# Sheriff failures 2018-01-09
+crbug.com/798481 [ Linux ] virtual/spv175/compositing/gestures/gesture-tapHighlight-simple-window-scroll.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index c56959c1..ab897dc 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -309,6 +309,12 @@
     "references_use_default_args": true
   },
   {
+    "prefix": "spv175",
+    "base": "printing",
+    "args": ["--enable-slimming-paint-v175", "--root-layer-scrolls"],
+    "references_use_default_args": true
+  },
+  {
     "prefix": "scalefactor200",
     "base": "fast/hidpi/static",
     "args": ["--force-device-scale-factor=2"]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-coverage-for-attributes-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-coverage-for-attributes-expected.txt
index b06cbcf6..f0130941 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-coverage-for-attributes-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-coverage-for-attributes-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 175 tests; 173 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 175 tests; 174 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS a.classList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList.
 PASS area.classList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList.
 PASS link.classList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList.
@@ -70,7 +70,7 @@
 PASS output.htmlFor in null namespace should be undefined.
 PASS td.htmlFor in null namespace should be undefined.
 PASS th.htmlFor in null namespace should be undefined.
-FAIL a.relList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList. assert_equals: expected "[object DOMTokenList]" but got "[object Undefined]"
+PASS a.relList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList.
 FAIL area.relList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList. assert_equals: expected "[object DOMTokenList]" but got "[object Undefined]"
 PASS link.relList in http://www.w3.org/1999/xhtml namespace should be DOMTokenList.
 PASS iframe.relList in http://www.w3.org/1999/xhtml namespace should be undefined.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
index 3650855..e35ecbde 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 5263 tests; 5144 PASS, 119 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 5263 tests; 5146 PASS, 117 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS Document interface: attribute domain
 PASS Document interface: attribute referrer
@@ -995,7 +995,7 @@
 PASS HTMLAnchorElement interface: attribute download
 PASS HTMLAnchorElement interface: attribute ping
 PASS HTMLAnchorElement interface: attribute rel
-FAIL HTMLAnchorElement interface: attribute relList assert_true: The prototype object must have a property "relList" expected true got false
+PASS HTMLAnchorElement interface: attribute relList
 PASS HTMLAnchorElement interface: attribute hreflang
 PASS HTMLAnchorElement interface: attribute type
 PASS HTMLAnchorElement interface: attribute text
@@ -1023,7 +1023,7 @@
 PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "download" with the proper type
 PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "ping" with the proper type
 PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "rel" with the proper type
-FAIL HTMLAnchorElement interface: document.createElement("a") must inherit property "relList" with the proper type assert_inherits: property "relList" not found in prototype chain
+PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "relList" with the proper type
 PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "hreflang" with the proper type
 PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "type" with the proper type
 PASS HTMLAnchorElement interface: document.createElement("a") must inherit property "text" with the proper type
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-a-element/rellist-feature-detection.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-a-element/rellist-feature-detection.html
new file mode 100644
index 0000000..8946eaa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/text-level-semantics/the-a-element/rellist-feature-detection.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>HTMLAnchorElement relList</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  var element = document.createElement("a");
+  // Test that setting rel is also setting relList, for both
+  // valid and invalid values.
+  element.rel = "whatever";
+  assert_true(element.relList.contains("whatever"));
+  element.rel = "prefetch";
+  assert_true(element.relList.contains("prefetch"));
+  // Test that add() works.
+  element.relList.add("preloadwhatever");
+  assert_equals(element.rel, "prefetch preloadwhatever");
+  assert_true(element.relList.contains("preloadwhatever"));
+  // Test that remove() works.
+  element.relList.remove("preloadwhatever");
+  assert_equals(element.rel, "prefetch");
+  assert_false(element.relList.contains("preloadwhatever"));
+  // Test that toggle() works.
+  element.relList.toggle("prefetch", false);
+  assert_equals(element.rel, "");
+  element.relList.toggle("prefetch", true);
+  assert_equals(element.rel, "prefetch");
+  // Test that replace() works.
+  element.relList.replace("prefetch", "first");
+  assert_equals(element.rel, "first");
+  // Test that indexed item getter works.
+  element.relList.add("second");
+  assert_equals(element.relList.length, 2);
+  assert_equals(element.relList[0], "first");
+  assert_equals(element.relList[1], "second");
+
+  // Test that supports() is returning true for valid values
+  // and false for invalid ones.
+  assert_false(element.relList.supports("bogus"));
+  assert_false(element.relList.supports("alternate"));
+  assert_false(element.relList.supports("author"));
+  assert_false(element.relList.supports("bookmark"));
+  assert_false(element.relList.supports("external"));
+  assert_false(element.relList.supports("help"));
+  assert_false(element.relList.supports("license"));
+  assert_false(element.relList.supports("next"));
+  assert_false(element.relList.supports("nofollow"));
+  assert_false(element.relList.supports("prev"));
+  assert_false(element.relList.supports("search"));
+  assert_false(element.relList.supports("tag"));
+  assert_true(element.relList.supports("noreferrer"));
+  assert_true(element.relList.supports("noopener"));
+}, "Make sure that relList based feature detection is working");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS
index 3c0bff5..3ffd9fa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS
@@ -1,5 +1,6 @@
 # TEAM: blink-network-dev@chromium.org
 # COMPONENT: Blink>Network>StreamsAPI
+# WPT-NOTIFY: true
 domenic@chromium.org
 ricea@chromium.org
 tyoshino@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/xhr/OWNERS
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/OWNERS
rename to third_party/WebKit/LayoutTests/external/wpt/xhr/OWNERS
diff --git a/third_party/WebKit/LayoutTests/fast/events/window-onerror-10-expected.txt b/third_party/WebKit/LayoutTests/fast/events/window-onerror-10-expected.txt
index d29eabd..c458da7 100644
--- a/third_party/WebKit/LayoutTests/fast/events/window-onerror-10-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/window-onerror-10-expected.txt
@@ -27,7 +27,7 @@
 Stack Trace:
 Error: exception in setTimeout
     at throwException onerror-test.js:6:11
-    at eval window-onerror-10.html:11:155
+    at window-onerror-10.html:11:155
 
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-forms-expected.txt b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-forms-expected.txt
index 569c39e..26a6839b 100644
--- a/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-forms-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/frames/sandboxed-iframe-forms-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 1: Blocked form submission to 'javascript:window.top.disallowedFormSubmitted();' because the form's frame is sandboxed and the 'allow-forms' permission is not set.
+CONSOLE ERROR: line 2: Blocked form submission to 'javascript:window.top.disallowedFormSubmitted();' because the form's frame is sandboxed and the 'allow-forms' permission is not set.
 This test runs five IFrames with forms allowed, one IFrame with forms disallowed, then five more IFrames with forms allowed. If ten form submissions are made, and the disallowed submission is not one of them, we consider the test to have passed. This test will print "PASS" on success.
 
                     
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/domdebugger/domdebugger-getEventListeners-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/domdebugger/domdebugger-getEventListeners-expected.txt
index 9601810..ccdd46b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/domdebugger/domdebugger-getEventListeners-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/domdebugger/domdebugger-getEventListeners-expected.txt
@@ -20,9 +20,9 @@
 
 type: click
 useCapture: false
-location: 0:105
+location: 0:113
 handler: function onclick(event) {
-  return 42;
+return 42;
 }
 sourceURL: inspected-page.html
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/printing/thead-under-multicol-expected.png b/third_party/WebKit/LayoutTests/platform/linux/printing/thead-under-multicol-expected.png
new file mode 100644
index 0000000..8adc774
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/printing/thead-under-multicol-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/printing/thead-under-multicol-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/printing/thead-under-multicol-expected.txt
new file mode 100644
index 0000000..e29862f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/printing/thead-under-multicol-expected.txt
@@ -0,0 +1,373 @@
+layer at (0,0) size 1561x1193 scrollHeight 2016
+  LayoutView at (0,0) size 1561x1193
+layer at (0,0) size 1561x2016 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutBlockFlow {HTML} at (0,0) size 1561x2016
+    LayoutBlockFlow {BODY} at (8,8) size 1545x2000
+layer at (8,8) size 1545x2000 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutBlockFlow {DIV} at (0,0) size 1545x2000
+    LayoutMultiColumnSet (anonymous) at (0,0) size 1545x2000
+layer at (8,8) size 765x3840 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 764.50x3840
+    LayoutTable {TABLE} at (0,0) size 305x3840
+      LayoutTableSection {THEAD} at (0,0) size 305x31
+        LayoutTableRow {TR} at (0,2) size 305x27
+          LayoutTableCell {TH} at (2,2) size 99x27 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 97x24
+              text run at (1,1) width 97: "Column 1"
+          LayoutTableCell {TH} at (103,2) size 99x27 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 97x24
+              text run at (1,1) width 97: "Column 2"
+          LayoutTableCell {TH} at (204,2) size 99x27 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 97x24
+              text run at (1,1) width 97: "Column 3"
+      LayoutTableSection {TBODY} at (0,31) size 305x3809
+        LayoutTableRow {TR} at (0,0) size 305x102
+          LayoutTableCell {TD} at (2,37) size 99x27 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-1"
+          LayoutTableCell {TD} at (103,37) size 99x27 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-1"
+          LayoutTableCell {TD} at (204,37) size 99x27 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-1"
+        LayoutTableRow {TR} at (0,104) size 305x102
+          LayoutTableCell {TD} at (2,141) size 99x27 [r=1 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-2"
+          LayoutTableCell {TD} at (103,141) size 99x27 [r=1 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-2"
+          LayoutTableCell {TD} at (204,141) size 99x27 [r=1 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-2"
+        LayoutTableRow {TR} at (0,208) size 305x102
+          LayoutTableCell {TD} at (2,245) size 99x27 [r=2 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-3"
+          LayoutTableCell {TD} at (103,245) size 99x27 [r=2 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-3"
+          LayoutTableCell {TD} at (204,245) size 99x27 [r=2 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-3"
+        LayoutTableRow {TR} at (0,312) size 305x102
+          LayoutTableCell {TD} at (2,349) size 99x27 [r=3 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-4"
+          LayoutTableCell {TD} at (103,349) size 99x27 [r=3 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-4"
+          LayoutTableCell {TD} at (204,349) size 99x27 [r=3 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-4"
+        LayoutTableRow {TR} at (0,416) size 305x102
+          LayoutTableCell {TD} at (2,453) size 99x27 [r=4 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-5"
+          LayoutTableCell {TD} at (103,453) size 99x27 [r=4 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-5"
+          LayoutTableCell {TD} at (204,453) size 99x27 [r=4 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-5"
+        LayoutTableRow {TR} at (0,520) size 305x102
+          LayoutTableCell {TD} at (2,557) size 99x27 [r=5 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-6"
+          LayoutTableCell {TD} at (103,557) size 99x27 [r=5 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-6"
+          LayoutTableCell {TD} at (204,557) size 99x27 [r=5 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-6"
+        LayoutTableRow {TR} at (0,624) size 305x102
+          LayoutTableCell {TD} at (2,661) size 99x27 [r=6 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-7"
+          LayoutTableCell {TD} at (103,661) size 99x27 [r=6 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-7"
+          LayoutTableCell {TD} at (204,661) size 99x27 [r=6 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-7"
+        LayoutTableRow {TR} at (0,728) size 305x102
+          LayoutTableCell {TD} at (2,765) size 99x27 [r=7 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-8"
+          LayoutTableCell {TD} at (103,765) size 99x27 [r=7 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-8"
+          LayoutTableCell {TD} at (204,765) size 99x27 [r=7 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-8"
+        LayoutTableRow {TR} at (0,832) size 305x102
+          LayoutTableCell {TD} at (2,869) size 99x27 [r=8 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-9"
+          LayoutTableCell {TD} at (103,869) size 99x27 [r=8 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-9"
+          LayoutTableCell {TD} at (204,869) size 99x27 [r=8 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-9"
+        LayoutTableRow {TR} at (0,936) size 305x102
+          LayoutTableCell {TD} at (2,973) size 99x27 [r=9 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-10"
+          LayoutTableCell {TD} at (103,973) size 99x27 [r=9 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-10"
+          LayoutTableCell {TD} at (204,973) size 99x27 [r=9 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-10"
+        LayoutTableRow {TR} at (0,1040) size 305x102
+          LayoutTableCell {TD} at (2,1077) size 99x27 [r=10 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "1-11"
+          LayoutTableCell {TD} at (103,1077) size 99x27 [r=10 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "2-11"
+          LayoutTableCell {TD} at (204,1077) size 99x27 [r=10 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "3-11"
+        LayoutTableRow {TR} at (0,1185) size 305x102
+          LayoutTableCell {TD} at (2,1222) size 99x27 [r=11 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-12"
+          LayoutTableCell {TD} at (103,1222) size 99x27 [r=11 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-12"
+          LayoutTableCell {TD} at (204,1222) size 99x27 [r=11 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-12"
+        LayoutTableRow {TR} at (0,1289) size 305x102
+          LayoutTableCell {TD} at (2,1326) size 99x27 [r=12 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-13"
+          LayoutTableCell {TD} at (103,1326) size 99x27 [r=12 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-13"
+          LayoutTableCell {TD} at (204,1326) size 99x27 [r=12 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-13"
+        LayoutTableRow {TR} at (0,1393) size 305x102
+          LayoutTableCell {TD} at (2,1430) size 99x27 [r=13 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-14"
+          LayoutTableCell {TD} at (103,1430) size 99x27 [r=13 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-14"
+          LayoutTableCell {TD} at (204,1430) size 99x27 [r=13 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-14"
+        LayoutTableRow {TR} at (0,1497) size 305x102
+          LayoutTableCell {TD} at (2,1534) size 99x27 [r=14 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-15"
+          LayoutTableCell {TD} at (103,1534) size 99x27 [r=14 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-15"
+          LayoutTableCell {TD} at (204,1534) size 99x27 [r=14 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-15"
+        LayoutTableRow {TR} at (0,1601) size 305x102
+          LayoutTableCell {TD} at (2,1638) size 99x27 [r=15 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-16"
+          LayoutTableCell {TD} at (103,1638) size 99x27 [r=15 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-16"
+          LayoutTableCell {TD} at (204,1638) size 99x27 [r=15 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-16"
+        LayoutTableRow {TR} at (0,1705) size 305x102
+          LayoutTableCell {TD} at (2,1742) size 99x27 [r=16 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-17"
+          LayoutTableCell {TD} at (103,1742) size 99x27 [r=16 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-17"
+          LayoutTableCell {TD} at (204,1742) size 99x27 [r=16 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-17"
+        LayoutTableRow {TR} at (0,1809) size 305x102
+          LayoutTableCell {TD} at (2,1846) size 99x27 [r=17 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-18"
+          LayoutTableCell {TD} at (103,1846) size 99x27 [r=17 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-18"
+          LayoutTableCell {TD} at (204,1846) size 99x27 [r=17 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-18"
+        LayoutTableRow {TR} at (0,1913) size 305x102
+          LayoutTableCell {TD} at (2,1950) size 99x27 [r=18 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-19"
+          LayoutTableCell {TD} at (103,1950) size 99x27 [r=18 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-19"
+          LayoutTableCell {TD} at (204,1950) size 99x27 [r=18 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-19"
+        LayoutTableRow {TR} at (0,2017) size 305x102
+          LayoutTableCell {TD} at (2,2054) size 99x27 [r=19 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-20"
+          LayoutTableCell {TD} at (103,2054) size 99x27 [r=19 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-20"
+          LayoutTableCell {TD} at (204,2054) size 99x27 [r=19 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-20"
+        LayoutTableRow {TR} at (0,2121) size 305x102
+          LayoutTableCell {TD} at (2,2158) size 99x27 [r=20 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-21"
+          LayoutTableCell {TD} at (103,2158) size 99x27 [r=20 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-21"
+          LayoutTableCell {TD} at (204,2158) size 99x27 [r=20 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-21"
+        LayoutTableRow {TR} at (0,2225) size 305x102
+          LayoutTableCell {TD} at (2,2262) size 99x27 [r=21 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-22"
+          LayoutTableCell {TD} at (103,2262) size 99x27 [r=21 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-22"
+          LayoutTableCell {TD} at (204,2262) size 99x27 [r=21 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-22"
+        LayoutTableRow {TR} at (0,2370) size 305x102
+          LayoutTableCell {TD} at (2,2407) size 99x27 [r=22 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-23"
+          LayoutTableCell {TD} at (103,2407) size 99x27 [r=22 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-23"
+          LayoutTableCell {TD} at (204,2407) size 99x27 [r=22 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-23"
+        LayoutTableRow {TR} at (0,2474) size 305x102
+          LayoutTableCell {TD} at (2,2511) size 99x27 [r=23 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-24"
+          LayoutTableCell {TD} at (103,2511) size 99x27 [r=23 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-24"
+          LayoutTableCell {TD} at (204,2511) size 99x27 [r=23 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-24"
+        LayoutTableRow {TR} at (0,2578) size 305x102
+          LayoutTableCell {TD} at (2,2615) size 99x27 [r=24 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-25"
+          LayoutTableCell {TD} at (103,2615) size 99x27 [r=24 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-25"
+          LayoutTableCell {TD} at (204,2615) size 99x27 [r=24 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-25"
+        LayoutTableRow {TR} at (0,2682) size 305x102
+          LayoutTableCell {TD} at (2,2719) size 99x27 [r=25 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-26"
+          LayoutTableCell {TD} at (103,2719) size 99x27 [r=25 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-26"
+          LayoutTableCell {TD} at (204,2719) size 99x27 [r=25 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-26"
+        LayoutTableRow {TR} at (0,2786) size 305x102
+          LayoutTableCell {TD} at (2,2823) size 99x27 [r=26 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-27"
+          LayoutTableCell {TD} at (103,2823) size 99x27 [r=26 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-27"
+          LayoutTableCell {TD} at (204,2823) size 99x27 [r=26 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-27"
+        LayoutTableRow {TR} at (0,2890) size 305x102
+          LayoutTableCell {TD} at (2,2927) size 99x27 [r=27 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-28"
+          LayoutTableCell {TD} at (103,2927) size 99x27 [r=27 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-28"
+          LayoutTableCell {TD} at (204,2927) size 99x27 [r=27 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-28"
+        LayoutTableRow {TR} at (0,2994) size 305x102
+          LayoutTableCell {TD} at (2,3031) size 99x27 [r=28 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-29"
+          LayoutTableCell {TD} at (103,3031) size 99x27 [r=28 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-29"
+          LayoutTableCell {TD} at (204,3031) size 99x27 [r=28 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-29"
+        LayoutTableRow {TR} at (0,3185) size 305x102
+          LayoutTableCell {TD} at (2,3222) size 99x27 [r=29 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-30"
+          LayoutTableCell {TD} at (103,3222) size 99x27 [r=29 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-30"
+          LayoutTableCell {TD} at (204,3222) size 99x27 [r=29 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-30"
+        LayoutTableRow {TR} at (0,3289) size 305x102
+          LayoutTableCell {TD} at (2,3326) size 99x27 [r=30 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-31"
+          LayoutTableCell {TD} at (103,3326) size 99x27 [r=30 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-31"
+          LayoutTableCell {TD} at (204,3326) size 99x27 [r=30 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-31"
+        LayoutTableRow {TR} at (0,3393) size 305x102
+          LayoutTableCell {TD} at (2,3430) size 99x27 [r=31 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-32"
+          LayoutTableCell {TD} at (103,3430) size 99x27 [r=31 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-32"
+          LayoutTableCell {TD} at (204,3430) size 99x27 [r=31 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-32"
+        LayoutTableRow {TR} at (0,3497) size 305x102
+          LayoutTableCell {TD} at (2,3534) size 99x27 [r=32 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-33"
+          LayoutTableCell {TD} at (103,3534) size 99x27 [r=32 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-33"
+          LayoutTableCell {TD} at (204,3534) size 99x27 [r=32 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-33"
+        LayoutTableRow {TR} at (0,3601) size 305x102
+          LayoutTableCell {TD} at (2,3638) size 99x27 [r=33 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-34"
+          LayoutTableCell {TD} at (103,3638) size 99x27 [r=33 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-34"
+          LayoutTableCell {TD} at (204,3638) size 99x27 [r=33 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-34"
+        LayoutTableRow {TR} at (0,3705) size 305x102
+          LayoutTableCell {TD} at (2,3742) size 99x27 [r=34 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-35"
+          LayoutTableCell {TD} at (103,3742) size 99x27 [r=34 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-35"
+          LayoutTableCell {TD} at (204,3742) size 99x27 [r=34 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-35"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/printing/thead-under-multicol-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/printing/thead-under-multicol-expected.png
new file mode 100644
index 0000000..927aea4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/printing/thead-under-multicol-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/printing/thead-under-multicol-expected.png b/third_party/WebKit/LayoutTests/platform/mac/printing/thead-under-multicol-expected.png
new file mode 100644
index 0000000..8946aacc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/printing/thead-under-multicol-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/printing/thead-under-multicol-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/printing/thead-under-multicol-expected.txt
new file mode 100644
index 0000000..0a8a35a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/printing/thead-under-multicol-expected.txt
@@ -0,0 +1,373 @@
+layer at (0,0) size 1561x1193 scrollHeight 2016
+  LayoutView at (0,0) size 1561x1193
+layer at (0,0) size 1561x2016 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutBlockFlow {HTML} at (0,0) size 1561x2016
+    LayoutBlockFlow {BODY} at (8,8) size 1545x2000
+layer at (8,8) size 1545x2000 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutBlockFlow {DIV} at (0,0) size 1545x2000
+    LayoutMultiColumnSet (anonymous) at (0,0) size 1545x2000
+layer at (8,8) size 765x3839 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 764.50x3839
+    LayoutTable {TABLE} at (0,0) size 308x3839
+      LayoutTableSection {THEAD} at (0,0) size 308x30
+        LayoutTableRow {TR} at (0,2) size 308x26
+          LayoutTableCell {TH} at (2,2) size 100x26 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 98x24
+              text run at (1,1) width 98: "Column 1"
+          LayoutTableCell {TH} at (104,2) size 100x26 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 98x24
+              text run at (1,1) width 98: "Column 2"
+          LayoutTableCell {TH} at (206,2) size 100x26 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 98x24
+              text run at (1,1) width 98: "Column 3"
+      LayoutTableSection {TBODY} at (0,30) size 308x3809
+        LayoutTableRow {TR} at (0,0) size 308x102
+          LayoutTableCell {TD} at (2,38) size 100x26 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-1"
+          LayoutTableCell {TD} at (104,38) size 100x26 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-1"
+          LayoutTableCell {TD} at (206,38) size 100x26 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-1"
+        LayoutTableRow {TR} at (0,104) size 308x102
+          LayoutTableCell {TD} at (2,142) size 100x26 [r=1 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-2"
+          LayoutTableCell {TD} at (104,142) size 100x26 [r=1 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-2"
+          LayoutTableCell {TD} at (206,142) size 100x26 [r=1 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-2"
+        LayoutTableRow {TR} at (0,208) size 308x102
+          LayoutTableCell {TD} at (2,246) size 100x26 [r=2 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-3"
+          LayoutTableCell {TD} at (104,246) size 100x26 [r=2 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-3"
+          LayoutTableCell {TD} at (206,246) size 100x26 [r=2 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-3"
+        LayoutTableRow {TR} at (0,312) size 308x102
+          LayoutTableCell {TD} at (2,350) size 100x26 [r=3 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-4"
+          LayoutTableCell {TD} at (104,350) size 100x26 [r=3 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-4"
+          LayoutTableCell {TD} at (206,350) size 100x26 [r=3 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-4"
+        LayoutTableRow {TR} at (0,416) size 308x102
+          LayoutTableCell {TD} at (2,454) size 100x26 [r=4 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-5"
+          LayoutTableCell {TD} at (104,454) size 100x26 [r=4 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-5"
+          LayoutTableCell {TD} at (206,454) size 100x26 [r=4 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-5"
+        LayoutTableRow {TR} at (0,520) size 308x102
+          LayoutTableCell {TD} at (2,558) size 100x26 [r=5 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-6"
+          LayoutTableCell {TD} at (104,558) size 100x26 [r=5 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-6"
+          LayoutTableCell {TD} at (206,558) size 100x26 [r=5 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-6"
+        LayoutTableRow {TR} at (0,624) size 308x102
+          LayoutTableCell {TD} at (2,662) size 100x26 [r=6 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-7"
+          LayoutTableCell {TD} at (104,662) size 100x26 [r=6 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-7"
+          LayoutTableCell {TD} at (206,662) size 100x26 [r=6 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-7"
+        LayoutTableRow {TR} at (0,728) size 308x102
+          LayoutTableCell {TD} at (2,766) size 100x26 [r=7 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-8"
+          LayoutTableCell {TD} at (104,766) size 100x26 [r=7 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-8"
+          LayoutTableCell {TD} at (206,766) size 100x26 [r=7 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-8"
+        LayoutTableRow {TR} at (0,832) size 308x102
+          LayoutTableCell {TD} at (2,870) size 100x26 [r=8 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-9"
+          LayoutTableCell {TD} at (104,870) size 100x26 [r=8 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-9"
+          LayoutTableCell {TD} at (206,870) size 100x26 [r=8 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-9"
+        LayoutTableRow {TR} at (0,936) size 308x102
+          LayoutTableCell {TD} at (2,974) size 100x26 [r=9 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-10"
+          LayoutTableCell {TD} at (104,974) size 100x26 [r=9 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-10"
+          LayoutTableCell {TD} at (206,974) size 100x26 [r=9 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-10"
+        LayoutTableRow {TR} at (0,1040) size 308x102
+          LayoutTableCell {TD} at (2,1078) size 100x26 [r=10 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "1-11"
+          LayoutTableCell {TD} at (104,1078) size 100x26 [r=10 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "2-11"
+          LayoutTableCell {TD} at (206,1078) size 100x26 [r=10 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "3-11"
+        LayoutTableRow {TR} at (0,1185) size 308x102
+          LayoutTableCell {TD} at (2,1223) size 100x26 [r=11 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-12"
+          LayoutTableCell {TD} at (104,1223) size 100x26 [r=11 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-12"
+          LayoutTableCell {TD} at (206,1223) size 100x26 [r=11 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-12"
+        LayoutTableRow {TR} at (0,1289) size 308x102
+          LayoutTableCell {TD} at (2,1327) size 100x26 [r=12 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-13"
+          LayoutTableCell {TD} at (104,1327) size 100x26 [r=12 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-13"
+          LayoutTableCell {TD} at (206,1327) size 100x26 [r=12 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-13"
+        LayoutTableRow {TR} at (0,1393) size 308x102
+          LayoutTableCell {TD} at (2,1431) size 100x26 [r=13 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-14"
+          LayoutTableCell {TD} at (104,1431) size 100x26 [r=13 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-14"
+          LayoutTableCell {TD} at (206,1431) size 100x26 [r=13 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-14"
+        LayoutTableRow {TR} at (0,1497) size 308x102
+          LayoutTableCell {TD} at (2,1535) size 100x26 [r=14 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-15"
+          LayoutTableCell {TD} at (104,1535) size 100x26 [r=14 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-15"
+          LayoutTableCell {TD} at (206,1535) size 100x26 [r=14 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-15"
+        LayoutTableRow {TR} at (0,1601) size 308x102
+          LayoutTableCell {TD} at (2,1639) size 100x26 [r=15 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-16"
+          LayoutTableCell {TD} at (104,1639) size 100x26 [r=15 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-16"
+          LayoutTableCell {TD} at (206,1639) size 100x26 [r=15 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-16"
+        LayoutTableRow {TR} at (0,1705) size 308x102
+          LayoutTableCell {TD} at (2,1743) size 100x26 [r=16 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-17"
+          LayoutTableCell {TD} at (104,1743) size 100x26 [r=16 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-17"
+          LayoutTableCell {TD} at (206,1743) size 100x26 [r=16 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-17"
+        LayoutTableRow {TR} at (0,1809) size 308x102
+          LayoutTableCell {TD} at (2,1847) size 100x26 [r=17 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-18"
+          LayoutTableCell {TD} at (104,1847) size 100x26 [r=17 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-18"
+          LayoutTableCell {TD} at (206,1847) size 100x26 [r=17 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-18"
+        LayoutTableRow {TR} at (0,1913) size 308x102
+          LayoutTableCell {TD} at (2,1951) size 100x26 [r=18 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-19"
+          LayoutTableCell {TD} at (104,1951) size 100x26 [r=18 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-19"
+          LayoutTableCell {TD} at (206,1951) size 100x26 [r=18 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-19"
+        LayoutTableRow {TR} at (0,2017) size 308x102
+          LayoutTableCell {TD} at (2,2055) size 100x26 [r=19 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-20"
+          LayoutTableCell {TD} at (104,2055) size 100x26 [r=19 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-20"
+          LayoutTableCell {TD} at (206,2055) size 100x26 [r=19 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-20"
+        LayoutTableRow {TR} at (0,2121) size 308x102
+          LayoutTableCell {TD} at (2,2159) size 100x26 [r=20 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-21"
+          LayoutTableCell {TD} at (104,2159) size 100x26 [r=20 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-21"
+          LayoutTableCell {TD} at (206,2159) size 100x26 [r=20 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-21"
+        LayoutTableRow {TR} at (0,2225) size 308x102
+          LayoutTableCell {TD} at (2,2263) size 100x26 [r=21 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-22"
+          LayoutTableCell {TD} at (104,2263) size 100x26 [r=21 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-22"
+          LayoutTableCell {TD} at (206,2263) size 100x26 [r=21 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-22"
+        LayoutTableRow {TR} at (0,2370) size 308x102
+          LayoutTableCell {TD} at (2,2408) size 100x26 [r=22 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-23"
+          LayoutTableCell {TD} at (104,2408) size 100x26 [r=22 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-23"
+          LayoutTableCell {TD} at (206,2408) size 100x26 [r=22 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-23"
+        LayoutTableRow {TR} at (0,2474) size 308x102
+          LayoutTableCell {TD} at (2,2512) size 100x26 [r=23 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-24"
+          LayoutTableCell {TD} at (104,2512) size 100x26 [r=23 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-24"
+          LayoutTableCell {TD} at (206,2512) size 100x26 [r=23 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-24"
+        LayoutTableRow {TR} at (0,2578) size 308x102
+          LayoutTableCell {TD} at (2,2616) size 100x26 [r=24 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-25"
+          LayoutTableCell {TD} at (104,2616) size 100x26 [r=24 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-25"
+          LayoutTableCell {TD} at (206,2616) size 100x26 [r=24 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-25"
+        LayoutTableRow {TR} at (0,2682) size 308x102
+          LayoutTableCell {TD} at (2,2720) size 100x26 [r=25 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-26"
+          LayoutTableCell {TD} at (104,2720) size 100x26 [r=25 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-26"
+          LayoutTableCell {TD} at (206,2720) size 100x26 [r=25 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-26"
+        LayoutTableRow {TR} at (0,2786) size 308x102
+          LayoutTableCell {TD} at (2,2824) size 100x26 [r=26 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-27"
+          LayoutTableCell {TD} at (104,2824) size 100x26 [r=26 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-27"
+          LayoutTableCell {TD} at (206,2824) size 100x26 [r=26 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-27"
+        LayoutTableRow {TR} at (0,2890) size 308x102
+          LayoutTableCell {TD} at (2,2928) size 100x26 [r=27 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-28"
+          LayoutTableCell {TD} at (104,2928) size 100x26 [r=27 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-28"
+          LayoutTableCell {TD} at (206,2928) size 100x26 [r=27 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-28"
+        LayoutTableRow {TR} at (0,2994) size 308x102
+          LayoutTableCell {TD} at (2,3032) size 100x26 [r=28 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-29"
+          LayoutTableCell {TD} at (104,3032) size 100x26 [r=28 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-29"
+          LayoutTableCell {TD} at (206,3032) size 100x26 [r=28 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-29"
+        LayoutTableRow {TR} at (0,3185) size 308x102
+          LayoutTableCell {TD} at (2,3223) size 100x26 [r=29 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-30"
+          LayoutTableCell {TD} at (104,3223) size 100x26 [r=29 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-30"
+          LayoutTableCell {TD} at (206,3223) size 100x26 [r=29 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-30"
+        LayoutTableRow {TR} at (0,3289) size 308x102
+          LayoutTableCell {TD} at (2,3327) size 100x26 [r=30 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-31"
+          LayoutTableCell {TD} at (104,3327) size 100x26 [r=30 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-31"
+          LayoutTableCell {TD} at (206,3327) size 100x26 [r=30 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-31"
+        LayoutTableRow {TR} at (0,3393) size 308x102
+          LayoutTableCell {TD} at (2,3431) size 100x26 [r=31 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-32"
+          LayoutTableCell {TD} at (104,3431) size 100x26 [r=31 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-32"
+          LayoutTableCell {TD} at (206,3431) size 100x26 [r=31 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-32"
+        LayoutTableRow {TR} at (0,3497) size 308x102
+          LayoutTableCell {TD} at (2,3535) size 100x26 [r=32 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-33"
+          LayoutTableCell {TD} at (104,3535) size 100x26 [r=32 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-33"
+          LayoutTableCell {TD} at (206,3535) size 100x26 [r=32 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-33"
+        LayoutTableRow {TR} at (0,3601) size 308x102
+          LayoutTableCell {TD} at (2,3639) size 100x26 [r=33 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-34"
+          LayoutTableCell {TD} at (104,3639) size 100x26 [r=33 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-34"
+          LayoutTableCell {TD} at (206,3639) size 100x26 [r=33 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-34"
+        LayoutTableRow {TR} at (0,3705) size 308x102
+          LayoutTableCell {TD} at (2,3743) size 100x26 [r=34 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-35"
+          LayoutTableCell {TD} at (104,3743) size 100x26 [r=34 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-35"
+          LayoutTableCell {TD} at (206,3743) size 100x26 [r=34 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-35"
diff --git a/third_party/WebKit/LayoutTests/platform/win/printing/thead-under-multicol-expected.png b/third_party/WebKit/LayoutTests/platform/win/printing/thead-under-multicol-expected.png
new file mode 100644
index 0000000..def54a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/printing/thead-under-multicol-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/printing/thead-under-multicol-expected.txt b/third_party/WebKit/LayoutTests/platform/win/printing/thead-under-multicol-expected.txt
new file mode 100644
index 0000000..c95b25d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/printing/thead-under-multicol-expected.txt
@@ -0,0 +1,373 @@
+layer at (0,0) size 1561x1193 scrollHeight 2016
+  LayoutView at (0,0) size 1561x1193
+layer at (0,0) size 1561x2016 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutBlockFlow {HTML} at (0,0) size 1561x2016
+    LayoutBlockFlow {BODY} at (8,8) size 1545x2000
+layer at (8,8) size 1545x2000 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutBlockFlow {DIV} at (0,0) size 1545x2000
+    LayoutMultiColumnSet (anonymous) at (0,0) size 1545x2000
+layer at (8,8) size 765x3840 backgroundClip at (0,0) size 1561x1193 clip at (0,0) size 1561x1193
+  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 764.50x3840
+    LayoutTable {TABLE} at (0,0) size 302x3840
+      LayoutTableSection {THEAD} at (0,0) size 302x31
+        LayoutTableRow {TR} at (0,2) size 302x27
+          LayoutTableCell {TH} at (2,2) size 98x27 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 96x24
+              text run at (1,1) width 96: "Column 1"
+          LayoutTableCell {TH} at (102,2) size 98x27 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 96x24
+              text run at (1,1) width 96: "Column 2"
+          LayoutTableCell {TH} at (202,2) size 98x27 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 96x24
+              text run at (1,1) width 96: "Column 3"
+      LayoutTableSection {TBODY} at (0,31) size 302x3809
+        LayoutTableRow {TR} at (0,0) size 302x102
+          LayoutTableCell {TD} at (2,37) size 98x27 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-1"
+          LayoutTableCell {TD} at (102,37) size 98x27 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-1"
+          LayoutTableCell {TD} at (202,37) size 98x27 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-1"
+        LayoutTableRow {TR} at (0,104) size 302x102
+          LayoutTableCell {TD} at (2,141) size 98x27 [r=1 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-2"
+          LayoutTableCell {TD} at (102,141) size 98x27 [r=1 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-2"
+          LayoutTableCell {TD} at (202,141) size 98x27 [r=1 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-2"
+        LayoutTableRow {TR} at (0,208) size 302x102
+          LayoutTableCell {TD} at (2,245) size 98x27 [r=2 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-3"
+          LayoutTableCell {TD} at (102,245) size 98x27 [r=2 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-3"
+          LayoutTableCell {TD} at (202,245) size 98x27 [r=2 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-3"
+        LayoutTableRow {TR} at (0,312) size 302x102
+          LayoutTableCell {TD} at (2,349) size 98x27 [r=3 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-4"
+          LayoutTableCell {TD} at (102,349) size 98x27 [r=3 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-4"
+          LayoutTableCell {TD} at (202,349) size 98x27 [r=3 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-4"
+        LayoutTableRow {TR} at (0,416) size 302x102
+          LayoutTableCell {TD} at (2,453) size 98x27 [r=4 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-5"
+          LayoutTableCell {TD} at (102,453) size 98x27 [r=4 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-5"
+          LayoutTableCell {TD} at (202,453) size 98x27 [r=4 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-5"
+        LayoutTableRow {TR} at (0,520) size 302x102
+          LayoutTableCell {TD} at (2,557) size 98x27 [r=5 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-6"
+          LayoutTableCell {TD} at (102,557) size 98x27 [r=5 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-6"
+          LayoutTableCell {TD} at (202,557) size 98x27 [r=5 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-6"
+        LayoutTableRow {TR} at (0,624) size 302x102
+          LayoutTableCell {TD} at (2,661) size 98x27 [r=6 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-7"
+          LayoutTableCell {TD} at (102,661) size 98x27 [r=6 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-7"
+          LayoutTableCell {TD} at (202,661) size 98x27 [r=6 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-7"
+        LayoutTableRow {TR} at (0,728) size 302x102
+          LayoutTableCell {TD} at (2,765) size 98x27 [r=7 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-8"
+          LayoutTableCell {TD} at (102,765) size 98x27 [r=7 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-8"
+          LayoutTableCell {TD} at (202,765) size 98x27 [r=7 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-8"
+        LayoutTableRow {TR} at (0,832) size 302x102
+          LayoutTableCell {TD} at (2,869) size 98x27 [r=8 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-9"
+          LayoutTableCell {TD} at (102,869) size 98x27 [r=8 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-9"
+          LayoutTableCell {TD} at (202,869) size 98x27 [r=8 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-9"
+        LayoutTableRow {TR} at (0,936) size 302x102
+          LayoutTableCell {TD} at (2,973) size 98x27 [r=9 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-10"
+          LayoutTableCell {TD} at (102,973) size 98x27 [r=9 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-10"
+          LayoutTableCell {TD} at (202,973) size 98x27 [r=9 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-10"
+        LayoutTableRow {TR} at (0,1040) size 302x102
+          LayoutTableCell {TD} at (2,1077) size 98x27 [r=10 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "1-11"
+          LayoutTableCell {TD} at (102,1077) size 98x27 [r=10 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "2-11"
+          LayoutTableCell {TD} at (202,1077) size 98x27 [r=10 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "3-11"
+        LayoutTableRow {TR} at (0,1185) size 302x102
+          LayoutTableCell {TD} at (2,1222) size 98x27 [r=11 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-12"
+          LayoutTableCell {TD} at (102,1222) size 98x27 [r=11 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-12"
+          LayoutTableCell {TD} at (202,1222) size 98x27 [r=11 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-12"
+        LayoutTableRow {TR} at (0,1289) size 302x102
+          LayoutTableCell {TD} at (2,1326) size 98x27 [r=12 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-13"
+          LayoutTableCell {TD} at (102,1326) size 98x27 [r=12 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-13"
+          LayoutTableCell {TD} at (202,1326) size 98x27 [r=12 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-13"
+        LayoutTableRow {TR} at (0,1393) size 302x102
+          LayoutTableCell {TD} at (2,1430) size 98x27 [r=13 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-14"
+          LayoutTableCell {TD} at (102,1430) size 98x27 [r=13 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-14"
+          LayoutTableCell {TD} at (202,1430) size 98x27 [r=13 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-14"
+        LayoutTableRow {TR} at (0,1497) size 302x102
+          LayoutTableCell {TD} at (2,1534) size 98x27 [r=14 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-15"
+          LayoutTableCell {TD} at (102,1534) size 98x27 [r=14 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-15"
+          LayoutTableCell {TD} at (202,1534) size 98x27 [r=14 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-15"
+        LayoutTableRow {TR} at (0,1601) size 302x102
+          LayoutTableCell {TD} at (2,1638) size 98x27 [r=15 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-16"
+          LayoutTableCell {TD} at (102,1638) size 98x27 [r=15 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-16"
+          LayoutTableCell {TD} at (202,1638) size 98x27 [r=15 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-16"
+        LayoutTableRow {TR} at (0,1705) size 302x102
+          LayoutTableCell {TD} at (2,1742) size 98x27 [r=16 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-17"
+          LayoutTableCell {TD} at (102,1742) size 98x27 [r=16 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-17"
+          LayoutTableCell {TD} at (202,1742) size 98x27 [r=16 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-17"
+        LayoutTableRow {TR} at (0,1809) size 302x102
+          LayoutTableCell {TD} at (2,1846) size 98x27 [r=17 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-18"
+          LayoutTableCell {TD} at (102,1846) size 98x27 [r=17 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-18"
+          LayoutTableCell {TD} at (202,1846) size 98x27 [r=17 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-18"
+        LayoutTableRow {TR} at (0,1913) size 302x102
+          LayoutTableCell {TD} at (2,1950) size 98x27 [r=18 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-19"
+          LayoutTableCell {TD} at (102,1950) size 98x27 [r=18 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-19"
+          LayoutTableCell {TD} at (202,1950) size 98x27 [r=18 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-19"
+        LayoutTableRow {TR} at (0,2017) size 302x102
+          LayoutTableCell {TD} at (2,2054) size 98x27 [r=19 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-20"
+          LayoutTableCell {TD} at (102,2054) size 98x27 [r=19 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-20"
+          LayoutTableCell {TD} at (202,2054) size 98x27 [r=19 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-20"
+        LayoutTableRow {TR} at (0,2121) size 302x102
+          LayoutTableCell {TD} at (2,2158) size 98x27 [r=20 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-21"
+          LayoutTableCell {TD} at (102,2158) size 98x27 [r=20 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-21"
+          LayoutTableCell {TD} at (202,2158) size 98x27 [r=20 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-21"
+        LayoutTableRow {TR} at (0,2225) size 302x102
+          LayoutTableCell {TD} at (2,2262) size 98x27 [r=21 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-22"
+          LayoutTableCell {TD} at (102,2262) size 98x27 [r=21 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-22"
+          LayoutTableCell {TD} at (202,2262) size 98x27 [r=21 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-22"
+        LayoutTableRow {TR} at (0,2370) size 302x102
+          LayoutTableCell {TD} at (2,2407) size 98x27 [r=22 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-23"
+          LayoutTableCell {TD} at (102,2407) size 98x27 [r=22 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-23"
+          LayoutTableCell {TD} at (202,2407) size 98x27 [r=22 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-23"
+        LayoutTableRow {TR} at (0,2474) size 302x102
+          LayoutTableCell {TD} at (2,2511) size 98x27 [r=23 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-24"
+          LayoutTableCell {TD} at (102,2511) size 98x27 [r=23 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-24"
+          LayoutTableCell {TD} at (202,2511) size 98x27 [r=23 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-24"
+        LayoutTableRow {TR} at (0,2578) size 302x102
+          LayoutTableCell {TD} at (2,2615) size 98x27 [r=24 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-25"
+          LayoutTableCell {TD} at (102,2615) size 98x27 [r=24 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-25"
+          LayoutTableCell {TD} at (202,2615) size 98x27 [r=24 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-25"
+        LayoutTableRow {TR} at (0,2682) size 302x102
+          LayoutTableCell {TD} at (2,2719) size 98x27 [r=25 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-26"
+          LayoutTableCell {TD} at (102,2719) size 98x27 [r=25 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-26"
+          LayoutTableCell {TD} at (202,2719) size 98x27 [r=25 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-26"
+        LayoutTableRow {TR} at (0,2786) size 302x102
+          LayoutTableCell {TD} at (2,2823) size 98x27 [r=26 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-27"
+          LayoutTableCell {TD} at (102,2823) size 98x27 [r=26 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-27"
+          LayoutTableCell {TD} at (202,2823) size 98x27 [r=26 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-27"
+        LayoutTableRow {TR} at (0,2890) size 302x102
+          LayoutTableCell {TD} at (2,2927) size 98x27 [r=27 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-28"
+          LayoutTableCell {TD} at (102,2927) size 98x27 [r=27 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-28"
+          LayoutTableCell {TD} at (202,2927) size 98x27 [r=27 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-28"
+        LayoutTableRow {TR} at (0,2994) size 302x102
+          LayoutTableCell {TD} at (2,3031) size 98x27 [r=28 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-29"
+          LayoutTableCell {TD} at (102,3031) size 98x27 [r=28 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-29"
+          LayoutTableCell {TD} at (202,3031) size 98x27 [r=28 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-29"
+        LayoutTableRow {TR} at (0,3185) size 302x102
+          LayoutTableCell {TD} at (2,3222) size 98x27 [r=29 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-30"
+          LayoutTableCell {TD} at (102,3222) size 98x27 [r=29 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-30"
+          LayoutTableCell {TD} at (202,3222) size 98x27 [r=29 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-30"
+        LayoutTableRow {TR} at (0,3289) size 302x102
+          LayoutTableCell {TD} at (2,3326) size 98x27 [r=30 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-31"
+          LayoutTableCell {TD} at (102,3326) size 98x27 [r=30 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-31"
+          LayoutTableCell {TD} at (202,3326) size 98x27 [r=30 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-31"
+        LayoutTableRow {TR} at (0,3393) size 302x102
+          LayoutTableCell {TD} at (2,3430) size 98x27 [r=31 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-32"
+          LayoutTableCell {TD} at (102,3430) size 98x27 [r=31 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-32"
+          LayoutTableCell {TD} at (202,3430) size 98x27 [r=31 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-32"
+        LayoutTableRow {TR} at (0,3497) size 302x102
+          LayoutTableCell {TD} at (2,3534) size 98x27 [r=32 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-33"
+          LayoutTableCell {TD} at (102,3534) size 98x27 [r=32 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-33"
+          LayoutTableCell {TD} at (202,3534) size 98x27 [r=32 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-33"
+        LayoutTableRow {TR} at (0,3601) size 302x102
+          LayoutTableCell {TD} at (2,3638) size 98x27 [r=33 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-34"
+          LayoutTableCell {TD} at (102,3638) size 98x27 [r=33 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-34"
+          LayoutTableCell {TD} at (202,3638) size 98x27 [r=33 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-34"
+        LayoutTableRow {TR} at (0,3705) size 302x102
+          LayoutTableCell {TD} at (2,3742) size 98x27 [r=34 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-35"
+          LayoutTableCell {TD} at (102,3742) size 98x27 [r=34 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-35"
+          LayoutTableCell {TD} at (202,3742) size 98x27 [r=34 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-35"
diff --git a/third_party/WebKit/LayoutTests/printing/thead-under-multicol.html b/third_party/WebKit/LayoutTests/printing/thead-under-multicol.html
new file mode 100644
index 0000000..01e0c70
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/printing/thead-under-multicol.html
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<title>Table header groups under multicol should just repeat in columns.</title>
+<style>
+    table {font-family: Helvetica, Arial, Verdana; font-size: 16pt;}
+    td {height: 100px;}
+</style>
+<script>
+    if (window.testRunner)
+        testRunner.setPrinting();
+</script>
+<div style="columns: 2; height: 2000px; column-fill: auto">
+<table>
+<thead style="break-inside: avoid">
+    <tr>
+        <th>Column 1</th>
+        <th>Column 2</th>
+        <th>Column 3</th>
+    </tr>
+</thead>
+<tbody>
+    <tr>
+        <td>1-1</td>
+        <td>2-1</td>
+        <td>3-1</td>
+    </tr>
+    <tr>
+        <td>1-2</td>
+        <td>2-2</td>
+        <td>3-2</td>
+    </tr>
+    <tr>
+        <td>1-3</td>
+        <td>2-3</td>
+        <td>3-3</td>
+    </tr>
+    <tr>
+        <td>1-4</td>
+        <td>2-4</td>
+        <td>3-4</td>
+    </tr>
+    <tr>
+        <td>1-5</td>
+        <td>2-5</td>
+        <td>3-5</td>
+    </tr>
+    <tr>
+        <td>1-6</td>
+        <td>2-6</td>
+        <td>3-6</td>
+    </tr>
+    <tr>
+        <td>1-7</td>
+        <td>2-7</td>
+        <td>3-7</td>
+    </tr>
+    <tr>
+        <td>1-8</td>
+        <td>2-8</td>
+        <td>3-8</td>
+    </tr>
+    <tr>
+        <td>1-9</td>
+        <td>2-9</td>
+        <td>3-9</td>
+    </tr>
+    <tr>
+        <td>1-10</td>
+        <td>2-10</td>
+        <td>3-10</td>
+    </tr>
+    <tr>
+        <td>1-11</td>
+        <td>2-11</td>
+        <td>3-11</td>
+    </tr>
+    <tr>
+        <td>1-12</td>
+        <td>2-12</td>
+        <td>3-12</td>
+    </tr>
+    <tr>
+        <td>1-13</td>
+        <td>2-13</td>
+        <td>3-13</td>
+    </tr>
+    <tr>
+        <td>1-14</td>
+        <td>2-14</td>
+        <td>3-14</td>
+    </tr>
+    <tr>
+        <td>1-15</td>
+        <td>2-15</td>
+        <td>3-15</td>
+    </tr>
+    <tr>
+        <td>1-16</td>
+        <td>2-16</td>
+        <td>3-16</td>
+    </tr>
+    <tr>
+        <td>1-17</td>
+        <td>2-17</td>
+        <td>3-17</td>
+    </tr>
+    <tr>
+        <td>1-18</td>
+        <td>2-18</td>
+        <td>3-18</td>
+    </tr>
+    <tr>
+        <td>1-19</td>
+        <td>2-19</td>
+        <td>3-19</td>
+    </tr>
+    <tr>
+        <td>1-20</td>
+        <td>2-20</td>
+        <td>3-20</td>
+    </tr>
+    <tr>
+        <td>1-21</td>
+        <td>2-21</td>
+        <td>3-21</td>
+    </tr>
+    <tr>
+        <td>1-22</td>
+        <td>2-22</td>
+        <td>3-22</td>
+    </tr>
+    <tr>
+        <td>1-23</td>
+        <td>2-23</td>
+        <td>3-23</td>
+    </tr>
+    <tr>
+        <td>1-24</td>
+        <td>2-24</td>
+        <td>3-24</td>
+    </tr>
+    <tr>
+        <td>1-25</td>
+        <td>2-25</td>
+        <td>3-25</td>
+    </tr>
+    <tr>
+        <td>1-26</td>
+        <td>2-26</td>
+        <td>3-26</td>
+    </tr>
+    <tr>
+        <td>1-27</td>
+        <td>2-27</td>
+        <td>3-27</td>
+    </tr>
+    <tr>
+        <td>1-28</td>
+        <td>2-28</td>
+        <td>3-28</td>
+    </tr>
+    <tr>
+        <td>1-29</td>
+        <td>2-29</td>
+        <td>3-29</td>
+    </tr>
+    <tr>
+        <td>1-30</td>
+        <td>2-30</td>
+        <td>3-30</td>
+    </tr>
+    <tr>
+        <td>1-31</td>
+        <td>2-31</td>
+        <td>3-31</td>
+    </tr>
+    <tr>
+        <td>1-32</td>
+        <td>2-32</td>
+        <td>3-32</td>
+    </tr>
+    <tr>
+        <td>1-33</td>
+        <td>2-33</td>
+        <td>3-33</td>
+    </tr>
+    <tr>
+        <td>1-34</td>
+        <td>2-34</td>
+        <td>3-34</td>
+    </tr>
+    <tr>
+        <td>1-35</td>
+        <td>2-35</td>
+        <td>3-35</td>
+    </tr>
+</tbody>
+</table>
+</div>
+
diff --git a/third_party/WebKit/LayoutTests/security/lazy-event-listener-expected.txt b/third_party/WebKit/LayoutTests/security/lazy-event-listener-expected.txt
index be1981c..0b63146 100644
--- a/third_party/WebKit/LayoutTests/security/lazy-event-listener-expected.txt
+++ b/third_party/WebKit/LayoutTests/security/lazy-event-listener-expected.txt
@@ -1,2 +1,2 @@
-CONSOLE ERROR: line 3: Uncaught SyntaxError: Single function literal required
+CONSOLE ERROR: line 2: Uncaught SyntaxError: Unexpected token }
 Test passes if it doesn't crash.
diff --git a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-normalization/normalize-numeric.html b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-normalization/normalize-numeric.html
index 7817161..8571514 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-normalization/normalize-numeric.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-normalization/normalize-numeric.html
@@ -10,6 +10,7 @@
 'use strict';
 
 function test_numeric_normalization(test, property, cssText, expected) {
+  assert_style_value_equals(CSSNumericValue.parse(cssText), expected);
   assert_style_value_equals(CSSStyleValue.parse(property, cssText), expected);
   assert_style_value_equals(
       createInlineStyleMap(test, property + ': ' + cssText).get(property),
@@ -29,10 +30,6 @@
 }, 'Normalizing a <dimension> returns a CSSUnitValue with the correct unit');
 
 test(t => {
-  test_numeric_normalization(t, 'width', '0', CSS.px(0));
-}, 'Normalizing a <dimension> with a unitless zero returns 0px');
-
-test(t => {
   test_numeric_normalization(t, 'z-index', '0', CSS.number(0));
 }, 'Normalizing a <number> with a unitless zero returns 0');
 
@@ -42,4 +39,11 @@
       new CSSMathSum(CSS.px(4), CSS.percent(1)));
 }, 'Normalizing a <calc> returns simplified expression');
 
+test(t => {
+  assert_style_value_equals(CSSStyleValue.parse('width', '0px'), CSS.px(0));
+  assert_style_value_equals(
+      createInlineStyleMap(t, 'width: 0').get('width'),
+      CSS.px(0));
+}, 'Normalizing a <dimension> with a unitless zero returns 0px');
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/numeric-objects/parse.html b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/numeric-objects/parse.html
index e229f76..0aff038 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/numeric-objects/parse.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/numeric-objects/parse.html
@@ -9,99 +9,15 @@
 
 test(() => {
   assert_throws(new SyntaxError(), () => CSSNumericValue.parse('%#('));
-  assert_throws(new SyntaxError(), () => CSSNumericValue.parse('auto'));
-  assert_throws(new SyntaxError(), () => CSSNumericValue.parse('1 2'));
 }, 'Parsing an invalid string throws SyntaxError');
 
 test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('-3.14'),
-      CSS.number(-3.14));
-}, 'Parsing a <number-token> returns a number CSSUnitValue');
+  assert_throws(new SyntaxError(), () => CSSNumericValue.parse('auto'));
+}, 'Parsing a string with a non numeric token throws SyntaxError');
 
 test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('-3.14%'),
-      CSS.percent(-3.14));
-}, 'Parsing a <percentage-token> returns a percent CSSUnitValue');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('-3.14px'),
-      CSS.px(-3.14));
-}, 'Parsing a <dimension-token> returns a CSSUnitValue with correct unit');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('0'),
-      CSS.number(0));
-}, 'Parsing a unitless zero returns zero');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1)'),
-      new CSSMathSum(1));
-}, 'Parsing a calc with only one argument returns a CSSMathSum with that argument');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 + 1)'),
-      new CSSMathSum(1, 1));
-}, 'Parsing a calc with addition returns a CSSMathSum');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 - 1)'),
-      new CSSMathSum(1, new CSSMathNegate(1)));
-}, 'Parsing a calc with subtraction returns a CSSMathSum with negated argument');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 * 1)'),
-      new CSSMathProduct(1, 1));
-}, 'Parsing a calc with multiplication returns a CSSMathProduct');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 / 1)'),
-      new CSSMathProduct(1, new CSSMathInvert(1)));
-}, 'Parsing a calc with division returns a CSSMathProduct with inverted argument');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 + 2 - 3 + 4)'),
-      new CSSMathSum(1, 2, new CSSMathNegate(3), 4));
-}, 'Parsing a calc with n-ary addition and subtraction returns a flat CSSMathSum');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 * 2 / 3 * 4)'),
-      new CSSMathProduct(1, 2, new CSSMathInvert(3), 4));
-}, 'Parsing a calc with n-ary multiplication and division returns a flat CSSMathProduct');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(calc(1 + 2) + 3)'),
-      new CSSMathSum(new CSSMathSum(1, 2), 3));
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 + calc(2 + 3))'),
-      new CSSMathSum(1, new CSSMathSum(2, 3)));
-}, 'Parsing a calc with nested sum returns nested CSSMathSum');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(calc(1 * 2) * 3)'),
-      new CSSMathProduct(new CSSMathProduct(1, 2), 3));
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(1 * calc(2 * 3))'),
-      new CSSMathProduct(1, new CSSMathProduct(2, 3)));
-}, 'Parsing a calc with nested product returns nested CSSMathProduct');
-
-test(() => {
-  assert_style_value_equals(
-      CSSNumericValue.parse('calc(calc(1px * 2) + 3%)'),
-      new CSSMathSum(new CSSMathProduct(CSS.px(1), 2), CSS.percent(3)));
-}, 'Parsing a calc with mixed compatible units returns correct CSSMathValue');
+  assert_throws(new SyntaxError(), () => CSSNumericValue.parse('1 2'));
+}, 'Parsing a string with left over numeric tokens throws SyntaxError');
 
 test(() => {
   assert_throws(new SyntaxError(), () => CSSNumericValue.parse('calc(calc(1px * 2s) + 3%)'));
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/README.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/README.txt
new file mode 100644
index 0000000..c68ac05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/README.txt
@@ -0,0 +1 @@
+# This suite runs tests with --enable-slimming-paint-v175
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/absolute-position-headers-and-footers-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/absolute-position-headers-and-footers-expected.txt
new file mode 100644
index 0000000..8c8af57
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/absolute-position-headers-and-footers-expected.txt
@@ -0,0 +1,243 @@
+layer at (0,0) size 800x600 scrollHeight 2685
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2685 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2685
+    LayoutBlockFlow {BODY} at (8,16) size 1030x2653
+      LayoutBlockFlow {P} at (0,0) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,36) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,72) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,108) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,144) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,180) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,216) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,252) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,288) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,324) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,360) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,396) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,432) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,468) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,504) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,540) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,576) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,612) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,648) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,684) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,720) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,756) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,783) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,819) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,855) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,891) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,927) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,963) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,999) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1035) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1071) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1107) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1143) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1179) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1215) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1251) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1287) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1323) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1359) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1395) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1431) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1467) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1503) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1539) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1582) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1618) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1654) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1690) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1726) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1762) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1798) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1834) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1870) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1906) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1942) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1978) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2014) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2050) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2086) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2122) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2158) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2194) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2230) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2266) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2302) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2338) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2381) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2417) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2453) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2489) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2525) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2561) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2597) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2633) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+layer at (8,0) size 606x38
+  LayoutBlockFlow (positioned) {DIV} at (8,0) size 606x38
+    LayoutBlockFlow {DIV} at (0,0) size 606x30
+      LayoutBlockFlow (anonymous) at (0,0) size 606x20
+        LayoutText {#text} at (0,0) size 606x19
+          text run at (0,0) width 606: "crbug.com/303728: Header Line is absolute positioned so should not be repeated on every page."
+layer at (8,28) size 606x2 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,28) size 606x2 [border: (1px inset #EEEEEE)]
+layer at (8,761) size 601x38 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) {DIV} at (8,761) size 601x38
+    LayoutBlockFlow {DIV} at (0,8) size 601x30
+      LayoutBlockFlow (anonymous) at (0,10) size 601x20
+        LayoutText {#text} at (0,0) size 601x19
+          text run at (0,0) width 601: "crbug.com/303728: Footer Line is absolute positioned so should not be repeated on every page."
+layer at (8,769) size 601x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,0) size 601x2 [border: (1px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/ellipsis-printing-style-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/ellipsis-printing-style-expected.txt
new file mode 100644
index 0000000..5560839
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/ellipsis-printing-style-expected.txt
@@ -0,0 +1,9 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x40 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x40
+    LayoutBlockFlow {BODY} at (8,8) size 1050x24
+layer at (8,8) size 168x24 scrollWidth 1216
+  LayoutBlockFlow {DIV} at (0,0) size 168x24 [color=#FFFFFF] [bgcolor=#000000]
+    LayoutText {#text} at (0,0) size 1216x16
+      text run at (0,0) width 1216: "This text should be ellipsized and the ellipsis should visible when printed."
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-but-static-headers-and-footers-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-but-static-headers-and-footers-expected.txt
new file mode 100644
index 0000000..e6a2b11
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-but-static-headers-and-footers-expected.txt
@@ -0,0 +1,243 @@
+layer at (0,0) size 800x600 scrollHeight 2685
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2685 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2685
+    LayoutBlockFlow {BODY} at (8,16) size 1030x2653
+      LayoutBlockFlow {P} at (0,0) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,36) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,72) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,108) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,144) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,180) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,216) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,252) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,288) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,324) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,360) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,396) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,432) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,468) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,504) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,540) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,576) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,612) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,648) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,684) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,720) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,756) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,783) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,819) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,855) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,891) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,927) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,963) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,999) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1035) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1071) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1107) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1143) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1179) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1215) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1251) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1287) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1323) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1359) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1395) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1431) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1467) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1503) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1539) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1582) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1618) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1654) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1690) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1726) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1762) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1798) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1834) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1870) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1906) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1942) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1978) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2014) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2050) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2086) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2122) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2158) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2194) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2230) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2266) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2302) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2338) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2381) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2417) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2453) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2489) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2525) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2561) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2597) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2633) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+layer at (8,16) size 667x38
+  LayoutBlockFlow (positioned) {DIV} at (8,16) size 667x38
+    LayoutBlockFlow {DIV} at (0,0) size 667x30
+      LayoutBlockFlow (anonymous) at (0,0) size 667x20
+        LayoutText {#text} at (0,0) size 667x19
+          text run at (0,0) width 667: "crbug.com/303728: Fixed-position header Line is statically positioned and will be repeated on every page."
+layer at (8,44) size 667x2 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,28) size 667x2 [border: (1px inset #EEEEEE)]
+layer at (8,2685) size 613x38 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) {DIV} at (8,2685) size 613x38
+    LayoutBlockFlow {DIV} at (0,8) size 613x30
+      LayoutBlockFlow (anonymous) at (0,10) size 613x20
+        LayoutText {#text} at (0,0) size 613x19
+          text run at (0,0) width 613: "crbug.com/303728: Footer Line is statically positioned and should not be repeated on every page."
+layer at (8,2693) size 613x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,0) size 613x2 [border: (1px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-absolute-covering-some-pages-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-absolute-covering-some-pages-expected.txt
new file mode 100644
index 0000000..c10310a5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-absolute-covering-some-pages-expected.txt
@@ -0,0 +1,19 @@
+layer at (0,0) size 800x600 scrollHeight 5016
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x5016 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x5016
+    LayoutBlockFlow {BODY} at (8,8) size 1030x5000
+      LayoutBlockFlow {DIV} at (0,0) size 1030x5000
+layer at (0,0) size 510x68
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 510x68 [border: (5px solid #000000)]
+    LayoutBlockFlow {DIV} at (5,5) size 500x50
+      LayoutBlockFlow (anonymous) at (0,0) size 500x40
+        LayoutText {#text} at (0,0) size 466x39
+          text run at (0,0) width 466: "crbug.com/303728: Header Line should be repeated on every page except"
+          text run at (0,20) width 377: "where it's clipped by the absolute element on pages 3 and 4."
+layer at (5,53) size 500x2 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,48) size 500x2 [border: (1px inset #EEEEEE)]
+layer at (0,1000) size 600x2000 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,1000) size 600x2000 [bgcolor=#000000]
+    LayoutText zI: 2 {#text} at (0,0) size 57x19
+      text run at (0,0) width 57: "Absolute"
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-clipped-expected.png b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-clipped-expected.png
new file mode 100644
index 0000000..38d3235
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-clipped-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-clipped-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-clipped-expected.txt
new file mode 100644
index 0000000..6b18463
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-clipped-expected.txt
@@ -0,0 +1,234 @@
+layer at (0,0) size 800x600 scrollHeight 2685
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2685 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2685
+    LayoutBlockFlow {BODY} at (8,16) size 1030x2653
+      LayoutBlockFlow {P} at (0,0) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,36) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,72) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,108) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,144) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,180) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,216) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,252) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,288) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,324) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,360) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,396) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,432) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,468) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,504) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,540) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,576) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,612) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,648) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,684) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,720) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,756) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,783) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,819) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,855) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,891) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,927) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,963) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,999) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1035) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1071) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1107) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1143) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1179) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1215) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1251) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1287) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1323) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1359) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1395) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1431) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1467) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1503) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1539) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1582) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1618) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1654) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1690) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1726) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1762) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1798) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1834) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1870) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1906) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1942) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1978) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2014) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2050) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2086) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2122) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2158) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2194) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2230) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2266) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2302) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2338) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2381) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2417) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2453) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2489) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2525) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2561) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2597) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2633) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+layer at (8,0) size 0x0
+  LayoutBlockFlow (positioned) {DIV} at (8,0) size 0x0
+layer at (8,0) size 986x22 backgroundClip at (8,0) size 400x50 clip at (8,0) size 400x50
+  LayoutBlockFlow (positioned) {DIV} at (8,0) size 986x22 [border: (1px solid #000000)]
+    LayoutBlockFlow {DIV} at (1,1) size 984x20
+      LayoutText {#text} at (0,0) size 984x19
+        text run at (0,0) width 984: "crbug.com/303728: Clipped header Line is inside absolute element positioned at top of page so should only appear on first page and should be clipped there."
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-expected.txt
new file mode 100644
index 0000000..72829d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-expected.txt
@@ -0,0 +1,243 @@
+layer at (0,0) size 800x600 scrollHeight 2685
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2685 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2685
+    LayoutBlockFlow {BODY} at (8,16) size 1030x2653
+      LayoutBlockFlow {P} at (0,0) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,36) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,72) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,108) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,144) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,180) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,216) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,252) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,288) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,324) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,360) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,396) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,432) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,468) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,504) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,540) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,576) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,612) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,648) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,684) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,720) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,756) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,783) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,819) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,855) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,891) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,927) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,963) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,999) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1035) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1071) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1107) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1143) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1179) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1215) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1251) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1287) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1323) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1359) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1395) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1431) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1467) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1503) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1539) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1582) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1618) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1654) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1690) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1726) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1762) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1798) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1834) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1870) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1906) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1942) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1978) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2014) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2050) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2086) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2122) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2158) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2194) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2230) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2266) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2302) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2338) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2381) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2417) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2453) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2489) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2525) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2561) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2597) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2633) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+layer at (8,0) size 516x38
+  LayoutBlockFlow (positioned) {DIV} at (8,0) size 516x38
+    LayoutBlockFlow {DIV} at (0,0) size 516x30
+      LayoutBlockFlow (anonymous) at (0,0) size 516x20
+        LayoutText {#text} at (0,0) size 516x19
+          text run at (0,0) width 516: "crbug.com/303728: Fixed-position header Line should be repeated on every page."
+layer at (8,28) size 516x2 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,28) size 516x2 [border: (1px inset #EEEEEE)]
+layer at (8,761) size 420x38 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) {DIV} at (8,761) size 420x38
+    LayoutBlockFlow {DIV} at (0,8) size 420x30
+      LayoutBlockFlow (anonymous) at (0,10) size 420x20
+        LayoutText {#text} at (0,0) size 420x19
+          text run at (0,0) width 420: "crbug.com/303728: Footer Line should be repeated on every page."
+layer at (8,769) size 420x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,0) size 420x2 [border: (1px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-inside-transform-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-inside-transform-expected.txt
new file mode 100644
index 0000000..a312cca92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-inside-transform-expected.txt
@@ -0,0 +1,247 @@
+layer at (0,0) size 800x600 scrollHeight 2685
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2685 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2685
+    LayoutBlockFlow {BODY} at (8,16) size 1030x2653
+      LayoutBlockFlow {P} at (0,0) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,36) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,72) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,108) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,144) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,180) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,216) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,252) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,288) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,324) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,360) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,396) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,432) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,468) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,504) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,540) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,576) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,612) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,648) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,684) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,720) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,756) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,783) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,819) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,855) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,891) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,927) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,963) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,999) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1035) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1071) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1107) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1143) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1179) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1215) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1251) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1287) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1323) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1359) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1395) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1431) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1467) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1503) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1539) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1582) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1618) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1654) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1690) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1726) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1762) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1798) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1834) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1870) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1906) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1942) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1978) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2014) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2050) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2086) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2122) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2158) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2194) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2230) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2266) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2302) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2338) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2381) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2417) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2453) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2489) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2525) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2561) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2597) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2633) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+layer at (8,16) size 1030x0
+  LayoutBlockFlow {DIV} at (0,0) size 1030x0
+layer at (8,16) size 449x38
+  LayoutBlockFlow (positioned) {DIV} at (0,0) size 449x38
+    LayoutBlockFlow {DIV} at (0,0) size 449x30
+      LayoutBlockFlow (anonymous) at (0,0) size 449x20
+        LayoutText {#text} at (0,0) size 449x19
+          text run at (0,0) width 449: "crbug.com/303728: Header Line should not be repeated on every page."
+layer at (8,44) size 449x2 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,28) size 449x2 [border: (1px inset #EEEEEE)]
+layer at (8,2685) size 1030x0
+  LayoutBlockFlow {DIV} at (0,2669) size 1030x0
+layer at (8,2647) size 444x38 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) {DIV} at (0,-38) size 444x38
+    LayoutBlockFlow {DIV} at (0,8) size 444x30
+      LayoutBlockFlow (anonymous) at (0,10) size 444x20
+        LayoutText {#text} at (0,0) size 444x19
+          text run at (0,0) width 444: "crbug.com/303728: Footer Line should not be repeated on every page."
+layer at (8,2655) size 444x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,0) size 444x2 [border: (1px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-larger-than-page-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-larger-than-page-expected.txt
new file mode 100644
index 0000000..01ffa2e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/fixed-positioned-headers-and-footers-larger-than-page-expected.txt
@@ -0,0 +1,243 @@
+layer at (0,0) size 800x600 scrollHeight 2685
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2685 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2685
+    LayoutBlockFlow {BODY} at (8,16) size 1030x2653
+      LayoutBlockFlow {P} at (0,0) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,36) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,72) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,108) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,144) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,180) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,216) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,252) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,288) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,324) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,360) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,396) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,432) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,468) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,504) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,540) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,576) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,612) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,648) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,684) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,720) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,756) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,783) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,819) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,855) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,891) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,927) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,963) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,999) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1035) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1071) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1107) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1143) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1179) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1215) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1251) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1287) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1323) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1359) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1395) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1431) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1467) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1503) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1539) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1582) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1618) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1654) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1690) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1726) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1762) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1798) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1834) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1870) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1906) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1942) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,1978) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2014) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2050) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2086) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2122) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2158) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2194) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2230) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2266) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2302) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2338) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2381) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2417) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2453) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2489) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2525) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2561) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2597) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+      LayoutBlockFlow {P} at (0,2633) size 1030x20
+        LayoutText {#text} at (0,0) size 66x19
+          text run at (0,0) width 66: "Filler lines"
+layer at (8,0) size 2010x48 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) {DIV} at (8,0) size 2010x48 [border: (5px solid #000000)]
+    LayoutBlockFlow {DIV} at (5,5) size 2000x30
+      LayoutBlockFlow (anonymous) at (0,0) size 2000x20
+        LayoutText {#text} at (0,0) size 696x19
+          text run at (0,0) width 696: "crbug.com/303728: Footer Line should be repeated on every page and should be clipped because it's too wide."
+layer at (13,33) size 2000x2 backgroundClip at (13,33) size 787x2 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,28) size 2000x2 [border: (1px inset #EEEEEE)]
+layer at (8,751) size 2010x48 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow (positioned) {DIV} at (8,751) size 2010x48 [border: (5px solid #000000)]
+    LayoutBlockFlow {DIV} at (5,13) size 2000x30
+      LayoutBlockFlow (anonymous) at (0,10) size 2000x20
+        LayoutText {#text} at (0,0) size 696x19
+          text run at (0,0) width 696: "crbug.com/303728: Footer Line should be repeated on every page and should be clipped because it's too wide."
+layer at (13,764) size 2000x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutBlockFlow {HR} at (0,0) size 2000x2 [border: (1px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/forced-break-tree-dump-only-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/forced-break-tree-dump-only-expected.txt
new file mode 100644
index 0000000..f08711c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/forced-break-tree-dump-only-expected.txt
@@ -0,0 +1,18 @@
+layer at (0,0) size 800x600 scrollHeight 827
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x827 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x827
+    LayoutBlockFlow {BODY} at (8,16) size 1050x803
+      LayoutBlockFlow {P} at (0,0) size 1050x40
+        LayoutText {#text} at (0,0) size 1010x39
+          text run at (0,0) width 554: "This is a test that only dumps the layout tree, and doesn't actually display the page. This "
+          text run at (554,0) width 456: "tests some peculiarities in the test framework for printing. To run this test"
+          text run at (0,20) width 102: "manually, run it "
+          text run at (101,20) width 221: "with content_shell --run-layout-test"
+      LayoutBlockFlow {DIV} at (0,56) size 1050x20
+        LayoutText {#text} at (0,0) size 163x19
+          text run at (0,0) width 163: "This should be on page 1."
+      LayoutBlockFlow {DIV} at (0,783) size 1050x20
+        LayoutText {#text} at (0,0) size 163x19
+          text run at (0,0) width 163: "This should be on page 2."
+
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/iframe-print-expected.png b/third_party/WebKit/LayoutTests/virtual/spv175/printing/iframe-print-expected.png
new file mode 100644
index 0000000..47fe9613
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/iframe-print-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/iframe-print-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/iframe-print-expected.txt
new file mode 100644
index 0000000..6fe1690
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/iframe-print-expected.txt
@@ -0,0 +1,41 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x799 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x799
+    LayoutBlockFlow {BODY} at (8,8) size 1050x783
+      LayoutText {#text} at (304,289) size 4x19
+        text run at (304,289) width 4: " "
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,208) size 304x104
+  LayoutIFrame {IFRAME} at (0,200) size 304x104 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x100
+      LayoutView at (0,0) size 300x100
+    layer at (0,0) size 300x36
+      LayoutBlockFlow {HTML} at (0,0) size 300x36
+        LayoutBlockFlow {BODY} at (8,8) size 284x20
+          LayoutText {#text} at (0,0) size 241x19
+            text run at (0,0) width 241: "You should see this text when printed."
+layer at (316,8) size 304x304
+  LayoutIFrame {IFRAME} at (308,0) size 304x304 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x300
+      LayoutView at (0,0) size 300x300
+    layer at (35,0) size 265x300
+      LayoutBlockFlow {HTML} at (0,0) size 265x300
+        LayoutBlockFlow {BODY} at (8,8) size 249x284
+          LayoutText {#text} at (0,0) size 19x245
+            text run at (0,0) width 245: "You should see this text when printed. "
+          LayoutBR {BR} at (0,244) size 19x1
+          LayoutText {#text} at (20,0) size 19x160
+            text run at (20,0) width 160: "Vertical text on the right. "
+          LayoutBR {BR} at (20,159) size 19x1
+          LayoutText {#text} at (0,0) size 0x0
+    layer at (48,8) size 204x154
+      LayoutIFrame {IFRAME} at (40,0) size 204x154 [border: (2px inset #EEEEEE)]
+        layer at (0,0) size 200x150
+          LayoutView at (0,0) size 200x150
+        layer at (0,0) size 200x56
+          LayoutBlockFlow {HTML} at (0,0) size 200x56
+            LayoutBlockFlow {BODY} at (8,8) size 184x40
+              LayoutText {#text} at (0,0) size 150x39
+                text run at (0,0) width 150: "You should see this text"
+                text run at (0,20) width 87: "when printed."
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/list-item-with-empty-first-line-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/list-item-with-empty-first-line-expected.txt
new file mode 100644
index 0000000..6476598
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/list-item-with-empty-first-line-expected.txt
@@ -0,0 +1,18 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x120 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x120
+    LayoutBlockFlow {BODY} at (8,8) size 1050x96
+      LayoutBlockFlow (anonymous) at (0,0) size 1050x20
+        LayoutText {#text} at (0,0) size 408x19
+          text run at (0,0) width 408: "Passes if both 'first' (with a line break) and 'second' have a bullet."
+      LayoutBlockFlow {UL} at (0,36) size 1050x60
+        LayoutListItem {LI} at (40,0) size 1010x40
+          LayoutListMarker (anonymous) at (-18,0) size 7x19: bullet
+          LayoutBR {BR} at (0,0) size 0x19
+          LayoutText {#text} at (0,20) size 24x19
+            text run at (0,20) width 24: "first"
+        LayoutListItem {LI} at (40,40) size 1010x20
+          LayoutListMarker (anonymous) at (-18,0) size 7x19: bullet
+          LayoutText {#text} at (0,0) size 44x19
+            text run at (0,0) width 44: "second"
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/quirks-percentage-height-body-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/quirks-percentage-height-body-expected.txt
new file mode 100644
index 0000000..1f9261b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/quirks-percentage-height-body-expected.txt
@@ -0,0 +1,5 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x799 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x799
+    LayoutBlockFlow {BODY} at (0,0) size 543x409.50 [border: (5px solid #FA8072)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/quirks-percentage-height-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/quirks-percentage-height-expected.txt
new file mode 100644
index 0000000..00065cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/quirks-percentage-height-expected.txt
@@ -0,0 +1,6 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x799 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x799
+    LayoutBlockFlow {BODY} at (0,0) size 1066x799
+      LayoutBlockFlow {DIV} at (0,0) size 543x409.50 [border: (5px solid #FA8072)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/simultaneous-position-float-change-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/simultaneous-position-float-change-expected.txt
new file mode 100644
index 0000000..d7c4f91f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/simultaneous-position-float-change-expected.txt
@@ -0,0 +1,7 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x799 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x799
+    LayoutBlockFlow {BODY} at (8,8) size 1050x783
+layer at (8,8) size 0x0
+  LayoutBlockFlow (positioned) {DIV} at (8,8) size 0x0
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/standards-percentage-heights-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/standards-percentage-heights-expected.txt
new file mode 100644
index 0000000..c9957e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/standards-percentage-heights-expected.txt
@@ -0,0 +1,5 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 510x510
+  LayoutBlockFlow {HTML} at (0,0) size 510x510 [border: (5px solid #FFC0CB)]
+    LayoutBlockFlow {BODY} at (5,5) size 260x260 [border: (5px solid #FA8072)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/subframes-percentage-height-expected.png b/third_party/WebKit/LayoutTests/virtual/spv175/printing/subframes-percentage-height-expected.png
new file mode 100644
index 0000000..60622f22
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/subframes-percentage-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/subframes-percentage-height-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/subframes-percentage-height-expected.txt
new file mode 100644
index 0000000..235a5a19
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/subframes-percentage-height-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 1066x799
+layer at (0,0) size 1066x400 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1066x400
+    LayoutBlockFlow {BODY} at (0,0) size 1066x400
+      LayoutText {#text} at (0,0) size 0x0
+layer at (0,0) size 300x150
+  LayoutIFrame {IFRAME} at (0,0) size 300x150
+    layer at (0,0) size 300x150
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 300x150
+      LayoutBlockFlow {HTML} at (0,0) size 300x150
+        LayoutBlockFlow {BODY} at (0,0) size 300x150
+          LayoutBlockFlow {DIV} at (0,0) size 300x150 [border: (10px solid #0000FF)]
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/tfoot-repeats-at-bottom-of-each-page-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/tfoot-repeats-at-bottom-of-each-page-expected.txt
new file mode 100644
index 0000000..3027f1cd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/tfoot-repeats-at-bottom-of-each-page-expected.txt
@@ -0,0 +1,379 @@
+layer at (0,0) size 800x600 scrollHeight 1542
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x1542 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x1542
+    LayoutBlockFlow {BODY} at (0,0) size 1046x1542
+      LayoutTable {TABLE} at (0,0) size 447x1542
+        LayoutTableSection {THEAD} at (0,0) size 447x40
+          LayoutTableRow {TR} at (0,0) size 447x40
+            LayoutTableCell {TH} at (0,0) size 149x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 1"
+            LayoutTableCell {TH} at (149,0) size 149x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 2"
+            LayoutTableCell {TH} at (298,0) size 149x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 3"
+        LayoutTableSection {TBODY} at (0,40) size 447x1462
+          LayoutTableRow {TR} at (0,0) size 447x39
+            LayoutTableCell {TD} at (0,0) size 149x39 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-1"
+            LayoutTableCell {TD} at (149,0) size 149x39 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-1"
+            LayoutTableCell {TD} at (298,0) size 149x39 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-1"
+          LayoutTableRow {TR} at (0,39) size 447x39
+            LayoutTableCell {TD} at (0,39) size 149x39 [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-2"
+            LayoutTableCell {TD} at (149,39) size 149x39 [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-2"
+            LayoutTableCell {TD} at (298,39) size 149x39 [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-2"
+          LayoutTableRow {TR} at (0,78) size 447x39
+            LayoutTableCell {TD} at (0,78) size 149x39 [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-3"
+            LayoutTableCell {TD} at (149,78) size 149x39 [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-3"
+            LayoutTableCell {TD} at (298,78) size 149x39 [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-3"
+          LayoutTableRow {TR} at (0,117) size 447x39
+            LayoutTableCell {TD} at (0,117) size 149x39 [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-4"
+            LayoutTableCell {TD} at (149,117) size 149x39 [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-4"
+            LayoutTableCell {TD} at (298,117) size 149x39 [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-4"
+          LayoutTableRow {TR} at (0,156) size 447x39
+            LayoutTableCell {TD} at (0,156) size 149x39 [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-5"
+            LayoutTableCell {TD} at (149,156) size 149x39 [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-5"
+            LayoutTableCell {TD} at (298,156) size 149x39 [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-5"
+          LayoutTableRow {TR} at (0,195) size 447x39
+            LayoutTableCell {TD} at (0,195) size 149x39 [r=5 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-6"
+            LayoutTableCell {TD} at (149,195) size 149x39 [r=5 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-6"
+            LayoutTableCell {TD} at (298,195) size 149x39 [r=5 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-6"
+          LayoutTableRow {TR} at (0,234) size 447x39
+            LayoutTableCell {TD} at (0,234) size 149x39 [r=6 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-7"
+            LayoutTableCell {TD} at (149,234) size 149x39 [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-7"
+            LayoutTableCell {TD} at (298,234) size 149x39 [r=6 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-7"
+          LayoutTableRow {TR} at (0,273) size 447x39
+            LayoutTableCell {TD} at (0,273) size 149x39 [r=7 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-8"
+            LayoutTableCell {TD} at (149,273) size 149x39 [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-8"
+            LayoutTableCell {TD} at (298,273) size 149x39 [r=7 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-8"
+          LayoutTableRow {TR} at (0,312) size 447x39
+            LayoutTableCell {TD} at (0,312) size 149x39 [r=8 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-9"
+            LayoutTableCell {TD} at (149,312) size 149x39 [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-9"
+            LayoutTableCell {TD} at (298,312) size 149x39 [r=8 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-9"
+          LayoutTableRow {TR} at (0,351) size 447x39
+            LayoutTableCell {TD} at (0,351) size 149x39 [r=9 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-10"
+            LayoutTableCell {TD} at (149,351) size 149x39 [r=9 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-10"
+            LayoutTableCell {TD} at (298,351) size 149x39 [r=9 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-10"
+          LayoutTableRow {TR} at (0,390) size 447x39
+            LayoutTableCell {TD} at (0,390) size 149x39 [r=10 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "1-11"
+            LayoutTableCell {TD} at (149,390) size 149x39 [r=10 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "2-11"
+            LayoutTableCell {TD} at (298,390) size 149x39 [r=10 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "3-11"
+          LayoutTableRow {TR} at (0,429) size 447x39
+            LayoutTableCell {TD} at (0,429) size 149x39 [r=11 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-12"
+            LayoutTableCell {TD} at (149,429) size 149x39 [r=11 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-12"
+            LayoutTableCell {TD} at (298,429) size 149x39 [r=11 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-12"
+          LayoutTableRow {TR} at (0,468) size 447x39
+            LayoutTableCell {TD} at (0,468) size 149x39 [r=12 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-13"
+            LayoutTableCell {TD} at (149,468) size 149x39 [r=12 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-13"
+            LayoutTableCell {TD} at (298,468) size 149x39 [r=12 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-13"
+          LayoutTableRow {TR} at (0,507) size 447x39
+            LayoutTableCell {TD} at (0,507) size 149x39 [r=13 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-14"
+            LayoutTableCell {TD} at (149,507) size 149x39 [r=13 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-14"
+            LayoutTableCell {TD} at (298,507) size 149x39 [r=13 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-14"
+          LayoutTableRow {TR} at (0,546) size 447x39
+            LayoutTableCell {TD} at (0,546) size 149x39 [r=14 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-15"
+            LayoutTableCell {TD} at (149,546) size 149x39 [r=14 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-15"
+            LayoutTableCell {TD} at (298,546) size 149x39 [r=14 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-15"
+          LayoutTableRow {TR} at (0,585) size 447x39
+            LayoutTableCell {TD} at (0,585) size 149x39 [r=15 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-16"
+            LayoutTableCell {TD} at (149,585) size 149x39 [r=15 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-16"
+            LayoutTableCell {TD} at (298,585) size 149x39 [r=15 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-16"
+          LayoutTableRow {TR} at (0,624) size 447x39
+            LayoutTableCell {TD} at (0,624) size 149x39 [r=16 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-17"
+            LayoutTableCell {TD} at (149,624) size 149x39 [r=16 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-17"
+            LayoutTableCell {TD} at (298,624) size 149x39 [r=16 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-17"
+          LayoutTableRow {TR} at (0,663) size 447x39
+            LayoutTableCell {TD} at (0,663) size 149x39 [r=17 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-18"
+            LayoutTableCell {TD} at (149,663) size 149x39 [r=17 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-18"
+            LayoutTableCell {TD} at (298,663) size 149x39 [r=17 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-18"
+          LayoutTableRow {TR} at (0,799) size 447x39
+            LayoutTableCell {TD} at (0,799) size 149x39 [r=18 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-19"
+            LayoutTableCell {TD} at (149,799) size 149x39 [r=18 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-19"
+            LayoutTableCell {TD} at (298,799) size 149x39 [r=18 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-19"
+          LayoutTableRow {TR} at (0,838) size 447x39
+            LayoutTableCell {TD} at (0,838) size 149x39 [r=19 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-20"
+            LayoutTableCell {TD} at (149,838) size 149x39 [r=19 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-20"
+            LayoutTableCell {TD} at (298,838) size 149x39 [r=19 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-20"
+          LayoutTableRow {TR} at (0,877) size 447x39
+            LayoutTableCell {TD} at (0,877) size 149x39 [r=20 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-21"
+            LayoutTableCell {TD} at (149,877) size 149x39 [r=20 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-21"
+            LayoutTableCell {TD} at (298,877) size 149x39 [r=20 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-21"
+          LayoutTableRow {TR} at (0,916) size 447x39
+            LayoutTableCell {TD} at (0,916) size 149x39 [r=21 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-22"
+            LayoutTableCell {TD} at (149,916) size 149x39 [r=21 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-22"
+            LayoutTableCell {TD} at (298,916) size 149x39 [r=21 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-22"
+          LayoutTableRow {TR} at (0,955) size 447x39
+            LayoutTableCell {TD} at (0,955) size 149x39 [r=22 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-23"
+            LayoutTableCell {TD} at (149,955) size 149x39 [r=22 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-23"
+            LayoutTableCell {TD} at (298,955) size 149x39 [r=22 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-23"
+          LayoutTableRow {TR} at (0,994) size 447x39
+            LayoutTableCell {TD} at (0,994) size 149x39 [r=23 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-24"
+            LayoutTableCell {TD} at (149,994) size 149x39 [r=23 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-24"
+            LayoutTableCell {TD} at (298,994) size 149x39 [r=23 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-24"
+          LayoutTableRow {TR} at (0,1033) size 447x39
+            LayoutTableCell {TD} at (0,1033) size 149x39 [r=24 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-25"
+            LayoutTableCell {TD} at (149,1033) size 149x39 [r=24 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-25"
+            LayoutTableCell {TD} at (298,1033) size 149x39 [r=24 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-25"
+          LayoutTableRow {TR} at (0,1072) size 447x39
+            LayoutTableCell {TD} at (0,1072) size 149x39 [r=25 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-26"
+            LayoutTableCell {TD} at (149,1072) size 149x39 [r=25 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-26"
+            LayoutTableCell {TD} at (298,1072) size 149x39 [r=25 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-26"
+          LayoutTableRow {TR} at (0,1111) size 447x39
+            LayoutTableCell {TD} at (0,1111) size 149x39 [r=26 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-27"
+            LayoutTableCell {TD} at (149,1111) size 149x39 [r=26 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-27"
+            LayoutTableCell {TD} at (298,1111) size 149x39 [r=26 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-27"
+          LayoutTableRow {TR} at (0,1150) size 447x39
+            LayoutTableCell {TD} at (0,1150) size 149x39 [r=27 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-28"
+            LayoutTableCell {TD} at (149,1150) size 149x39 [r=27 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-28"
+            LayoutTableCell {TD} at (298,1150) size 149x39 [r=27 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-28"
+          LayoutTableRow {TR} at (0,1189) size 447x39
+            LayoutTableCell {TD} at (0,1189) size 149x39 [r=28 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-29"
+            LayoutTableCell {TD} at (149,1189) size 149x39 [r=28 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-29"
+            LayoutTableCell {TD} at (298,1189) size 149x39 [r=28 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-29"
+          LayoutTableRow {TR} at (0,1228) size 447x39
+            LayoutTableCell {TD} at (0,1228) size 149x39 [r=29 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-30"
+            LayoutTableCell {TD} at (149,1228) size 149x39 [r=29 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-30"
+            LayoutTableCell {TD} at (298,1228) size 149x39 [r=29 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-30"
+          LayoutTableRow {TR} at (0,1267) size 447x39
+            LayoutTableCell {TD} at (0,1267) size 149x39 [r=30 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-31"
+            LayoutTableCell {TD} at (149,1267) size 149x39 [r=30 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-31"
+            LayoutTableCell {TD} at (298,1267) size 149x39 [r=30 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-31"
+          LayoutTableRow {TR} at (0,1306) size 447x39
+            LayoutTableCell {TD} at (0,1306) size 149x39 [r=31 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-32"
+            LayoutTableCell {TD} at (149,1306) size 149x39 [r=31 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-32"
+            LayoutTableCell {TD} at (298,1306) size 149x39 [r=31 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-32"
+          LayoutTableRow {TR} at (0,1345) size 447x39
+            LayoutTableCell {TD} at (0,1345) size 149x39 [r=32 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-33"
+            LayoutTableCell {TD} at (149,1345) size 149x39 [r=32 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-33"
+            LayoutTableCell {TD} at (298,1345) size 149x39 [r=32 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-33"
+          LayoutTableRow {TR} at (0,1384) size 447x39
+            LayoutTableCell {TD} at (0,1384) size 149x39 [r=33 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-34"
+            LayoutTableCell {TD} at (149,1384) size 149x39 [r=33 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-34"
+            LayoutTableCell {TD} at (298,1384) size 149x39 [r=33 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-34"
+          LayoutTableRow {TR} at (0,1423) size 447x39
+            LayoutTableCell {TD} at (0,1423) size 149x39 [r=34 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-35"
+            LayoutTableCell {TD} at (149,1423) size 149x39 [r=34 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-35"
+            LayoutTableCell {TD} at (298,1423) size 149x39 [r=34 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-35"
+        LayoutTableSection {TFOOT} at (0,1502) size 447x40
+          LayoutTableRow {TR} at (0,0) size 447x40
+            LayoutTableCell {TH} at (0,0) size 149x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 129x37
+                text run at (10,1) width 129: "Footer 1"
+            LayoutTableCell {TH} at (149,0) size 149x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 129x37
+                text run at (10,1) width 129: "Footer 2"
+            LayoutTableCell {TH} at (298,0) size 149x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 129x37
+                text run at (10,1) width 129: "Footer 3"
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/tfoot-repeats-at-bottom-of-each-page-multiple-tables-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/tfoot-repeats-at-bottom-of-each-page-multiple-tables-expected.txt
new file mode 100644
index 0000000..7da7bb7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/tfoot-repeats-at-bottom-of-each-page-multiple-tables-expected.txt
@@ -0,0 +1,713 @@
+layer at (0,0) size 800x600 scrollHeight 3023
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x3023 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x3023
+    LayoutBlockFlow {BODY} at (0,0) size 1046x3023
+      LayoutTable {TABLE} at (0,0) size 447x1386
+        LayoutTableSection {THEAD} at (0,0) size 447x40
+          LayoutTableRow {TR} at (0,0) size 447x40
+            LayoutTableCell {TH} at (0,0) size 149x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 1"
+            LayoutTableCell {TH} at (149,0) size 149x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 2"
+            LayoutTableCell {TH} at (298,0) size 149x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 3"
+        LayoutTableSection {TBODY} at (0,40) size 447x1306
+          LayoutTableRow {TR} at (0,0) size 447x39
+            LayoutTableCell {TD} at (0,0) size 149x39 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-1"
+            LayoutTableCell {TD} at (149,0) size 149x39 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-1"
+            LayoutTableCell {TD} at (298,0) size 149x39 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-1"
+          LayoutTableRow {TR} at (0,39) size 447x39
+            LayoutTableCell {TD} at (0,39) size 149x39 [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-2"
+            LayoutTableCell {TD} at (149,39) size 149x39 [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-2"
+            LayoutTableCell {TD} at (298,39) size 149x39 [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-2"
+          LayoutTableRow {TR} at (0,78) size 447x39
+            LayoutTableCell {TD} at (0,78) size 149x39 [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-3"
+            LayoutTableCell {TD} at (149,78) size 149x39 [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-3"
+            LayoutTableCell {TD} at (298,78) size 149x39 [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-3"
+          LayoutTableRow {TR} at (0,117) size 447x39
+            LayoutTableCell {TD} at (0,117) size 149x39 [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-4"
+            LayoutTableCell {TD} at (149,117) size 149x39 [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-4"
+            LayoutTableCell {TD} at (298,117) size 149x39 [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-4"
+          LayoutTableRow {TR} at (0,156) size 447x39
+            LayoutTableCell {TD} at (0,156) size 149x39 [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-5"
+            LayoutTableCell {TD} at (149,156) size 149x39 [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-5"
+            LayoutTableCell {TD} at (298,156) size 149x39 [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-5"
+          LayoutTableRow {TR} at (0,195) size 447x39
+            LayoutTableCell {TD} at (0,195) size 149x39 [r=5 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-6"
+            LayoutTableCell {TD} at (149,195) size 149x39 [r=5 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-6"
+            LayoutTableCell {TD} at (298,195) size 149x39 [r=5 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-6"
+          LayoutTableRow {TR} at (0,234) size 447x39
+            LayoutTableCell {TD} at (0,234) size 149x39 [r=6 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-7"
+            LayoutTableCell {TD} at (149,234) size 149x39 [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-7"
+            LayoutTableCell {TD} at (298,234) size 149x39 [r=6 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-7"
+          LayoutTableRow {TR} at (0,273) size 447x39
+            LayoutTableCell {TD} at (0,273) size 149x39 [r=7 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-8"
+            LayoutTableCell {TD} at (149,273) size 149x39 [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-8"
+            LayoutTableCell {TD} at (298,273) size 149x39 [r=7 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-8"
+          LayoutTableRow {TR} at (0,312) size 447x39
+            LayoutTableCell {TD} at (0,312) size 149x39 [r=8 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-9"
+            LayoutTableCell {TD} at (149,312) size 149x39 [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-9"
+            LayoutTableCell {TD} at (298,312) size 149x39 [r=8 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-9"
+          LayoutTableRow {TR} at (0,351) size 447x39
+            LayoutTableCell {TD} at (0,351) size 149x39 [r=9 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-10"
+            LayoutTableCell {TD} at (149,351) size 149x39 [r=9 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-10"
+            LayoutTableCell {TD} at (298,351) size 149x39 [r=9 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-10"
+          LayoutTableRow {TR} at (0,390) size 447x39
+            LayoutTableCell {TD} at (0,390) size 149x39 [r=10 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "1-11"
+            LayoutTableCell {TD} at (149,390) size 149x39 [r=10 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "2-11"
+            LayoutTableCell {TD} at (298,390) size 149x39 [r=10 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "3-11"
+          LayoutTableRow {TR} at (0,429) size 447x39
+            LayoutTableCell {TD} at (0,429) size 149x39 [r=11 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-12"
+            LayoutTableCell {TD} at (149,429) size 149x39 [r=11 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-12"
+            LayoutTableCell {TD} at (298,429) size 149x39 [r=11 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-12"
+          LayoutTableRow {TR} at (0,468) size 447x39
+            LayoutTableCell {TD} at (0,468) size 149x39 [r=12 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-13"
+            LayoutTableCell {TD} at (149,468) size 149x39 [r=12 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-13"
+            LayoutTableCell {TD} at (298,468) size 149x39 [r=12 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-13"
+          LayoutTableRow {TR} at (0,507) size 447x39
+            LayoutTableCell {TD} at (0,507) size 149x39 [r=13 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-14"
+            LayoutTableCell {TD} at (149,507) size 149x39 [r=13 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-14"
+            LayoutTableCell {TD} at (298,507) size 149x39 [r=13 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-14"
+          LayoutTableRow {TR} at (0,546) size 447x39
+            LayoutTableCell {TD} at (0,546) size 149x39 [r=14 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-15"
+            LayoutTableCell {TD} at (149,546) size 149x39 [r=14 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-15"
+            LayoutTableCell {TD} at (298,546) size 149x39 [r=14 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-15"
+          LayoutTableRow {TR} at (0,585) size 447x39
+            LayoutTableCell {TD} at (0,585) size 149x39 [r=15 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-16"
+            LayoutTableCell {TD} at (149,585) size 149x39 [r=15 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-16"
+            LayoutTableCell {TD} at (298,585) size 149x39 [r=15 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-16"
+          LayoutTableRow {TR} at (0,624) size 447x39
+            LayoutTableCell {TD} at (0,624) size 149x39 [r=16 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-17"
+            LayoutTableCell {TD} at (149,624) size 149x39 [r=16 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-17"
+            LayoutTableCell {TD} at (298,624) size 149x39 [r=16 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-17"
+          LayoutTableRow {TR} at (0,663) size 447x39
+            LayoutTableCell {TD} at (0,663) size 149x39 [r=17 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-18"
+            LayoutTableCell {TD} at (149,663) size 149x39 [r=17 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-18"
+            LayoutTableCell {TD} at (298,663) size 149x39 [r=17 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-18"
+          LayoutTableRow {TR} at (0,799) size 447x39
+            LayoutTableCell {TD} at (0,799) size 149x39 [r=18 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-19"
+            LayoutTableCell {TD} at (149,799) size 149x39 [r=18 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-19"
+            LayoutTableCell {TD} at (298,799) size 149x39 [r=18 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-19"
+          LayoutTableRow {TR} at (0,838) size 447x39
+            LayoutTableCell {TD} at (0,838) size 149x39 [r=19 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-20"
+            LayoutTableCell {TD} at (149,838) size 149x39 [r=19 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-20"
+            LayoutTableCell {TD} at (298,838) size 149x39 [r=19 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-20"
+          LayoutTableRow {TR} at (0,877) size 447x39
+            LayoutTableCell {TD} at (0,877) size 149x39 [r=20 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-21"
+            LayoutTableCell {TD} at (149,877) size 149x39 [r=20 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-21"
+            LayoutTableCell {TD} at (298,877) size 149x39 [r=20 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-21"
+          LayoutTableRow {TR} at (0,916) size 447x39
+            LayoutTableCell {TD} at (0,916) size 149x39 [r=21 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-22"
+            LayoutTableCell {TD} at (149,916) size 149x39 [r=21 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-22"
+            LayoutTableCell {TD} at (298,916) size 149x39 [r=21 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-22"
+          LayoutTableRow {TR} at (0,955) size 447x39
+            LayoutTableCell {TD} at (0,955) size 149x39 [r=22 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-23"
+            LayoutTableCell {TD} at (149,955) size 149x39 [r=22 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-23"
+            LayoutTableCell {TD} at (298,955) size 149x39 [r=22 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-23"
+          LayoutTableRow {TR} at (0,994) size 447x39
+            LayoutTableCell {TD} at (0,994) size 149x39 [r=23 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-24"
+            LayoutTableCell {TD} at (149,994) size 149x39 [r=23 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-24"
+            LayoutTableCell {TD} at (298,994) size 149x39 [r=23 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-24"
+          LayoutTableRow {TR} at (0,1033) size 447x39
+            LayoutTableCell {TD} at (0,1033) size 149x39 [r=24 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-25"
+            LayoutTableCell {TD} at (149,1033) size 149x39 [r=24 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-25"
+            LayoutTableCell {TD} at (298,1033) size 149x39 [r=24 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-25"
+          LayoutTableRow {TR} at (0,1072) size 447x39
+            LayoutTableCell {TD} at (0,1072) size 149x39 [r=25 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-26"
+            LayoutTableCell {TD} at (149,1072) size 149x39 [r=25 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-26"
+            LayoutTableCell {TD} at (298,1072) size 149x39 [r=25 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-26"
+          LayoutTableRow {TR} at (0,1111) size 447x39
+            LayoutTableCell {TD} at (0,1111) size 149x39 [r=26 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-27"
+            LayoutTableCell {TD} at (149,1111) size 149x39 [r=26 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-27"
+            LayoutTableCell {TD} at (298,1111) size 149x39 [r=26 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-27"
+          LayoutTableRow {TR} at (0,1150) size 447x39
+            LayoutTableCell {TD} at (0,1150) size 149x39 [r=27 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-28"
+            LayoutTableCell {TD} at (149,1150) size 149x39 [r=27 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-28"
+            LayoutTableCell {TD} at (298,1150) size 149x39 [r=27 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-28"
+          LayoutTableRow {TR} at (0,1189) size 447x39
+            LayoutTableCell {TD} at (0,1189) size 149x39 [r=28 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-29"
+            LayoutTableCell {TD} at (149,1189) size 149x39 [r=28 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-29"
+            LayoutTableCell {TD} at (298,1189) size 149x39 [r=28 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-29"
+          LayoutTableRow {TR} at (0,1228) size 447x39
+            LayoutTableCell {TD} at (0,1228) size 149x39 [r=29 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-30"
+            LayoutTableCell {TD} at (149,1228) size 149x39 [r=29 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-30"
+            LayoutTableCell {TD} at (298,1228) size 149x39 [r=29 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-30"
+          LayoutTableRow {TR} at (0,1267) size 447x39
+            LayoutTableCell {TD} at (0,1267) size 149x39 [r=30 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-31"
+            LayoutTableCell {TD} at (149,1267) size 149x39 [r=30 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-31"
+            LayoutTableCell {TD} at (298,1267) size 149x39 [r=30 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-31"
+        LayoutTableSection {TFOOT} at (0,1346) size 447x40
+          LayoutTableRow {TR} at (0,0) size 447x40
+            LayoutTableCell {TH} at (0,0) size 149x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 129x37
+                text run at (10,1) width 129: "Footer 1"
+            LayoutTableCell {TH} at (149,0) size 149x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 129x37
+                text run at (10,1) width 129: "Footer 2"
+            LayoutTableCell {TH} at (298,0) size 149x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 129x37
+                text run at (10,1) width 129: "Footer 3"
+      LayoutTable {TABLE} at (0,1386) size 501x1637
+        LayoutTableSection {THEAD} at (0,0) size 501x40
+          LayoutTableRow {TR} at (0,0) size 501x40
+            LayoutTableCell {TH} at (0,0) size 167x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 165x37
+                text run at (1,1) width 165: "Column2 1"
+            LayoutTableCell {TH} at (167,0) size 167x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 165x37
+                text run at (1,1) width 165: "Column2 2"
+            LayoutTableCell {TH} at (334,0) size 167x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 165x37
+                text run at (1,1) width 165: "Column2 3"
+        LayoutTableSection {TBODY} at (0,40) size 501x1557
+          LayoutTableRow {TR} at (0,0) size 501x39
+            LayoutTableCell {TD} at (0,0) size 167x39 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-1"
+            LayoutTableCell {TD} at (167,0) size 167x39 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-1"
+            LayoutTableCell {TD} at (334,0) size 167x39 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-1"
+          LayoutTableRow {TR} at (0,39) size 501x39
+            LayoutTableCell {TD} at (0,39) size 167x39 [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-2"
+            LayoutTableCell {TD} at (167,39) size 167x39 [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-2"
+            LayoutTableCell {TD} at (334,39) size 167x39 [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-2"
+          LayoutTableRow {TR} at (0,78) size 501x39
+            LayoutTableCell {TD} at (0,78) size 167x39 [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-3"
+            LayoutTableCell {TD} at (167,78) size 167x39 [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-3"
+            LayoutTableCell {TD} at (334,78) size 167x39 [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-3"
+          LayoutTableRow {TR} at (0,212) size 501x39
+            LayoutTableCell {TD} at (0,212) size 167x39 [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-4"
+            LayoutTableCell {TD} at (167,212) size 167x39 [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-4"
+            LayoutTableCell {TD} at (334,212) size 167x39 [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-4"
+          LayoutTableRow {TR} at (0,251) size 501x39
+            LayoutTableCell {TD} at (0,251) size 167x39 [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-5"
+            LayoutTableCell {TD} at (167,251) size 167x39 [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-5"
+            LayoutTableCell {TD} at (334,251) size 167x39 [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-5"
+          LayoutTableRow {TR} at (0,290) size 501x39
+            LayoutTableCell {TD} at (0,290) size 167x39 [r=5 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-6"
+            LayoutTableCell {TD} at (167,290) size 167x39 [r=5 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-6"
+            LayoutTableCell {TD} at (334,290) size 167x39 [r=5 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-6"
+          LayoutTableRow {TR} at (0,329) size 501x39
+            LayoutTableCell {TD} at (0,329) size 167x39 [r=6 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-7"
+            LayoutTableCell {TD} at (167,329) size 167x39 [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-7"
+            LayoutTableCell {TD} at (334,329) size 167x39 [r=6 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-7"
+          LayoutTableRow {TR} at (0,368) size 501x39
+            LayoutTableCell {TD} at (0,368) size 167x39 [r=7 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-8"
+            LayoutTableCell {TD} at (167,368) size 167x39 [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-8"
+            LayoutTableCell {TD} at (334,368) size 167x39 [r=7 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-8"
+          LayoutTableRow {TR} at (0,407) size 501x39
+            LayoutTableCell {TD} at (0,407) size 167x39 [r=8 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-9"
+            LayoutTableCell {TD} at (167,407) size 167x39 [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-9"
+            LayoutTableCell {TD} at (334,407) size 167x39 [r=8 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-9"
+          LayoutTableRow {TR} at (0,446) size 501x39
+            LayoutTableCell {TD} at (0,446) size 167x39 [r=9 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-10"
+            LayoutTableCell {TD} at (167,446) size 167x39 [r=9 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-10"
+            LayoutTableCell {TD} at (334,446) size 167x39 [r=9 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-10"
+          LayoutTableRow {TR} at (0,485) size 501x39
+            LayoutTableCell {TD} at (0,485) size 167x39 [r=10 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "1-11"
+            LayoutTableCell {TD} at (167,485) size 167x39 [r=10 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "2-11"
+            LayoutTableCell {TD} at (334,485) size 167x39 [r=10 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "3-11"
+          LayoutTableRow {TR} at (0,524) size 501x39
+            LayoutTableCell {TD} at (0,524) size 167x39 [r=11 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-12"
+            LayoutTableCell {TD} at (167,524) size 167x39 [r=11 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-12"
+            LayoutTableCell {TD} at (334,524) size 167x39 [r=11 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-12"
+          LayoutTableRow {TR} at (0,563) size 501x39
+            LayoutTableCell {TD} at (0,563) size 167x39 [r=12 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-13"
+            LayoutTableCell {TD} at (167,563) size 167x39 [r=12 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-13"
+            LayoutTableCell {TD} at (334,563) size 167x39 [r=12 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-13"
+          LayoutTableRow {TR} at (0,602) size 501x39
+            LayoutTableCell {TD} at (0,602) size 167x39 [r=13 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-14"
+            LayoutTableCell {TD} at (167,602) size 167x39 [r=13 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-14"
+            LayoutTableCell {TD} at (334,602) size 167x39 [r=13 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-14"
+          LayoutTableRow {TR} at (0,641) size 501x39
+            LayoutTableCell {TD} at (0,641) size 167x39 [r=14 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-15"
+            LayoutTableCell {TD} at (167,641) size 167x39 [r=14 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-15"
+            LayoutTableCell {TD} at (334,641) size 167x39 [r=14 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-15"
+          LayoutTableRow {TR} at (0,680) size 501x39
+            LayoutTableCell {TD} at (0,680) size 167x39 [r=15 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-16"
+            LayoutTableCell {TD} at (167,680) size 167x39 [r=15 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-16"
+            LayoutTableCell {TD} at (334,680) size 167x39 [r=15 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-16"
+          LayoutTableRow {TR} at (0,719) size 501x39
+            LayoutTableCell {TD} at (0,719) size 167x39 [r=16 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-17"
+            LayoutTableCell {TD} at (167,719) size 167x39 [r=16 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-17"
+            LayoutTableCell {TD} at (334,719) size 167x39 [r=16 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-17"
+          LayoutTableRow {TR} at (0,758) size 501x39
+            LayoutTableCell {TD} at (0,758) size 167x39 [r=17 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-18"
+            LayoutTableCell {TD} at (167,758) size 167x39 [r=17 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-18"
+            LayoutTableCell {TD} at (334,758) size 167x39 [r=17 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-18"
+          LayoutTableRow {TR} at (0,797) size 501x39
+            LayoutTableCell {TD} at (0,797) size 167x39 [r=18 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-19"
+            LayoutTableCell {TD} at (167,797) size 167x39 [r=18 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-19"
+            LayoutTableCell {TD} at (334,797) size 167x39 [r=18 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-19"
+          LayoutTableRow {TR} at (0,836) size 501x39
+            LayoutTableCell {TD} at (0,836) size 167x39 [r=19 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-20"
+            LayoutTableCell {TD} at (167,836) size 167x39 [r=19 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-20"
+            LayoutTableCell {TD} at (334,836) size 167x39 [r=19 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-20"
+          LayoutTableRow {TR} at (0,875) size 501x39
+            LayoutTableCell {TD} at (0,875) size 167x39 [r=20 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-21"
+            LayoutTableCell {TD} at (167,875) size 167x39 [r=20 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-21"
+            LayoutTableCell {TD} at (334,875) size 167x39 [r=20 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-21"
+          LayoutTableRow {TR} at (0,1011) size 501x39
+            LayoutTableCell {TD} at (0,1011) size 167x39 [r=21 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-22"
+            LayoutTableCell {TD} at (167,1011) size 167x39 [r=21 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-22"
+            LayoutTableCell {TD} at (334,1011) size 167x39 [r=21 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-22"
+          LayoutTableRow {TR} at (0,1050) size 501x39
+            LayoutTableCell {TD} at (0,1050) size 167x39 [r=22 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-23"
+            LayoutTableCell {TD} at (167,1050) size 167x39 [r=22 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-23"
+            LayoutTableCell {TD} at (334,1050) size 167x39 [r=22 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-23"
+          LayoutTableRow {TR} at (0,1089) size 501x39
+            LayoutTableCell {TD} at (0,1089) size 167x39 [r=23 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-24"
+            LayoutTableCell {TD} at (167,1089) size 167x39 [r=23 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-24"
+            LayoutTableCell {TD} at (334,1089) size 167x39 [r=23 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-24"
+          LayoutTableRow {TR} at (0,1128) size 501x39
+            LayoutTableCell {TD} at (0,1128) size 167x39 [r=24 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-25"
+            LayoutTableCell {TD} at (167,1128) size 167x39 [r=24 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-25"
+            LayoutTableCell {TD} at (334,1128) size 167x39 [r=24 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-25"
+          LayoutTableRow {TR} at (0,1167) size 501x39
+            LayoutTableCell {TD} at (0,1167) size 167x39 [r=25 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-26"
+            LayoutTableCell {TD} at (167,1167) size 167x39 [r=25 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-26"
+            LayoutTableCell {TD} at (334,1167) size 167x39 [r=25 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-26"
+          LayoutTableRow {TR} at (0,1206) size 501x39
+            LayoutTableCell {TD} at (0,1206) size 167x39 [r=26 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-27"
+            LayoutTableCell {TD} at (167,1206) size 167x39 [r=26 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-27"
+            LayoutTableCell {TD} at (334,1206) size 167x39 [r=26 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-27"
+          LayoutTableRow {TR} at (0,1245) size 501x39
+            LayoutTableCell {TD} at (0,1245) size 167x39 [r=27 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-28"
+            LayoutTableCell {TD} at (167,1245) size 167x39 [r=27 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-28"
+            LayoutTableCell {TD} at (334,1245) size 167x39 [r=27 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-28"
+          LayoutTableRow {TR} at (0,1284) size 501x39
+            LayoutTableCell {TD} at (0,1284) size 167x39 [r=28 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-29"
+            LayoutTableCell {TD} at (167,1284) size 167x39 [r=28 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-29"
+            LayoutTableCell {TD} at (334,1284) size 167x39 [r=28 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-29"
+          LayoutTableRow {TR} at (0,1323) size 501x39
+            LayoutTableCell {TD} at (0,1323) size 167x39 [r=29 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-30"
+            LayoutTableCell {TD} at (167,1323) size 167x39 [r=29 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-30"
+            LayoutTableCell {TD} at (334,1323) size 167x39 [r=29 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-30"
+          LayoutTableRow {TR} at (0,1362) size 501x39
+            LayoutTableCell {TD} at (0,1362) size 167x39 [r=30 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-31"
+            LayoutTableCell {TD} at (167,1362) size 167x39 [r=30 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-31"
+            LayoutTableCell {TD} at (334,1362) size 167x39 [r=30 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-31"
+          LayoutTableRow {TR} at (0,1401) size 501x39
+            LayoutTableCell {TD} at (0,1401) size 167x39 [r=31 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-32"
+            LayoutTableCell {TD} at (167,1401) size 167x39 [r=31 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-32"
+            LayoutTableCell {TD} at (334,1401) size 167x39 [r=31 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-32"
+          LayoutTableRow {TR} at (0,1440) size 501x39
+            LayoutTableCell {TD} at (0,1440) size 167x39 [r=32 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-33"
+            LayoutTableCell {TD} at (167,1440) size 167x39 [r=32 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-33"
+            LayoutTableCell {TD} at (334,1440) size 167x39 [r=32 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-33"
+          LayoutTableRow {TR} at (0,1479) size 501x39
+            LayoutTableCell {TD} at (0,1479) size 167x39 [r=33 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-34"
+            LayoutTableCell {TD} at (167,1479) size 167x39 [r=33 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-34"
+            LayoutTableCell {TD} at (334,1479) size 167x39 [r=33 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-34"
+          LayoutTableRow {TR} at (0,1518) size 501x39
+            LayoutTableCell {TD} at (0,1518) size 167x39 [r=34 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-35"
+            LayoutTableCell {TD} at (167,1518) size 167x39 [r=34 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-35"
+            LayoutTableCell {TD} at (334,1518) size 167x39 [r=34 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-35"
+        LayoutTableSection {TFOOT} at (0,1597) size 501x40
+          LayoutTableRow {TR} at (0,0) size 501x40
+            LayoutTableCell {TH} at (0,0) size 167x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 147x37
+                text run at (10,1) width 147: "Footer2 1"
+            LayoutTableCell {TH} at (167,0) size 167x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 147x37
+                text run at (10,1) width 147: "Footer2 2"
+            LayoutTableCell {TH} at (334,0) size 167x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (10,1) size 147x37
+                text run at (10,1) width 147: "Footer2 3"
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-repeats-at-top-of-each-page-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-repeats-at-top-of-each-page-expected.txt
new file mode 100644
index 0000000..0e791e10
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-repeats-at-top-of-each-page-expected.txt
@@ -0,0 +1,368 @@
+layer at (0,0) size 800x600 scrollHeight 1548
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x1548 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x1548
+    LayoutBlockFlow {BODY} at (8,8) size 1030x1532
+      LayoutTable {TABLE} at (0,0) size 455x1532
+        LayoutTableSection {THEAD} at (0,0) size 455x44
+          LayoutTableRow {TR} at (0,2) size 455x40
+            LayoutTableCell {TH} at (2,2) size 149x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 1"
+            LayoutTableCell {TH} at (153,2) size 149x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 2"
+            LayoutTableCell {TH} at (304,2) size 149x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 3"
+        LayoutTableSection {TBODY} at (0,44) size 455x1488
+          LayoutTableRow {TR} at (0,0) size 455x39
+            LayoutTableCell {TD} at (2,0) size 149x39 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-1"
+            LayoutTableCell {TD} at (153,0) size 149x39 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-1"
+            LayoutTableCell {TD} at (304,0) size 149x39 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-1"
+          LayoutTableRow {TR} at (0,41) size 455x39
+            LayoutTableCell {TD} at (2,41) size 149x39 [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-2"
+            LayoutTableCell {TD} at (153,41) size 149x39 [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-2"
+            LayoutTableCell {TD} at (304,41) size 149x39 [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-2"
+          LayoutTableRow {TR} at (0,82) size 455x39
+            LayoutTableCell {TD} at (2,82) size 149x39 [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-3"
+            LayoutTableCell {TD} at (153,82) size 149x39 [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-3"
+            LayoutTableCell {TD} at (304,82) size 149x39 [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-3"
+          LayoutTableRow {TR} at (0,123) size 455x39
+            LayoutTableCell {TD} at (2,123) size 149x39 [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-4"
+            LayoutTableCell {TD} at (153,123) size 149x39 [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-4"
+            LayoutTableCell {TD} at (304,123) size 149x39 [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-4"
+          LayoutTableRow {TR} at (0,164) size 455x39
+            LayoutTableCell {TD} at (2,164) size 149x39 [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-5"
+            LayoutTableCell {TD} at (153,164) size 149x39 [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-5"
+            LayoutTableCell {TD} at (304,164) size 149x39 [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-5"
+          LayoutTableRow {TR} at (0,205) size 455x39
+            LayoutTableCell {TD} at (2,205) size 149x39 [r=5 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-6"
+            LayoutTableCell {TD} at (153,205) size 149x39 [r=5 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-6"
+            LayoutTableCell {TD} at (304,205) size 149x39 [r=5 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-6"
+          LayoutTableRow {TR} at (0,246) size 455x39
+            LayoutTableCell {TD} at (2,246) size 149x39 [r=6 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-7"
+            LayoutTableCell {TD} at (153,246) size 149x39 [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-7"
+            LayoutTableCell {TD} at (304,246) size 149x39 [r=6 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-7"
+          LayoutTableRow {TR} at (0,287) size 455x39
+            LayoutTableCell {TD} at (2,287) size 149x39 [r=7 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-8"
+            LayoutTableCell {TD} at (153,287) size 149x39 [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-8"
+            LayoutTableCell {TD} at (304,287) size 149x39 [r=7 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-8"
+          LayoutTableRow {TR} at (0,328) size 455x39
+            LayoutTableCell {TD} at (2,328) size 149x39 [r=8 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-9"
+            LayoutTableCell {TD} at (153,328) size 149x39 [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-9"
+            LayoutTableCell {TD} at (304,328) size 149x39 [r=8 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-9"
+          LayoutTableRow {TR} at (0,369) size 455x39
+            LayoutTableCell {TD} at (2,369) size 149x39 [r=9 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-10"
+            LayoutTableCell {TD} at (153,369) size 149x39 [r=9 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-10"
+            LayoutTableCell {TD} at (304,369) size 149x39 [r=9 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-10"
+          LayoutTableRow {TR} at (0,410) size 455x39
+            LayoutTableCell {TD} at (2,410) size 149x39 [r=10 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "1-11"
+            LayoutTableCell {TD} at (153,410) size 149x39 [r=10 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "2-11"
+            LayoutTableCell {TD} at (304,410) size 149x39 [r=10 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "3-11"
+          LayoutTableRow {TR} at (0,451) size 455x39
+            LayoutTableCell {TD} at (2,451) size 149x39 [r=11 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-12"
+            LayoutTableCell {TD} at (153,451) size 149x39 [r=11 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-12"
+            LayoutTableCell {TD} at (304,451) size 149x39 [r=11 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-12"
+          LayoutTableRow {TR} at (0,492) size 455x39
+            LayoutTableCell {TD} at (2,492) size 149x39 [r=12 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-13"
+            LayoutTableCell {TD} at (153,492) size 149x39 [r=12 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-13"
+            LayoutTableCell {TD} at (304,492) size 149x39 [r=12 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-13"
+          LayoutTableRow {TR} at (0,533) size 455x39
+            LayoutTableCell {TD} at (2,533) size 149x39 [r=13 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-14"
+            LayoutTableCell {TD} at (153,533) size 149x39 [r=13 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-14"
+            LayoutTableCell {TD} at (304,533) size 149x39 [r=13 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-14"
+          LayoutTableRow {TR} at (0,574) size 455x39
+            LayoutTableCell {TD} at (2,574) size 149x39 [r=14 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-15"
+            LayoutTableCell {TD} at (153,574) size 149x39 [r=14 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-15"
+            LayoutTableCell {TD} at (304,574) size 149x39 [r=14 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-15"
+          LayoutTableRow {TR} at (0,615) size 455x39
+            LayoutTableCell {TD} at (2,615) size 149x39 [r=15 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-16"
+            LayoutTableCell {TD} at (153,615) size 149x39 [r=15 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-16"
+            LayoutTableCell {TD} at (304,615) size 149x39 [r=15 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-16"
+          LayoutTableRow {TR} at (0,656) size 455x39
+            LayoutTableCell {TD} at (2,656) size 149x39 [r=16 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-17"
+            LayoutTableCell {TD} at (153,656) size 149x39 [r=16 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-17"
+            LayoutTableCell {TD} at (304,656) size 149x39 [r=16 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-17"
+          LayoutTableRow {TR} at (0,697) size 455x39
+            LayoutTableCell {TD} at (2,697) size 149x39 [r=17 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-18"
+            LayoutTableCell {TD} at (153,697) size 149x39 [r=17 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-18"
+            LayoutTableCell {TD} at (304,697) size 149x39 [r=17 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-18"
+          LayoutTableRow {TR} at (0,791) size 455x39
+            LayoutTableCell {TD} at (2,791) size 149x39 [r=18 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-19"
+            LayoutTableCell {TD} at (153,791) size 149x39 [r=18 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-19"
+            LayoutTableCell {TD} at (304,791) size 149x39 [r=18 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-19"
+          LayoutTableRow {TR} at (0,832) size 455x39
+            LayoutTableCell {TD} at (2,832) size 149x39 [r=19 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-20"
+            LayoutTableCell {TD} at (153,832) size 149x39 [r=19 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-20"
+            LayoutTableCell {TD} at (304,832) size 149x39 [r=19 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-20"
+          LayoutTableRow {TR} at (0,873) size 455x39
+            LayoutTableCell {TD} at (2,873) size 149x39 [r=20 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-21"
+            LayoutTableCell {TD} at (153,873) size 149x39 [r=20 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-21"
+            LayoutTableCell {TD} at (304,873) size 149x39 [r=20 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-21"
+          LayoutTableRow {TR} at (0,914) size 455x39
+            LayoutTableCell {TD} at (2,914) size 149x39 [r=21 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-22"
+            LayoutTableCell {TD} at (153,914) size 149x39 [r=21 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-22"
+            LayoutTableCell {TD} at (304,914) size 149x39 [r=21 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-22"
+          LayoutTableRow {TR} at (0,955) size 455x39
+            LayoutTableCell {TD} at (2,955) size 149x39 [r=22 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-23"
+            LayoutTableCell {TD} at (153,955) size 149x39 [r=22 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-23"
+            LayoutTableCell {TD} at (304,955) size 149x39 [r=22 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-23"
+          LayoutTableRow {TR} at (0,996) size 455x39
+            LayoutTableCell {TD} at (2,996) size 149x39 [r=23 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-24"
+            LayoutTableCell {TD} at (153,996) size 149x39 [r=23 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-24"
+            LayoutTableCell {TD} at (304,996) size 149x39 [r=23 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-24"
+          LayoutTableRow {TR} at (0,1037) size 455x39
+            LayoutTableCell {TD} at (2,1037) size 149x39 [r=24 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-25"
+            LayoutTableCell {TD} at (153,1037) size 149x39 [r=24 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-25"
+            LayoutTableCell {TD} at (304,1037) size 149x39 [r=24 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-25"
+          LayoutTableRow {TR} at (0,1078) size 455x39
+            LayoutTableCell {TD} at (2,1078) size 149x39 [r=25 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-26"
+            LayoutTableCell {TD} at (153,1078) size 149x39 [r=25 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-26"
+            LayoutTableCell {TD} at (304,1078) size 149x39 [r=25 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-26"
+          LayoutTableRow {TR} at (0,1119) size 455x39
+            LayoutTableCell {TD} at (2,1119) size 149x39 [r=26 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-27"
+            LayoutTableCell {TD} at (153,1119) size 149x39 [r=26 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-27"
+            LayoutTableCell {TD} at (304,1119) size 149x39 [r=26 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-27"
+          LayoutTableRow {TR} at (0,1160) size 455x39
+            LayoutTableCell {TD} at (2,1160) size 149x39 [r=27 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-28"
+            LayoutTableCell {TD} at (153,1160) size 149x39 [r=27 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-28"
+            LayoutTableCell {TD} at (304,1160) size 149x39 [r=27 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-28"
+          LayoutTableRow {TR} at (0,1201) size 455x39
+            LayoutTableCell {TD} at (2,1201) size 149x39 [r=28 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-29"
+            LayoutTableCell {TD} at (153,1201) size 149x39 [r=28 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-29"
+            LayoutTableCell {TD} at (304,1201) size 149x39 [r=28 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-29"
+          LayoutTableRow {TR} at (0,1242) size 455x39
+            LayoutTableCell {TD} at (2,1242) size 149x39 [r=29 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-30"
+            LayoutTableCell {TD} at (153,1242) size 149x39 [r=29 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-30"
+            LayoutTableCell {TD} at (304,1242) size 149x39 [r=29 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-30"
+          LayoutTableRow {TR} at (0,1283) size 455x39
+            LayoutTableCell {TD} at (2,1283) size 149x39 [r=30 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-31"
+            LayoutTableCell {TD} at (153,1283) size 149x39 [r=30 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-31"
+            LayoutTableCell {TD} at (304,1283) size 149x39 [r=30 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-31"
+          LayoutTableRow {TR} at (0,1324) size 455x39
+            LayoutTableCell {TD} at (2,1324) size 149x39 [r=31 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-32"
+            LayoutTableCell {TD} at (153,1324) size 149x39 [r=31 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-32"
+            LayoutTableCell {TD} at (304,1324) size 149x39 [r=31 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-32"
+          LayoutTableRow {TR} at (0,1365) size 455x39
+            LayoutTableCell {TD} at (2,1365) size 149x39 [r=32 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-33"
+            LayoutTableCell {TD} at (153,1365) size 149x39 [r=32 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-33"
+            LayoutTableCell {TD} at (304,1365) size 149x39 [r=32 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-33"
+          LayoutTableRow {TR} at (0,1406) size 455x39
+            LayoutTableCell {TD} at (2,1406) size 149x39 [r=33 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-34"
+            LayoutTableCell {TD} at (153,1406) size 149x39 [r=33 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-34"
+            LayoutTableCell {TD} at (304,1406) size 149x39 [r=33 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-34"
+          LayoutTableRow {TR} at (0,1447) size 455x39
+            LayoutTableCell {TD} at (2,1447) size 149x39 [r=34 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-35"
+            LayoutTableCell {TD} at (153,1447) size 149x39 [r=34 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-35"
+            LayoutTableCell {TD} at (304,1447) size 149x39 [r=34 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-35"
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.txt
new file mode 100644
index 0000000..122c0cbf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.txt
@@ -0,0 +1,691 @@
+layer at (0,0) size 800x600 scrollHeight 2982
+  LayoutView at (0,0) size 1046x799
+layer at (0,0) size 1046x2982 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1046x2982
+    LayoutBlockFlow {BODY} at (8,8) size 1030x2966
+      LayoutTable {TABLE} at (0,0) size 455x1368
+        LayoutTableSection {THEAD} at (0,0) size 455x44
+          LayoutTableRow {TR} at (0,2) size 455x40
+            LayoutTableCell {TH} at (2,2) size 149x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 1"
+            LayoutTableCell {TH} at (153,2) size 149x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 2"
+            LayoutTableCell {TH} at (304,2) size 149x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 147x37
+                text run at (1,1) width 147: "Column 3"
+        LayoutTableSection {TBODY} at (0,44) size 455x1324
+          LayoutTableRow {TR} at (0,0) size 455x39
+            LayoutTableCell {TD} at (2,0) size 149x39 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-1"
+            LayoutTableCell {TD} at (153,0) size 149x39 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-1"
+            LayoutTableCell {TD} at (304,0) size 149x39 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-1"
+          LayoutTableRow {TR} at (0,41) size 455x39
+            LayoutTableCell {TD} at (2,41) size 149x39 [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-2"
+            LayoutTableCell {TD} at (153,41) size 149x39 [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-2"
+            LayoutTableCell {TD} at (304,41) size 149x39 [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-2"
+          LayoutTableRow {TR} at (0,82) size 455x39
+            LayoutTableCell {TD} at (2,82) size 149x39 [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-3"
+            LayoutTableCell {TD} at (153,82) size 149x39 [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-3"
+            LayoutTableCell {TD} at (304,82) size 149x39 [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-3"
+          LayoutTableRow {TR} at (0,123) size 455x39
+            LayoutTableCell {TD} at (2,123) size 149x39 [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-4"
+            LayoutTableCell {TD} at (153,123) size 149x39 [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-4"
+            LayoutTableCell {TD} at (304,123) size 149x39 [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-4"
+          LayoutTableRow {TR} at (0,164) size 455x39
+            LayoutTableCell {TD} at (2,164) size 149x39 [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-5"
+            LayoutTableCell {TD} at (153,164) size 149x39 [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-5"
+            LayoutTableCell {TD} at (304,164) size 149x39 [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-5"
+          LayoutTableRow {TR} at (0,205) size 455x39
+            LayoutTableCell {TD} at (2,205) size 149x39 [r=5 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-6"
+            LayoutTableCell {TD} at (153,205) size 149x39 [r=5 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-6"
+            LayoutTableCell {TD} at (304,205) size 149x39 [r=5 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-6"
+          LayoutTableRow {TR} at (0,246) size 455x39
+            LayoutTableCell {TD} at (2,246) size 149x39 [r=6 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-7"
+            LayoutTableCell {TD} at (153,246) size 149x39 [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-7"
+            LayoutTableCell {TD} at (304,246) size 149x39 [r=6 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-7"
+          LayoutTableRow {TR} at (0,287) size 455x39
+            LayoutTableCell {TD} at (2,287) size 149x39 [r=7 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-8"
+            LayoutTableCell {TD} at (153,287) size 149x39 [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-8"
+            LayoutTableCell {TD} at (304,287) size 149x39 [r=7 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-8"
+          LayoutTableRow {TR} at (0,328) size 455x39
+            LayoutTableCell {TD} at (2,328) size 149x39 [r=8 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-9"
+            LayoutTableCell {TD} at (153,328) size 149x39 [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-9"
+            LayoutTableCell {TD} at (304,328) size 149x39 [r=8 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-9"
+          LayoutTableRow {TR} at (0,369) size 455x39
+            LayoutTableCell {TD} at (2,369) size 149x39 [r=9 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-10"
+            LayoutTableCell {TD} at (153,369) size 149x39 [r=9 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-10"
+            LayoutTableCell {TD} at (304,369) size 149x39 [r=9 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-10"
+          LayoutTableRow {TR} at (0,410) size 455x39
+            LayoutTableCell {TD} at (2,410) size 149x39 [r=10 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "1-11"
+            LayoutTableCell {TD} at (153,410) size 149x39 [r=10 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "2-11"
+            LayoutTableCell {TD} at (304,410) size 149x39 [r=10 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "3-11"
+          LayoutTableRow {TR} at (0,451) size 455x39
+            LayoutTableCell {TD} at (2,451) size 149x39 [r=11 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-12"
+            LayoutTableCell {TD} at (153,451) size 149x39 [r=11 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-12"
+            LayoutTableCell {TD} at (304,451) size 149x39 [r=11 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-12"
+          LayoutTableRow {TR} at (0,492) size 455x39
+            LayoutTableCell {TD} at (2,492) size 149x39 [r=12 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-13"
+            LayoutTableCell {TD} at (153,492) size 149x39 [r=12 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-13"
+            LayoutTableCell {TD} at (304,492) size 149x39 [r=12 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-13"
+          LayoutTableRow {TR} at (0,533) size 455x39
+            LayoutTableCell {TD} at (2,533) size 149x39 [r=13 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-14"
+            LayoutTableCell {TD} at (153,533) size 149x39 [r=13 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-14"
+            LayoutTableCell {TD} at (304,533) size 149x39 [r=13 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-14"
+          LayoutTableRow {TR} at (0,574) size 455x39
+            LayoutTableCell {TD} at (2,574) size 149x39 [r=14 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-15"
+            LayoutTableCell {TD} at (153,574) size 149x39 [r=14 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-15"
+            LayoutTableCell {TD} at (304,574) size 149x39 [r=14 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-15"
+          LayoutTableRow {TR} at (0,615) size 455x39
+            LayoutTableCell {TD} at (2,615) size 149x39 [r=15 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-16"
+            LayoutTableCell {TD} at (153,615) size 149x39 [r=15 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-16"
+            LayoutTableCell {TD} at (304,615) size 149x39 [r=15 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-16"
+          LayoutTableRow {TR} at (0,656) size 455x39
+            LayoutTableCell {TD} at (2,656) size 149x39 [r=16 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-17"
+            LayoutTableCell {TD} at (153,656) size 149x39 [r=16 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-17"
+            LayoutTableCell {TD} at (304,656) size 149x39 [r=16 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-17"
+          LayoutTableRow {TR} at (0,697) size 455x39
+            LayoutTableCell {TD} at (2,697) size 149x39 [r=17 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-18"
+            LayoutTableCell {TD} at (153,697) size 149x39 [r=17 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-18"
+            LayoutTableCell {TD} at (304,697) size 149x39 [r=17 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-18"
+          LayoutTableRow {TR} at (0,791) size 455x39
+            LayoutTableCell {TD} at (2,791) size 149x39 [r=18 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-19"
+            LayoutTableCell {TD} at (153,791) size 149x39 [r=18 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-19"
+            LayoutTableCell {TD} at (304,791) size 149x39 [r=18 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-19"
+          LayoutTableRow {TR} at (0,832) size 455x39
+            LayoutTableCell {TD} at (2,832) size 149x39 [r=19 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-20"
+            LayoutTableCell {TD} at (153,832) size 149x39 [r=19 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-20"
+            LayoutTableCell {TD} at (304,832) size 149x39 [r=19 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-20"
+          LayoutTableRow {TR} at (0,873) size 455x39
+            LayoutTableCell {TD} at (2,873) size 149x39 [r=20 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-21"
+            LayoutTableCell {TD} at (153,873) size 149x39 [r=20 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-21"
+            LayoutTableCell {TD} at (304,873) size 149x39 [r=20 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-21"
+          LayoutTableRow {TR} at (0,914) size 455x39
+            LayoutTableCell {TD} at (2,914) size 149x39 [r=21 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-22"
+            LayoutTableCell {TD} at (153,914) size 149x39 [r=21 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-22"
+            LayoutTableCell {TD} at (304,914) size 149x39 [r=21 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-22"
+          LayoutTableRow {TR} at (0,955) size 455x39
+            LayoutTableCell {TD} at (2,955) size 149x39 [r=22 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-23"
+            LayoutTableCell {TD} at (153,955) size 149x39 [r=22 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-23"
+            LayoutTableCell {TD} at (304,955) size 149x39 [r=22 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-23"
+          LayoutTableRow {TR} at (0,996) size 455x39
+            LayoutTableCell {TD} at (2,996) size 149x39 [r=23 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-24"
+            LayoutTableCell {TD} at (153,996) size 149x39 [r=23 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-24"
+            LayoutTableCell {TD} at (304,996) size 149x39 [r=23 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-24"
+          LayoutTableRow {TR} at (0,1037) size 455x39
+            LayoutTableCell {TD} at (2,1037) size 149x39 [r=24 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-25"
+            LayoutTableCell {TD} at (153,1037) size 149x39 [r=24 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-25"
+            LayoutTableCell {TD} at (304,1037) size 149x39 [r=24 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-25"
+          LayoutTableRow {TR} at (0,1078) size 455x39
+            LayoutTableCell {TD} at (2,1078) size 149x39 [r=25 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-26"
+            LayoutTableCell {TD} at (153,1078) size 149x39 [r=25 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-26"
+            LayoutTableCell {TD} at (304,1078) size 149x39 [r=25 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-26"
+          LayoutTableRow {TR} at (0,1119) size 455x39
+            LayoutTableCell {TD} at (2,1119) size 149x39 [r=26 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-27"
+            LayoutTableCell {TD} at (153,1119) size 149x39 [r=26 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-27"
+            LayoutTableCell {TD} at (304,1119) size 149x39 [r=26 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-27"
+          LayoutTableRow {TR} at (0,1160) size 455x39
+            LayoutTableCell {TD} at (2,1160) size 149x39 [r=27 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-28"
+            LayoutTableCell {TD} at (153,1160) size 149x39 [r=27 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-28"
+            LayoutTableCell {TD} at (304,1160) size 149x39 [r=27 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-28"
+          LayoutTableRow {TR} at (0,1201) size 455x39
+            LayoutTableCell {TD} at (2,1201) size 149x39 [r=28 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-29"
+            LayoutTableCell {TD} at (153,1201) size 149x39 [r=28 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-29"
+            LayoutTableCell {TD} at (304,1201) size 149x39 [r=28 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-29"
+          LayoutTableRow {TR} at (0,1242) size 455x39
+            LayoutTableCell {TD} at (2,1242) size 149x39 [r=29 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-30"
+            LayoutTableCell {TD} at (153,1242) size 149x39 [r=29 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-30"
+            LayoutTableCell {TD} at (304,1242) size 149x39 [r=29 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-30"
+          LayoutTableRow {TR} at (0,1283) size 455x39
+            LayoutTableCell {TD} at (2,1283) size 149x39 [r=30 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-31"
+            LayoutTableCell {TD} at (153,1283) size 149x39 [r=30 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-31"
+            LayoutTableCell {TD} at (304,1283) size 149x39 [r=30 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-31"
+      LayoutTable {TABLE} at (0,1368) size 509x1598
+        LayoutTableSection {THEAD} at (0,0) size 509x44
+          LayoutTableRow {TR} at (0,2) size 509x40
+            LayoutTableCell {TH} at (2,2) size 167x40 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 165x37
+                text run at (1,1) width 165: "Column2 1"
+            LayoutTableCell {TH} at (171,2) size 167x40 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 165x37
+                text run at (1,1) width 165: "Column2 2"
+            LayoutTableCell {TH} at (340,2) size 167x40 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 165x37
+                text run at (1,1) width 165: "Column2 3"
+        LayoutTableSection {TBODY} at (0,44) size 509x1554
+          LayoutTableRow {TR} at (0,0) size 509x39
+            LayoutTableCell {TD} at (2,0) size 167x39 [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-1"
+            LayoutTableCell {TD} at (171,0) size 167x39 [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-1"
+            LayoutTableCell {TD} at (340,0) size 167x39 [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-1"
+          LayoutTableRow {TR} at (0,41) size 509x39
+            LayoutTableCell {TD} at (2,41) size 167x39 [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-2"
+            LayoutTableCell {TD} at (171,41) size 167x39 [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-2"
+            LayoutTableCell {TD} at (340,41) size 167x39 [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-2"
+          LayoutTableRow {TR} at (0,82) size 509x39
+            LayoutTableCell {TD} at (2,82) size 167x39 [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-3"
+            LayoutTableCell {TD} at (171,82) size 167x39 [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-3"
+            LayoutTableCell {TD} at (340,82) size 167x39 [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-3"
+          LayoutTableRow {TR} at (0,123) size 509x39
+            LayoutTableCell {TD} at (2,123) size 167x39 [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-4"
+            LayoutTableCell {TD} at (171,123) size 167x39 [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-4"
+            LayoutTableCell {TD} at (340,123) size 167x39 [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-4"
+          LayoutTableRow {TR} at (0,222) size 509x39
+            LayoutTableCell {TD} at (2,222) size 167x39 [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-5"
+            LayoutTableCell {TD} at (171,222) size 167x39 [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-5"
+            LayoutTableCell {TD} at (340,222) size 167x39 [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-5"
+          LayoutTableRow {TR} at (0,263) size 509x39
+            LayoutTableCell {TD} at (2,263) size 167x39 [r=5 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-6"
+            LayoutTableCell {TD} at (171,263) size 167x39 [r=5 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-6"
+            LayoutTableCell {TD} at (340,263) size 167x39 [r=5 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-6"
+          LayoutTableRow {TR} at (0,304) size 509x39
+            LayoutTableCell {TD} at (2,304) size 167x39 [r=6 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-7"
+            LayoutTableCell {TD} at (171,304) size 167x39 [r=6 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-7"
+            LayoutTableCell {TD} at (340,304) size 167x39 [r=6 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-7"
+          LayoutTableRow {TR} at (0,345) size 509x39
+            LayoutTableCell {TD} at (2,345) size 167x39 [r=7 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-8"
+            LayoutTableCell {TD} at (171,345) size 167x39 [r=7 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-8"
+            LayoutTableCell {TD} at (340,345) size 167x39 [r=7 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-8"
+          LayoutTableRow {TR} at (0,386) size 509x39
+            LayoutTableCell {TD} at (2,386) size 167x39 [r=8 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "1-9"
+            LayoutTableCell {TD} at (171,386) size 167x39 [r=8 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "2-9"
+            LayoutTableCell {TD} at (340,386) size 167x39 [r=8 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 47x36
+                text run at (1,1) width 47: "3-9"
+          LayoutTableRow {TR} at (0,427) size 509x39
+            LayoutTableCell {TD} at (2,427) size 167x39 [r=9 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-10"
+            LayoutTableCell {TD} at (171,427) size 167x39 [r=9 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-10"
+            LayoutTableCell {TD} at (340,427) size 167x39 [r=9 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-10"
+          LayoutTableRow {TR} at (0,468) size 509x39
+            LayoutTableCell {TD} at (2,468) size 167x39 [r=10 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "1-11"
+            LayoutTableCell {TD} at (171,468) size 167x39 [r=10 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "2-11"
+            LayoutTableCell {TD} at (340,468) size 167x39 [r=10 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 63x36
+                text run at (1,1) width 63: "3-11"
+          LayoutTableRow {TR} at (0,509) size 509x39
+            LayoutTableCell {TD} at (2,509) size 167x39 [r=11 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-12"
+            LayoutTableCell {TD} at (171,509) size 167x39 [r=11 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-12"
+            LayoutTableCell {TD} at (340,509) size 167x39 [r=11 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-12"
+          LayoutTableRow {TR} at (0,550) size 509x39
+            LayoutTableCell {TD} at (2,550) size 167x39 [r=12 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-13"
+            LayoutTableCell {TD} at (171,550) size 167x39 [r=12 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-13"
+            LayoutTableCell {TD} at (340,550) size 167x39 [r=12 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-13"
+          LayoutTableRow {TR} at (0,591) size 509x39
+            LayoutTableCell {TD} at (2,591) size 167x39 [r=13 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-14"
+            LayoutTableCell {TD} at (171,591) size 167x39 [r=13 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-14"
+            LayoutTableCell {TD} at (340,591) size 167x39 [r=13 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-14"
+          LayoutTableRow {TR} at (0,632) size 509x39
+            LayoutTableCell {TD} at (2,632) size 167x39 [r=14 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-15"
+            LayoutTableCell {TD} at (171,632) size 167x39 [r=14 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-15"
+            LayoutTableCell {TD} at (340,632) size 167x39 [r=14 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-15"
+          LayoutTableRow {TR} at (0,673) size 509x39
+            LayoutTableCell {TD} at (2,673) size 167x39 [r=15 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-16"
+            LayoutTableCell {TD} at (171,673) size 167x39 [r=15 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-16"
+            LayoutTableCell {TD} at (340,673) size 167x39 [r=15 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-16"
+          LayoutTableRow {TR} at (0,714) size 509x39
+            LayoutTableCell {TD} at (2,714) size 167x39 [r=16 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-17"
+            LayoutTableCell {TD} at (171,714) size 167x39 [r=16 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-17"
+            LayoutTableCell {TD} at (340,714) size 167x39 [r=16 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-17"
+          LayoutTableRow {TR} at (0,755) size 509x39
+            LayoutTableCell {TD} at (2,755) size 167x39 [r=17 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-18"
+            LayoutTableCell {TD} at (171,755) size 167x39 [r=17 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-18"
+            LayoutTableCell {TD} at (340,755) size 167x39 [r=17 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-18"
+          LayoutTableRow {TR} at (0,796) size 509x39
+            LayoutTableCell {TD} at (2,796) size 167x39 [r=18 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-19"
+            LayoutTableCell {TD} at (171,796) size 167x39 [r=18 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-19"
+            LayoutTableCell {TD} at (340,796) size 167x39 [r=18 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-19"
+          LayoutTableRow {TR} at (0,837) size 509x39
+            LayoutTableCell {TD} at (2,837) size 167x39 [r=19 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-20"
+            LayoutTableCell {TD} at (171,837) size 167x39 [r=19 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-20"
+            LayoutTableCell {TD} at (340,837) size 167x39 [r=19 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-20"
+          LayoutTableRow {TR} at (0,878) size 509x39
+            LayoutTableCell {TD} at (2,878) size 167x39 [r=20 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-21"
+            LayoutTableCell {TD} at (171,878) size 167x39 [r=20 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-21"
+            LayoutTableCell {TD} at (340,878) size 167x39 [r=20 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-21"
+          LayoutTableRow {TR} at (0,919) size 509x39
+            LayoutTableCell {TD} at (2,919) size 167x39 [r=21 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-22"
+            LayoutTableCell {TD} at (171,919) size 167x39 [r=21 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-22"
+            LayoutTableCell {TD} at (340,919) size 167x39 [r=21 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-22"
+          LayoutTableRow {TR} at (0,1021) size 509x39
+            LayoutTableCell {TD} at (2,1021) size 167x39 [r=22 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-23"
+            LayoutTableCell {TD} at (171,1021) size 167x39 [r=22 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-23"
+            LayoutTableCell {TD} at (340,1021) size 167x39 [r=22 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-23"
+          LayoutTableRow {TR} at (0,1062) size 509x39
+            LayoutTableCell {TD} at (2,1062) size 167x39 [r=23 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-24"
+            LayoutTableCell {TD} at (171,1062) size 167x39 [r=23 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-24"
+            LayoutTableCell {TD} at (340,1062) size 167x39 [r=23 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-24"
+          LayoutTableRow {TR} at (0,1103) size 509x39
+            LayoutTableCell {TD} at (2,1103) size 167x39 [r=24 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-25"
+            LayoutTableCell {TD} at (171,1103) size 167x39 [r=24 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-25"
+            LayoutTableCell {TD} at (340,1103) size 167x39 [r=24 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-25"
+          LayoutTableRow {TR} at (0,1144) size 509x39
+            LayoutTableCell {TD} at (2,1144) size 167x39 [r=25 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-26"
+            LayoutTableCell {TD} at (171,1144) size 167x39 [r=25 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-26"
+            LayoutTableCell {TD} at (340,1144) size 167x39 [r=25 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-26"
+          LayoutTableRow {TR} at (0,1185) size 509x39
+            LayoutTableCell {TD} at (2,1185) size 167x39 [r=26 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-27"
+            LayoutTableCell {TD} at (171,1185) size 167x39 [r=26 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-27"
+            LayoutTableCell {TD} at (340,1185) size 167x39 [r=26 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-27"
+          LayoutTableRow {TR} at (0,1226) size 509x39
+            LayoutTableCell {TD} at (2,1226) size 167x39 [r=27 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-28"
+            LayoutTableCell {TD} at (171,1226) size 167x39 [r=27 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-28"
+            LayoutTableCell {TD} at (340,1226) size 167x39 [r=27 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-28"
+          LayoutTableRow {TR} at (0,1267) size 509x39
+            LayoutTableCell {TD} at (2,1267) size 167x39 [r=28 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-29"
+            LayoutTableCell {TD} at (171,1267) size 167x39 [r=28 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-29"
+            LayoutTableCell {TD} at (340,1267) size 167x39 [r=28 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-29"
+          LayoutTableRow {TR} at (0,1308) size 509x39
+            LayoutTableCell {TD} at (2,1308) size 167x39 [r=29 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-30"
+            LayoutTableCell {TD} at (171,1308) size 167x39 [r=29 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-30"
+            LayoutTableCell {TD} at (340,1308) size 167x39 [r=29 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-30"
+          LayoutTableRow {TR} at (0,1349) size 509x39
+            LayoutTableCell {TD} at (2,1349) size 167x39 [r=30 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-31"
+            LayoutTableCell {TD} at (171,1349) size 167x39 [r=30 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-31"
+            LayoutTableCell {TD} at (340,1349) size 167x39 [r=30 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-31"
+          LayoutTableRow {TR} at (0,1390) size 509x39
+            LayoutTableCell {TD} at (2,1390) size 167x39 [r=31 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-32"
+            LayoutTableCell {TD} at (171,1390) size 167x39 [r=31 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-32"
+            LayoutTableCell {TD} at (340,1390) size 167x39 [r=31 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-32"
+          LayoutTableRow {TR} at (0,1431) size 509x39
+            LayoutTableCell {TD} at (2,1431) size 167x39 [r=32 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-33"
+            LayoutTableCell {TD} at (171,1431) size 167x39 [r=32 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-33"
+            LayoutTableCell {TD} at (340,1431) size 167x39 [r=32 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-33"
+          LayoutTableRow {TR} at (0,1472) size 509x39
+            LayoutTableCell {TD} at (2,1472) size 167x39 [r=33 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-34"
+            LayoutTableCell {TD} at (171,1472) size 167x39 [r=33 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-34"
+            LayoutTableCell {TD} at (340,1472) size 167x39 [r=33 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-34"
+          LayoutTableRow {TR} at (0,1513) size 509x39
+            LayoutTableCell {TD} at (2,1513) size 167x39 [r=34 c=0 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "1-35"
+            LayoutTableCell {TD} at (171,1513) size 167x39 [r=34 c=1 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "2-35"
+            LayoutTableCell {TD} at (340,1513) size 167x39 [r=34 c=2 rs=1 cs=1]
+              LayoutText {#text} at (1,1) size 65x36
+                text run at (1,1) width 65: "3-35"
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-under-multicol-expected.png b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-under-multicol-expected.png
new file mode 100644
index 0000000..b095ed6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-under-multicol-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-under-multicol-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-under-multicol-expected.txt
new file mode 100644
index 0000000..2f045ba8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/printing/thead-under-multicol-expected.txt
@@ -0,0 +1,373 @@
+layer at (0,0) size 800x600 scrollHeight 2016
+  LayoutView at (0,0) size 1561x1193
+layer at (0,0) size 1561x2016 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {HTML} at (0,0) size 1561x2016
+    LayoutBlockFlow {BODY} at (8,8) size 1545x2000
+layer at (8,8) size 1545x2000 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutBlockFlow {DIV} at (0,0) size 1545x2000
+    LayoutMultiColumnSet (anonymous) at (0,0) size 1545x2000
+layer at (8,8) size 765x3840 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutMultiColumnFlowThread (anonymous) at (0,0) size 764.50x3840
+    LayoutTable {TABLE} at (0,0) size 305x3840
+      LayoutTableSection {THEAD} at (0,0) size 305x31
+        LayoutTableRow {TR} at (0,2) size 305x27
+          LayoutTableCell {TH} at (2,2) size 99x27 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 97x24
+              text run at (1,1) width 97: "Column 1"
+          LayoutTableCell {TH} at (103,2) size 99x27 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 97x24
+              text run at (1,1) width 97: "Column 2"
+          LayoutTableCell {TH} at (204,2) size 99x27 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 97x24
+              text run at (1,1) width 97: "Column 3"
+      LayoutTableSection {TBODY} at (0,31) size 305x3809
+        LayoutTableRow {TR} at (0,0) size 305x102
+          LayoutTableCell {TD} at (2,37) size 99x27 [r=0 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-1"
+          LayoutTableCell {TD} at (103,37) size 99x27 [r=0 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-1"
+          LayoutTableCell {TD} at (204,37) size 99x27 [r=0 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-1"
+        LayoutTableRow {TR} at (0,104) size 305x102
+          LayoutTableCell {TD} at (2,141) size 99x27 [r=1 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-2"
+          LayoutTableCell {TD} at (103,141) size 99x27 [r=1 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-2"
+          LayoutTableCell {TD} at (204,141) size 99x27 [r=1 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-2"
+        LayoutTableRow {TR} at (0,208) size 305x102
+          LayoutTableCell {TD} at (2,245) size 99x27 [r=2 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-3"
+          LayoutTableCell {TD} at (103,245) size 99x27 [r=2 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-3"
+          LayoutTableCell {TD} at (204,245) size 99x27 [r=2 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-3"
+        LayoutTableRow {TR} at (0,312) size 305x102
+          LayoutTableCell {TD} at (2,349) size 99x27 [r=3 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-4"
+          LayoutTableCell {TD} at (103,349) size 99x27 [r=3 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-4"
+          LayoutTableCell {TD} at (204,349) size 99x27 [r=3 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-4"
+        LayoutTableRow {TR} at (0,416) size 305x102
+          LayoutTableCell {TD} at (2,453) size 99x27 [r=4 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-5"
+          LayoutTableCell {TD} at (103,453) size 99x27 [r=4 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-5"
+          LayoutTableCell {TD} at (204,453) size 99x27 [r=4 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-5"
+        LayoutTableRow {TR} at (0,520) size 305x102
+          LayoutTableCell {TD} at (2,557) size 99x27 [r=5 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-6"
+          LayoutTableCell {TD} at (103,557) size 99x27 [r=5 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-6"
+          LayoutTableCell {TD} at (204,557) size 99x27 [r=5 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-6"
+        LayoutTableRow {TR} at (0,624) size 305x102
+          LayoutTableCell {TD} at (2,661) size 99x27 [r=6 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-7"
+          LayoutTableCell {TD} at (103,661) size 99x27 [r=6 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-7"
+          LayoutTableCell {TD} at (204,661) size 99x27 [r=6 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-7"
+        LayoutTableRow {TR} at (0,728) size 305x102
+          LayoutTableCell {TD} at (2,765) size 99x27 [r=7 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-8"
+          LayoutTableCell {TD} at (103,765) size 99x27 [r=7 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-8"
+          LayoutTableCell {TD} at (204,765) size 99x27 [r=7 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-8"
+        LayoutTableRow {TR} at (0,832) size 305x102
+          LayoutTableCell {TD} at (2,869) size 99x27 [r=8 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "1-9"
+          LayoutTableCell {TD} at (103,869) size 99x27 [r=8 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "2-9"
+          LayoutTableCell {TD} at (204,869) size 99x27 [r=8 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 31x24
+              text run at (1,1) width 31: "3-9"
+        LayoutTableRow {TR} at (0,936) size 305x102
+          LayoutTableCell {TD} at (2,973) size 99x27 [r=9 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-10"
+          LayoutTableCell {TD} at (103,973) size 99x27 [r=9 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-10"
+          LayoutTableCell {TD} at (204,973) size 99x27 [r=9 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-10"
+        LayoutTableRow {TR} at (0,1040) size 305x102
+          LayoutTableCell {TD} at (2,1077) size 99x27 [r=10 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "1-11"
+          LayoutTableCell {TD} at (103,1077) size 99x27 [r=10 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "2-11"
+          LayoutTableCell {TD} at (204,1077) size 99x27 [r=10 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 42x24
+              text run at (1,1) width 42: "3-11"
+        LayoutTableRow {TR} at (0,1185) size 305x102
+          LayoutTableCell {TD} at (2,1222) size 99x27 [r=11 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-12"
+          LayoutTableCell {TD} at (103,1222) size 99x27 [r=11 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-12"
+          LayoutTableCell {TD} at (204,1222) size 99x27 [r=11 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-12"
+        LayoutTableRow {TR} at (0,1289) size 305x102
+          LayoutTableCell {TD} at (2,1326) size 99x27 [r=12 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-13"
+          LayoutTableCell {TD} at (103,1326) size 99x27 [r=12 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-13"
+          LayoutTableCell {TD} at (204,1326) size 99x27 [r=12 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-13"
+        LayoutTableRow {TR} at (0,1393) size 305x102
+          LayoutTableCell {TD} at (2,1430) size 99x27 [r=13 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-14"
+          LayoutTableCell {TD} at (103,1430) size 99x27 [r=13 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-14"
+          LayoutTableCell {TD} at (204,1430) size 99x27 [r=13 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-14"
+        LayoutTableRow {TR} at (0,1497) size 305x102
+          LayoutTableCell {TD} at (2,1534) size 99x27 [r=14 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-15"
+          LayoutTableCell {TD} at (103,1534) size 99x27 [r=14 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-15"
+          LayoutTableCell {TD} at (204,1534) size 99x27 [r=14 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-15"
+        LayoutTableRow {TR} at (0,1601) size 305x102
+          LayoutTableCell {TD} at (2,1638) size 99x27 [r=15 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-16"
+          LayoutTableCell {TD} at (103,1638) size 99x27 [r=15 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-16"
+          LayoutTableCell {TD} at (204,1638) size 99x27 [r=15 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-16"
+        LayoutTableRow {TR} at (0,1705) size 305x102
+          LayoutTableCell {TD} at (2,1742) size 99x27 [r=16 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-17"
+          LayoutTableCell {TD} at (103,1742) size 99x27 [r=16 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-17"
+          LayoutTableCell {TD} at (204,1742) size 99x27 [r=16 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-17"
+        LayoutTableRow {TR} at (0,1809) size 305x102
+          LayoutTableCell {TD} at (2,1846) size 99x27 [r=17 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-18"
+          LayoutTableCell {TD} at (103,1846) size 99x27 [r=17 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-18"
+          LayoutTableCell {TD} at (204,1846) size 99x27 [r=17 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-18"
+        LayoutTableRow {TR} at (0,1913) size 305x102
+          LayoutTableCell {TD} at (2,1950) size 99x27 [r=18 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-19"
+          LayoutTableCell {TD} at (103,1950) size 99x27 [r=18 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-19"
+          LayoutTableCell {TD} at (204,1950) size 99x27 [r=18 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-19"
+        LayoutTableRow {TR} at (0,2017) size 305x102
+          LayoutTableCell {TD} at (2,2054) size 99x27 [r=19 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-20"
+          LayoutTableCell {TD} at (103,2054) size 99x27 [r=19 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-20"
+          LayoutTableCell {TD} at (204,2054) size 99x27 [r=19 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-20"
+        LayoutTableRow {TR} at (0,2121) size 305x102
+          LayoutTableCell {TD} at (2,2158) size 99x27 [r=20 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-21"
+          LayoutTableCell {TD} at (103,2158) size 99x27 [r=20 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-21"
+          LayoutTableCell {TD} at (204,2158) size 99x27 [r=20 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-21"
+        LayoutTableRow {TR} at (0,2225) size 305x102
+          LayoutTableCell {TD} at (2,2262) size 99x27 [r=21 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-22"
+          LayoutTableCell {TD} at (103,2262) size 99x27 [r=21 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-22"
+          LayoutTableCell {TD} at (204,2262) size 99x27 [r=21 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-22"
+        LayoutTableRow {TR} at (0,2370) size 305x102
+          LayoutTableCell {TD} at (2,2407) size 99x27 [r=22 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-23"
+          LayoutTableCell {TD} at (103,2407) size 99x27 [r=22 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-23"
+          LayoutTableCell {TD} at (204,2407) size 99x27 [r=22 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-23"
+        LayoutTableRow {TR} at (0,2474) size 305x102
+          LayoutTableCell {TD} at (2,2511) size 99x27 [r=23 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-24"
+          LayoutTableCell {TD} at (103,2511) size 99x27 [r=23 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-24"
+          LayoutTableCell {TD} at (204,2511) size 99x27 [r=23 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-24"
+        LayoutTableRow {TR} at (0,2578) size 305x102
+          LayoutTableCell {TD} at (2,2615) size 99x27 [r=24 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-25"
+          LayoutTableCell {TD} at (103,2615) size 99x27 [r=24 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-25"
+          LayoutTableCell {TD} at (204,2615) size 99x27 [r=24 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-25"
+        LayoutTableRow {TR} at (0,2682) size 305x102
+          LayoutTableCell {TD} at (2,2719) size 99x27 [r=25 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-26"
+          LayoutTableCell {TD} at (103,2719) size 99x27 [r=25 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-26"
+          LayoutTableCell {TD} at (204,2719) size 99x27 [r=25 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-26"
+        LayoutTableRow {TR} at (0,2786) size 305x102
+          LayoutTableCell {TD} at (2,2823) size 99x27 [r=26 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-27"
+          LayoutTableCell {TD} at (103,2823) size 99x27 [r=26 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-27"
+          LayoutTableCell {TD} at (204,2823) size 99x27 [r=26 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-27"
+        LayoutTableRow {TR} at (0,2890) size 305x102
+          LayoutTableCell {TD} at (2,2927) size 99x27 [r=27 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-28"
+          LayoutTableCell {TD} at (103,2927) size 99x27 [r=27 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-28"
+          LayoutTableCell {TD} at (204,2927) size 99x27 [r=27 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-28"
+        LayoutTableRow {TR} at (0,2994) size 305x102
+          LayoutTableCell {TD} at (2,3031) size 99x27 [r=28 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-29"
+          LayoutTableCell {TD} at (103,3031) size 99x27 [r=28 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-29"
+          LayoutTableCell {TD} at (204,3031) size 99x27 [r=28 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-29"
+        LayoutTableRow {TR} at (0,3185) size 305x102
+          LayoutTableCell {TD} at (2,3222) size 99x27 [r=29 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-30"
+          LayoutTableCell {TD} at (103,3222) size 99x27 [r=29 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-30"
+          LayoutTableCell {TD} at (204,3222) size 99x27 [r=29 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-30"
+        LayoutTableRow {TR} at (0,3289) size 305x102
+          LayoutTableCell {TD} at (2,3326) size 99x27 [r=30 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-31"
+          LayoutTableCell {TD} at (103,3326) size 99x27 [r=30 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-31"
+          LayoutTableCell {TD} at (204,3326) size 99x27 [r=30 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-31"
+        LayoutTableRow {TR} at (0,3393) size 305x102
+          LayoutTableCell {TD} at (2,3430) size 99x27 [r=31 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-32"
+          LayoutTableCell {TD} at (103,3430) size 99x27 [r=31 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-32"
+          LayoutTableCell {TD} at (204,3430) size 99x27 [r=31 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-32"
+        LayoutTableRow {TR} at (0,3497) size 305x102
+          LayoutTableCell {TD} at (2,3534) size 99x27 [r=32 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-33"
+          LayoutTableCell {TD} at (103,3534) size 99x27 [r=32 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-33"
+          LayoutTableCell {TD} at (204,3534) size 99x27 [r=32 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-33"
+        LayoutTableRow {TR} at (0,3601) size 305x102
+          LayoutTableCell {TD} at (2,3638) size 99x27 [r=33 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-34"
+          LayoutTableCell {TD} at (103,3638) size 99x27 [r=33 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-34"
+          LayoutTableCell {TD} at (204,3638) size 99x27 [r=33 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-34"
+        LayoutTableRow {TR} at (0,3705) size 305x102
+          LayoutTableCell {TD} at (2,3742) size 99x27 [r=34 c=0 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "1-35"
+          LayoutTableCell {TD} at (103,3742) size 99x27 [r=34 c=1 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "2-35"
+          LayoutTableCell {TD} at (204,3742) size 99x27 [r=34 c=2 rs=1 cs=1]
+            LayoutText {#text} at (1,1) size 43x24
+              text run at (1,1) width 43: "3-35"
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index df97cbd..1b030abd 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -259,6 +259,7 @@
     property protocol
     property referrerPolicy
     property rel
+    property relList
     property rev
     property search
     property shape
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 342e410..c5e099c 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1550,6 +1550,7 @@
     getter protocol
     getter referrerPolicy
     getter rel
+    getter relList
     getter rev
     getter search
     getter shape
@@ -1575,6 +1576,7 @@
     setter protocol
     setter referrerPolicy
     setter rel
+    setter relList
     setter rev
     setter search
     setter shape
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index 0e91038..53e6209 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -270,6 +270,7 @@
     property protocol
     property referrerPolicy
     property rel
+    property relList
     property rev
     property search
     property shape
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 0e60a5f..21d7ed6 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -2146,6 +2146,7 @@
     getter protocol
     getter referrerPolicy
     getter rel
+    getter relList
     getter rev
     getter search
     getter shape
@@ -2171,6 +2172,7 @@
     setter protocol
     setter referrerPolicy
     setter rel
+    setter relList
     setter rev
     setter search
     setter shape
diff --git a/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h b/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h
index 6aec285..13072a5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h
+++ b/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h
@@ -8,7 +8,7 @@
 #include <type_traits>
 #include "bindings/core/v8/IDLTypesBase.h"
 #include "bindings/core/v8/NativeValueTraits.h"
-#include "bindings/core/v8/V8BindingForCore.h"
+#include "platform/bindings/V8Binding.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Optional.h"
 #include "platform/wtf/TypeTraits.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/ReferrerScriptInfo.h b/third_party/WebKit/Source/bindings/core/v8/ReferrerScriptInfo.h
index c270f07b..85bc6c1 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ReferrerScriptInfo.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ReferrerScriptInfo.h
@@ -22,7 +22,7 @@
 // https://html.spec.whatwg.org/multipage/webappapis.html#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability)
 class CORE_EXPORT ReferrerScriptInfo {
  public:
-  ReferrerScriptInfo() = default;
+  ReferrerScriptInfo() {}
   ReferrerScriptInfo(const KURL& base_url,
                      network::mojom::FetchCredentialsMode credentials_mode,
                      const String& nonce,
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp
index c9786b7..1ec83c8 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffectModelTest.cpp
@@ -38,24 +38,23 @@
 #include "core/animation/animatable/AnimatableUnknown.h"
 #include "core/css/CSSPrimitiveValue.h"
 #include "core/dom/Element.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class AnimationKeyframeEffectModel : public ::testing::Test {
+class AnimationKeyframeEffectModel : public PageTestBase {
  protected:
   void SetUp() override {
-    page_holder = DummyPageHolder::Create();
-    document = &page_holder->GetDocument();
-    element = document->createElement("foo");
+    PageTestBase::SetUp(IntSize());
+    element = GetDocument().createElement("foo");
   }
 
   void ExpectLengthValue(double expected_value,
                          scoped_refptr<Interpolation> interpolation_value) {
     ActiveInterpolations interpolations;
     interpolations.push_back(interpolation_value);
-    EnsureInterpolatedValueCached(interpolations, *document, element);
+    EnsureInterpolatedValueCached(interpolations, GetDocument(), element);
 
     const TypedInterpolationValue* typed_value =
         ToInvalidatableInterpolation(interpolation_value.get())
@@ -73,7 +72,7 @@
       scoped_refptr<Interpolation> interpolation_value) {
     ActiveInterpolations interpolations;
     interpolations.push_back(interpolation_value);
-    EnsureInterpolatedValueCached(interpolations, *document, element);
+    EnsureInterpolatedValueCached(interpolations, GetDocument(), element);
 
     const TypedInterpolationValue* typed_value =
         ToInvalidatableInterpolation(interpolation_value.get())
@@ -87,8 +86,6 @@
     EXPECT_EQ(expected_value, css_value->CssText());
   }
 
-  std::unique_ptr<DummyPageHolder> page_holder;
-  Persistent<Document> document;
   Persistent<Element> element;
 };
 
diff --git a/third_party/WebKit/Source/core/css/CSSCalculationValue.cpp b/third_party/WebKit/Source/core/css/CSSCalculationValue.cpp
index b7b982c..af176c1 100644
--- a/third_party/WebKit/Source/core/css/CSSCalculationValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSCalculationValue.cpp
@@ -681,24 +681,11 @@
   return OK;
 }
 
-namespace {
-
-CSSCalcExpressionNode* CreateCalcBinaryOperation(CSSCalcExpressionNode* lhs,
-                                                 CSSCalcExpressionNode* rhs,
-                                                 CalcOperator op,
-                                                 bool simplify) {
-  if (simplify)
-    return CSSCalcBinaryOperation::CreateSimplified(lhs, rhs, op);
-  return CSSCalcBinaryOperation::Create(lhs, rhs, op);
-}
-
-}  // namespace
-
 class CSSCalcExpressionNodeParser {
   STACK_ALLOCATED();
 
  public:
-  CSSCalcExpressionNodeParser(bool simplify) : simplify_(simplify) {}
+  CSSCalcExpressionNodeParser() {}
 
   CSSCalcExpressionNode* ParseCalc(CSSParserTokenRange tokens) {
     Value result;
@@ -779,9 +766,9 @@
       if (!ParseValueTerm(tokens, depth, &rhs))
         return false;
 
-      result->value = CreateCalcBinaryOperation(
+      result->value = CSSCalcBinaryOperation::CreateSimplified(
           result->value, rhs.value,
-          static_cast<CalcOperator>(operator_character), simplify_);
+          static_cast<CalcOperator>(operator_character));
 
       if (!result->value)
         return false;
@@ -814,9 +801,9 @@
       if (!ParseValueMultiplicativeExpression(tokens, depth, &rhs))
         return false;
 
-      result->value = CreateCalcBinaryOperation(
+      result->value = CSSCalcBinaryOperation::CreateSimplified(
           result->value, rhs.value,
-          static_cast<CalcOperator>(operator_character), simplify_);
+          static_cast<CalcOperator>(operator_character));
 
       if (!result->value)
         return false;
@@ -830,9 +817,6 @@
                             Value* result) {
     return ParseAdditiveValueExpression(tokens, depth, result);
   }
-
- private:
-  const bool simplify_;
 };
 
 CSSCalcExpressionNode* CSSCalcValue::CreateExpressionNode(
@@ -863,15 +847,7 @@
 
 CSSCalcValue* CSSCalcValue::Create(const CSSParserTokenRange& tokens,
                                    ValueRange range) {
-  CSSCalcExpressionNodeParser parser(false /* simplify */);
-  CSSCalcExpressionNode* expression = parser.ParseCalc(tokens);
-
-  return expression ? new CSSCalcValue(expression, range) : nullptr;
-}
-
-CSSCalcValue* CSSCalcValue::CreateSimplified(const CSSParserTokenRange& tokens,
-                                             ValueRange range) {
-  CSSCalcExpressionNodeParser parser(true /* simplify */);
+  CSSCalcExpressionNodeParser parser;
   CSSCalcExpressionNode* expression = parser.ParseCalc(tokens);
 
   return expression ? new CSSCalcValue(expression, range) : nullptr;
diff --git a/third_party/WebKit/Source/core/css/CSSCalculationValue.h b/third_party/WebKit/Source/core/css/CSSCalculationValue.h
index 8aee4a4..ad2fe770 100644
--- a/third_party/WebKit/Source/core/css/CSSCalculationValue.h
+++ b/third_party/WebKit/Source/core/css/CSSCalculationValue.h
@@ -109,7 +109,6 @@
 class CORE_EXPORT CSSCalcValue : public GarbageCollected<CSSCalcValue> {
  public:
   static CSSCalcValue* Create(const CSSParserTokenRange&, ValueRange);
-  static CSSCalcValue* CreateSimplified(const CSSParserTokenRange&, ValueRange);
   static CSSCalcValue* Create(CSSCalcExpressionNode*,
                               ValueRange = kValueRangeAll);
 
diff --git a/third_party/WebKit/Source/core/css/CSSGroupingRule.idl b/third_party/WebKit/Source/core/css/CSSGroupingRule.idl
index b135abf..63f2b8e 100644
--- a/third_party/WebKit/Source/core/css/CSSGroupingRule.idl
+++ b/third_party/WebKit/Source/core/css/CSSGroupingRule.idl
@@ -4,7 +4,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
 
-interface CSSGroupingRule : CSSRule {
+[
+    Exposed=Window
+] interface CSSGroupingRule : CSSRule {
     [SameObject] readonly attribute CSSRuleList cssRules;
     [RaisesException, CallWith=ExecutionContext] unsigned long insertRule(DOMString rule, unsigned long index);
     [RaisesException] void deleteRule(unsigned long index);
diff --git a/third_party/WebKit/Source/core/css/CSSImportRule.idl b/third_party/WebKit/Source/core/css/CSSImportRule.idl
index b298deb..5d51822 100644
--- a/third_party/WebKit/Source/core/css/CSSImportRule.idl
+++ b/third_party/WebKit/Source/core/css/CSSImportRule.idl
@@ -20,7 +20,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssimportrule-interface
 
-interface CSSImportRule : CSSRule {
+[
+    Exposed=Window
+] interface CSSImportRule : CSSRule {
     readonly attribute DOMString href;
     // TODO(foolip): media should have [PutForwards=mediaText].
     [SameObject] readonly attribute MediaList media;
diff --git a/third_party/WebKit/Source/core/css/CSSNamespaceRule.idl b/third_party/WebKit/Source/core/css/CSSNamespaceRule.idl
index 64197ca4..f9f9813 100644
--- a/third_party/WebKit/Source/core/css/CSSNamespaceRule.idl
+++ b/third_party/WebKit/Source/core/css/CSSNamespaceRule.idl
@@ -4,7 +4,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface
 
-interface CSSNamespaceRule : CSSRule {
+[
+    Exposed=Window
+] interface CSSNamespaceRule : CSSRule {
 
     readonly attribute DOMString namespaceURI;
     readonly attribute DOMString prefix;
diff --git a/third_party/WebKit/Source/core/css/CSSPageRule.idl b/third_party/WebKit/Source/core/css/CSSPageRule.idl
index 28d909440..01ce1c7 100644
--- a/third_party/WebKit/Source/core/css/CSSPageRule.idl
+++ b/third_party/WebKit/Source/core/css/CSSPageRule.idl
@@ -25,7 +25,9 @@
 // margin at-rules should be implemented crbug.com/320370, since the
 // spec https://drafts.csswg.org/css-page/#at-page-rule allows only
 // margin at-rules inside @page.
-interface CSSPageRule : CSSRule {
+[
+    Exposed=Window
+] interface CSSPageRule : CSSRule {
     [SetterCallWith=ExecutionContext] attribute DOMString selectorText;
     // TODO(foolip): style should have [PutForwards=cssText].
     [SameObject] readonly attribute CSSStyleDeclaration style;
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 3e60f26..8e787b3 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -1837,7 +1837,7 @@
     },
     {
       name: "offset-anchor",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       runtime_flag: "CSSOffsetPositionAnchor",
       field_group: "*",
@@ -1858,7 +1858,7 @@
     },
     {
       name: "offset-path",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       field_group: "*",
       field_template: "pointer",
@@ -1870,7 +1870,7 @@
     },
     {
       name: "offset-position",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       runtime_flag: "CSSOffsetPositionAnchor",
       field_group: "*",
@@ -1882,7 +1882,7 @@
     },
     {
       name: "offset-rotate",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       field_group: "*",
       field_template: "external",
@@ -4002,7 +4002,7 @@
         "offset-position", "offset-path", "offset-distance", "offset-rotate",
         "offset-anchor"
       ],
-      property_methods: ["ParseShorthand"],
+      property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
     },
     {
       name: "outline",
diff --git a/third_party/WebKit/Source/core/css/CSSRule.idl b/third_party/WebKit/Source/core/css/CSSRule.idl
index 03f6ba403..6de5c97 100644
--- a/third_party/WebKit/Source/core/css/CSSRule.idl
+++ b/third_party/WebKit/Source/core/css/CSSRule.idl
@@ -20,7 +20,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssrule-interface
 
-interface CSSRule {
+[
+    Exposed=Window
+] interface CSSRule {
     const unsigned short STYLE_RULE = 1;
     const unsigned short CHARSET_RULE = 2;
     const unsigned short IMPORT_RULE = 3;
diff --git a/third_party/WebKit/Source/core/css/CSSRuleList.idl b/third_party/WebKit/Source/core/css/CSSRuleList.idl
index d6356a7..f1656adc 100644
--- a/third_party/WebKit/Source/core/css/CSSRuleList.idl
+++ b/third_party/WebKit/Source/core/css/CSSRuleList.idl
@@ -26,7 +26,9 @@
 // https://drafts.csswg.org/cssom/#the-cssrulelist-interface
 
 // TODO(foolip): CSSRuleList should be an [ArrayClass].
-interface CSSRuleList {
+[
+    Exposed=Window
+] interface CSSRuleList {
     [Measure] getter CSSRule? item(unsigned long index);
     readonly attribute unsigned long length;
 };
diff --git a/third_party/WebKit/Source/core/css/CSSStyleDeclaration.idl b/third_party/WebKit/Source/core/css/CSSStyleDeclaration.idl
index 8715c4a1..1fd427b 100644
--- a/third_party/WebKit/Source/core/css/CSSStyleDeclaration.idl
+++ b/third_party/WebKit/Source/core/css/CSSStyleDeclaration.idl
@@ -20,7 +20,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface
 
-interface CSSStyleDeclaration {
+[
+    Exposed=Window
+] interface CSSStyleDeclaration {
     [CEReactions, RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString cssText;
     readonly attribute unsigned long length;
     getter DOMString item(unsigned long index);
diff --git a/third_party/WebKit/Source/core/css/CSSStyleRule.idl b/third_party/WebKit/Source/core/css/CSSStyleRule.idl
index d2373f9..c5792e9ab 100644
--- a/third_party/WebKit/Source/core/css/CSSStyleRule.idl
+++ b/third_party/WebKit/Source/core/css/CSSStyleRule.idl
@@ -20,7 +20,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssstylerule-interface
 
-interface CSSStyleRule : CSSRule {
+[
+    Exposed=Window
+] interface CSSStyleRule : CSSRule {
     [SetterCallWith=ExecutionContext] attribute DOMString selectorText;
     [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
     [SameObject, RuntimeEnabled=CSSTypedOM] readonly attribute StylePropertyMap attributeStyleMap;
diff --git a/third_party/WebKit/Source/core/css/CSSStyleSheet.idl b/third_party/WebKit/Source/core/css/CSSStyleSheet.idl
index c966596..1251d19 100644
--- a/third_party/WebKit/Source/core/css/CSSStyleSheet.idl
+++ b/third_party/WebKit/Source/core/css/CSSStyleSheet.idl
@@ -20,7 +20,9 @@
 
 // https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
 
-interface CSSStyleSheet : StyleSheet {
+[
+    Exposed=Window
+] interface CSSStyleSheet : StyleSheet {
     readonly attribute CSSRule? ownerRule;
     [SameObject, RaisesException] readonly attribute CSSRuleList cssRules;
     [RaisesException] unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index a6be797..4cd8a20 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -386,20 +386,6 @@
       style);
 }
 
-static CSSValue* ValueForPosition(const LengthPoint& position,
-                                  const ComputedStyle& style) {
-  DCHECK_EQ(position.X().IsAuto(), position.Y().IsAuto());
-  if (position.X().IsAuto())
-    return CSSIdentifierValue::Create(CSSValueAuto);
-
-  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
-      position.X(), style));
-  list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
-      position.Y(), style));
-  return list;
-}
-
 static CSSValueID IdentifierForFamily(const AtomicString& family) {
   if (family == FontFamilyNames::webkit_cursive)
     return CSSValueCursive;
@@ -1686,45 +1672,6 @@
   return list;
 }
 
-CSSValue* ComputedStyleCSSValueMapping::ValueForOffset(
-    const ComputedStyle& style,
-    const LayoutObject* layout_object,
-    Node* styled_node,
-    bool allow_visited_style) {
-  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
-    CSSValue* position = ValueForPosition(style.OffsetPosition(), style);
-    if (!position->IsIdentifierValue())
-      list->Append(*position);
-    else
-      DCHECK(ToCSSIdentifierValue(position)->GetValueID() == CSSValueAuto);
-  }
-
-  static const CSSProperty* longhands[3] = {&GetCSSPropertyOffsetPath(),
-                                            &GetCSSPropertyOffsetDistance(),
-                                            &GetCSSPropertyOffsetRotate()};
-  for (const CSSProperty* longhand : longhands) {
-    const CSSValue* value = ComputedStyleCSSValueMapping::Get(
-        *longhand, style, layout_object, styled_node, allow_visited_style);
-    DCHECK(value);
-    list->Append(*value);
-  }
-
-  if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
-    CSSValue* anchor = ValueForPosition(style.OffsetAnchor(), style);
-    if (!anchor->IsIdentifierValue()) {
-      // Add a slash before anchor.
-      CSSValueList* result = CSSValueList::CreateSlashSeparated();
-      result->Append(*list);
-      result->Append(*anchor);
-      return result;
-    } else {
-      DCHECK(ToCSSIdentifierValue(anchor)->GetValueID() == CSSValueAuto);
-    }
-  }
-  return list;
-}
-
 CSSValue* ComputedStyleCSSValueMapping::ValueForFont(
     const ComputedStyle& style) {
   // Add a slash between size and line-height.
@@ -2870,29 +2817,6 @@
       return ValuesForInlineBlockShorthand(scrollSnapMarginInlineShorthand(),
                                            style, layout_object, styled_node,
                                            allow_visited_style);
-    case CSSPropertyOffset:
-      return ValueForOffset(style, layout_object, styled_node,
-                            allow_visited_style);
-
-    case CSSPropertyOffsetAnchor:
-      return ValueForPosition(style.OffsetAnchor(), style);
-
-    case CSSPropertyOffsetPosition:
-      return ValueForPosition(style.OffsetPosition(), style);
-
-    case CSSPropertyOffsetPath:
-      if (const BasicShape* style_motion_path = style.OffsetPath())
-        return ValueForBasicShape(style, style_motion_path);
-      return CSSIdentifierValue::Create(CSSValueNone);
-
-    case CSSPropertyOffsetRotate: {
-      CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-      if (style.OffsetRotate().type == kOffsetRotationAuto)
-        list->Append(*CSSIdentifierValue::Create(CSSValueAuto));
-      list->Append(*CSSPrimitiveValue::Create(
-          style.OffsetRotate().angle, CSSPrimitiveValue::UnitType::kDegrees));
-      return list;
-    }
     // SVG properties.
     case CSSPropertyFill:
       return AdjustSVGPaintForCurrentColor(
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index 1d56d1d..78f6c4d 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -248,7 +248,7 @@
       field_template: "external",
       include_paths: ["platform/fonts/Font.h"],
       type_name: "Font",
-      field_group: "inherited",
+      field_group: "inherited->font",
       inherited: true,
       default_value: "Font()",
       computed_style_custom_functions: ["getter", "setter"],
diff --git a/third_party/WebKit/Source/core/css/MediaList.idl b/third_party/WebKit/Source/core/css/MediaList.idl
index 06705b5..fb08328 100644
--- a/third_party/WebKit/Source/core/css/MediaList.idl
+++ b/third_party/WebKit/Source/core/css/MediaList.idl
@@ -26,7 +26,9 @@
 // https://drafts.csswg.org/cssom/#the-medialist-interface
 
 // TODO(foolip): MediaList should be an [ArrayClass].
-interface MediaList {
+[
+    Exposed=Window
+] interface MediaList {
     // TODO(foolip): [TreatNullAs=EmptyString] stringifier attribute DOMString mediaText;
     attribute DOMString? mediaText;
     readonly attribute unsigned long length;
diff --git a/third_party/WebKit/Source/core/css/MediaQueryList.idl b/third_party/WebKit/Source/core/css/MediaQueryList.idl
index bc417ccc..915600b 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryList.idl
+++ b/third_party/WebKit/Source/core/css/MediaQueryList.idl
@@ -20,7 +20,8 @@
 // https://drafts.csswg.org/cssom-view/#the-mediaquerylist-interface
 
 [
-    ActiveScriptWrappable
+    ActiveScriptWrappable,
+    Exposed=Window
 ] interface MediaQueryList : EventTarget {
     readonly attribute DOMString media;
     readonly attribute boolean matches;
diff --git a/third_party/WebKit/Source/core/css/MediaQueryListEvent.idl b/third_party/WebKit/Source/core/css/MediaQueryListEvent.idl
index 094e9a20..fdc30d5 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryListEvent.idl
+++ b/third_party/WebKit/Source/core/css/MediaQueryListEvent.idl
@@ -5,6 +5,7 @@
 // https://drafts.csswg.org/cssom-view/#mediaquerylistevent
 
 [
+    Exposed=Window,
     Constructor(DOMString type, optional MediaQueryListEventInit eventInitDict)
 ] interface MediaQueryListEvent : Event {
     readonly attribute DOMString media;
diff --git a/third_party/WebKit/Source/core/css/StyleSheet.idl b/third_party/WebKit/Source/core/css/StyleSheet.idl
index 6864cc81..3da7328 100644
--- a/third_party/WebKit/Source/core/css/StyleSheet.idl
+++ b/third_party/WebKit/Source/core/css/StyleSheet.idl
@@ -20,7 +20,9 @@
 
 // https://drafts.csswg.org/cssom/#the-stylesheet-interface
 
-interface StyleSheet {
+[
+    Exposed=Window
+] interface StyleSheet {
     readonly attribute DOMString type;
     readonly attribute DOMString? href;
     // TODO(foolip): ownerNode should be (Element or ProcessingInstruction).
diff --git a/third_party/WebKit/Source/core/css/StyleSheetList.idl b/third_party/WebKit/Source/core/css/StyleSheetList.idl
index b0b9bf6..79e97b9 100644
--- a/third_party/WebKit/Source/core/css/StyleSheetList.idl
+++ b/third_party/WebKit/Source/core/css/StyleSheetList.idl
@@ -21,7 +21,9 @@
 // https://drafts.csswg.org/cssom/#the-stylesheetlist-interface
 
 // TODO(foolip): StyleSheetList should be an [ArrayClass].
-interface StyleSheetList {
+[
+    Exposed=Window
+] interface StyleSheetList {
     [Measure] getter StyleSheet? item(unsigned long index);
     readonly attribute unsigned long length;
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
index bc225c0..a4d3da1 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.cpp
@@ -190,8 +190,7 @@
     const CSSParserToken& token = range.Peek();
     if (token.FunctionId() == CSSValueCalc ||
         token.FunctionId() == CSSValueWebkitCalc) {
-      calc_value_ =
-          CSSCalcValue::CreateSimplified(ConsumeFunction(range_), value_range);
+      calc_value_ = CSSCalcValue::Create(ConsumeFunction(range_), value_range);
     }
   }
 
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
index 4993a1e..a8359bd 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
@@ -12,12 +12,64 @@
 #include "core/css/CSSQuadValue.h"
 #include "core/css/CSSReflectValue.h"
 #include "core/css/CSSValue.h"
+#include "core/css/CSSValueList.h"
 #include "core/css/CSSValuePair.h"
 #include "core/css/StyleColor.h"
 #include "core/css/ZoomAdjustedPixelValue.h"
 
 namespace blink {
 
+CSSValue* ComputedStyleUtils::ValueForPosition(const LengthPoint& position,
+                                               const ComputedStyle& style) {
+  DCHECK_EQ(position.X().IsAuto(), position.Y().IsAuto());
+  if (position.X().IsAuto())
+    return CSSIdentifierValue::Create(CSSValueAuto);
+
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
+      position.X(), style));
+  list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
+      position.Y(), style));
+  return list;
+}
+
+CSSValue* ComputedStyleUtils::ValueForOffset(const ComputedStyle& style,
+                                             const LayoutObject* layout_object,
+                                             Node* styled_node,
+                                             bool allow_visited_style) {
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
+    CSSValue* position = ValueForPosition(style.OffsetPosition(), style);
+    if (!position->IsIdentifierValue())
+      list->Append(*position);
+    else
+      DCHECK(ToCSSIdentifierValue(position)->GetValueID() == CSSValueAuto);
+  }
+
+  static const CSSProperty* longhands[3] = {&GetCSSPropertyOffsetPath(),
+                                            &GetCSSPropertyOffsetDistance(),
+                                            &GetCSSPropertyOffsetRotate()};
+  for (const CSSProperty* longhand : longhands) {
+    const CSSValue* value = longhand->CSSValueFromComputedStyle(
+        style, layout_object, styled_node, allow_visited_style);
+    DCHECK(value);
+    list->Append(*value);
+  }
+
+  if (RuntimeEnabledFeatures::CSSOffsetPositionAnchorEnabled()) {
+    CSSValue* anchor = ValueForPosition(style.OffsetAnchor(), style);
+    if (!anchor->IsIdentifierValue()) {
+      // Add a slash before anchor.
+      CSSValueList* result = CSSValueList::CreateSlashSeparated();
+      result->Append(*list);
+      result->Append(*anchor);
+      return result;
+    }
+    DCHECK(ToCSSIdentifierValue(anchor)->GetValueID() == CSSValueAuto);
+  }
+  return list;
+}
+
 CSSValue* ComputedStyleUtils::CurrentColorOrValidColor(
     const ComputedStyle& style,
     const StyleColor& color) {
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
index f73bb74..ab53995 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
@@ -70,6 +70,13 @@
                                           const ComputedStyle&);
   static CSSValue* ValueForReflection(const StyleReflection*,
                                       const ComputedStyle&);
+  static CSSValue* ValueForPosition(const LengthPoint& position,
+                                    const ComputedStyle&);
+
+  static CSSValue* ValueForOffset(const ComputedStyle&,
+                                  const LayoutObject*,
+                                  Node*,
+                                  bool allow_visited_style);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/OffsetAnchorCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/OffsetAnchorCustom.cpp
index 86dc9509..65245839 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/OffsetAnchorCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/OffsetAnchorCustom.cpp
@@ -8,6 +8,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -25,5 +27,14 @@
                          Optional<WebFeature>());
 }
 
+const CSSValue* OffsetAnchor::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForPosition(style.OffsetAnchor(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/OffsetPathCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/OffsetPathCustom.cpp
index 5602d1b..ef94b035 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/OffsetPathCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/OffsetPathCustom.cpp
@@ -4,6 +4,7 @@
 
 #include "core/css/properties/longhands/OffsetPath.h"
 
+#include "core/css/BasicShapeFunctions.h"
 #include "core/css/properties/CSSParsingUtils.h"
 
 namespace blink {
@@ -16,5 +17,16 @@
   return CSSParsingUtils::ConsumeOffsetPath(range, context);
 }
 
+const CSSValue* OffsetPath::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (const BasicShape* style_motion_path = style.OffsetPath())
+    return ValueForBasicShape(style, style_motion_path);
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/OffsetPositionCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/OffsetPositionCustom.cpp
index 29b1017..806f238 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/OffsetPositionCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/OffsetPositionCustom.cpp
@@ -7,7 +7,9 @@
 #include "core/css/CSSValuePair.h"
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
 #include "core/frame/UseCounter.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -30,5 +32,14 @@
   return value;
 }
 
+const CSSValue* OffsetPosition::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForPosition(style.OffsetPosition(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/OffsetRotateCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/OffsetRotateCustom.cpp
index ef070e8..14706fd 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/OffsetRotateCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/OffsetRotateCustom.cpp
@@ -15,6 +15,19 @@
     const CSSParserLocalContext&) const {
   return CSSParsingUtils::ConsumeOffsetRotate(range, context);
 }
+const CSSValue* OffsetRotate::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  if (style.OffsetRotate().type == kOffsetRotationAuto)
+    list->Append(*CSSIdentifierValue::Create(CSSValueAuto));
+  list->Append(*CSSPrimitiveValue::Create(
+      style.OffsetRotate().angle, CSSPrimitiveValue::UnitType::kDegrees));
+  return list;
+}
 
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/shorthands/OffsetCustom.cpp b/third_party/WebKit/Source/core/css/properties/shorthands/OffsetCustom.cpp
index fbecec8..fb952bc1 100644
--- a/third_party/WebKit/Source/core/css/properties/shorthands/OffsetCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/shorthands/OffsetCustom.cpp
@@ -9,7 +9,9 @@
 #include "core/css/parser/CSSParserLocalContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
 #include "core/css/properties/Longhand.h"
+#include "core/style/ComputedStyle.h"
 #include "platform/runtime_enabled_features.h"
 
 namespace blink {
@@ -116,5 +118,15 @@
   return true;
 }
 
+const CSSValue* Offset::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject* layout_object,
+    Node* styled_node,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForOffset(style, layout_object, styled_node,
+                                            allow_visited_style);
+}
+
 }  // namespace CSSShorthand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/ime/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/ime/InputMethodControllerTest.cpp
index 80d2e31..2c42947 100644
--- a/third_party/WebKit/Source/core/editing/ime/InputMethodControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/ime/InputMethodControllerTest.cpp
@@ -19,40 +19,26 @@
 #include "core/frame/Settings.h"
 #include "core/html/forms/HTMLInputElement.h"
 #include "core/html/forms/HTMLTextAreaElement.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class InputMethodControllerTest : public ::testing::Test {
+class InputMethodControllerTest : public PageTestBase {
  protected:
   InputMethodController& Controller() {
     return GetFrame().GetInputMethodController();
   }
-  Document& GetDocument() const { return *document_; }
-  LocalFrame& GetFrame() const { return dummy_page_holder_->GetFrame(); }
   Element* InsertHTMLElement(const char* element_code, const char* element_id);
   void CreateHTMLWithCompositionInputEventListeners();
   void CreateHTMLWithCompositionEndEventListener(const SelectionType);
-
- private:
-  void SetUp() override;
-
-  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
-  Persistent<Document> document_;
 };
 
-void InputMethodControllerTest::SetUp() {
-  dummy_page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
-  document_ = &dummy_page_holder_->GetDocument();
-  DCHECK(document_);
-}
-
 Element* InputMethodControllerTest::InsertHTMLElement(const char* element_code,
                                                       const char* element_id) {
   GetDocument().write(element_code);
   GetDocument().UpdateStyleAndLayout();
-  Element* element = GetDocument().getElementById(element_id);
+  Element* element = GetElementById(element_id);
   element->focus();
   return element;
 }
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
index 61525ff..88ff269 100644
--- a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
@@ -73,8 +73,10 @@
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/probe/CoreProbes.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "platform/CrossThreadFunctional.h"
 #include "platform/LayoutTestSupport.h"
+#include "platform/WebTaskRunner.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/paint/PaintController.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
@@ -82,12 +84,12 @@
 #include "platform/wtf/PtrUtil.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
+#include "public/platform/InterfaceRegistry.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebFloatRect.h"
 #include "public/platform/WebLayerTreeView.h"
 #include "public/platform/WebRect.h"
 #include "public/platform/WebString.h"
-#include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebSettings.h"
 #include "public/web/WebViewClient.h"
 
@@ -100,13 +102,28 @@
   // though |frame| is meant to be main frame.  See http://crbug.com/526162.
   return frame->ViewImpl() && !frame->Parent();
 }
+
+// TODO(dgozman): somehow get this from a mojo config.
+// See kMaximumMojoMessageSize in services/service_manager/embedder/main.cc.
+const size_t kMaxDevToolsMessageChunkSize = 128 * 1024 * 1024 / 8;
+
+bool ShouldInterruptForMethod(const String& method) {
+  // Keep in sync with DevToolsSession::ShouldSendOnIO.
+  // TODO(dgozman): find a way to share this.
+  return method == "Debugger.pause" || method == "Debugger.setBreakpoint" ||
+         method == "Debugger.setBreakpointByUrl" ||
+         method == "Debugger.removeBreakpoint" ||
+         method == "Debugger.setBreakpointsActive" ||
+         method == "Performance.getMetrics";
+}
+
 }  // namespace
 
 class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
  public:
   ~ClientMessageLoopAdapter() override { instance_ = nullptr; }
 
-  static void EnsureMainThreadDebuggerCreated(WebDevToolsAgentClient* client) {
+  static void EnsureMainThreadDebuggerCreated() {
     if (instance_)
       return;
     std::unique_ptr<ClientMessageLoopAdapter> instance(
@@ -171,8 +188,8 @@
   void RunIfWaitingForDebugger(LocalFrame* frame) override {
     WebDevToolsAgentImpl* agent =
         WebLocalFrameImpl::FromFrame(frame)->DevToolsAgentImpl();
-    if (agent && agent->Client())
-      agent->Client()->ResumeStartup();
+    if (agent && agent->GetClient())
+      agent->GetClient()->ResumeStartup();
   }
 
   bool running_for_debug_break_;
@@ -183,29 +200,114 @@
 
 ClientMessageLoopAdapter* ClientMessageLoopAdapter::instance_ = nullptr;
 
+// Created and stored in unique_ptr on UI.
+// Binds request, receives messages and destroys on IO.
+class WebDevToolsAgentImpl::IOSession : public mojom::blink::DevToolsSession {
+ public:
+  IOSession(int session_id,
+            scoped_refptr<base::SingleThreadTaskRunner> session_task_runner,
+            scoped_refptr<WebTaskRunner> agent_task_runner,
+            CrossThreadWeakPersistent<WebDevToolsAgentImpl> agent,
+            mojom::blink::DevToolsSessionRequest request)
+      : session_id_(session_id),
+        session_task_runner_(session_task_runner),
+        agent_task_runner_(agent_task_runner),
+        agent_(std::move(agent)),
+        binding_(this) {
+    session_task_runner->PostTask(
+        FROM_HERE, ConvertToBaseCallback(CrossThreadBind(
+                       &IOSession::BindInterface, CrossThreadUnretained(this),
+                       WTF::Passed(std::move(request)))));
+  }
+
+  ~IOSession() override {}
+
+  void BindInterface(mojom::blink::DevToolsSessionRequest request) {
+    binding_.Bind(std::move(request));
+  }
+
+  void DeleteSoon() { session_task_runner_->DeleteSoon(FROM_HERE, this); }
+
+  // mojom::blink::DevToolsSession implementation.
+  void DispatchProtocolMessage(int call_id,
+                               const String& method,
+                               const String& message) override {
+    DCHECK(ShouldInterruptForMethod(method));
+    MainThreadDebugger::InterruptMainThreadAndRun(
+        CrossThreadBind(&WebDevToolsAgentImpl::DispatchMessageFromFrontend,
+                        agent_, session_id_, method, message));
+    PostCrossThreadTask(
+        *agent_task_runner_, FROM_HERE,
+        CrossThreadBind(&WebDevToolsAgentImpl::DispatchOnInspectorBackend,
+                        agent_, session_id_, call_id, method, message));
+  }
+
+  void InspectElement(const WebPoint&) override { NOTREACHED(); }
+
+ private:
+  int session_id_;
+  scoped_refptr<base::SingleThreadTaskRunner> session_task_runner_;
+  scoped_refptr<WebTaskRunner> agent_task_runner_;
+  CrossThreadWeakPersistent<WebDevToolsAgentImpl> agent_;
+  mojo::Binding<mojom::blink::DevToolsSession> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSession);
+};
+
+class WebDevToolsAgentImpl::Session : public GarbageCollectedFinalized<Session>,
+                                      public mojom::blink::DevToolsSession {
+ public:
+  Session(int session_id,
+          WebDevToolsAgentImpl* agent,
+          mojom::blink::DevToolsSessionAssociatedRequest request)
+      : session_id_(session_id),
+        agent_(agent),
+        binding_(this, std::move(request)) {}
+
+  ~Session() override {}
+
+  virtual void Trace(blink::Visitor* visitor) { visitor->Trace(agent_); }
+
+  // mojom::blink::DevToolsSession implementation.
+  void DispatchProtocolMessage(int call_id,
+                               const String& method,
+                               const String& message) override {
+    DCHECK(!ShouldInterruptForMethod(method));
+    agent_->DispatchOnInspectorBackend(session_id_, call_id, method, message);
+  }
+
+  void InspectElement(const WebPoint& point) override {
+    agent_->InspectElementAt(session_id_, point);
+  }
+
+ private:
+  int session_id_;
+  Member<WebDevToolsAgentImpl> agent_;
+  mojo::AssociatedBinding<mojom::blink::DevToolsSession> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(Session);
+};
+
 // static
-WebDevToolsAgentImpl* WebDevToolsAgentImpl::Create(
-    WebLocalFrameImpl* frame,
-    WebDevToolsAgentClient* client) {
+WebDevToolsAgentImpl* WebDevToolsAgentImpl::Create(WebLocalFrameImpl* frame) {
   if (!IsMainFrame(frame)) {
-    WebDevToolsAgentImpl* agent =
-        new WebDevToolsAgentImpl(frame, client, false);
+    WebDevToolsAgentImpl* agent = new WebDevToolsAgentImpl(frame, false);
     if (frame->FrameWidget())
       agent->LayerTreeViewChanged(frame->FrameWidget()->GetLayerTreeView());
     return agent;
   }
 
   WebViewImpl* view = frame->ViewImpl();
-  WebDevToolsAgentImpl* agent = new WebDevToolsAgentImpl(frame, client, true);
+  WebDevToolsAgentImpl* agent = new WebDevToolsAgentImpl(frame, true);
   agent->LayerTreeViewChanged(view->LayerTreeView());
   return agent;
 }
 
 WebDevToolsAgentImpl::WebDevToolsAgentImpl(
     WebLocalFrameImpl* web_local_frame_impl,
-    WebDevToolsAgentClient* client,
     bool include_view_agents)
-    : client_(client),
+    : binding_(this),
+      client_(nullptr),
       web_local_frame_impl_(web_local_frame_impl),
       probe_sink_(web_local_frame_impl_->GetFrame()->GetProbeSink()),
       resource_content_loader_(InspectorResourceContentLoader::Create(
@@ -218,6 +320,10 @@
       layer_tree_id_(0) {
   DCHECK(IsMainThread());
   DCHECK(web_local_frame_impl_->GetFrame());
+  web_local_frame_impl_->GetFrame()
+      ->GetInterfaceRegistry()
+      ->AddAssociatedInterface(WTF::BindRepeating(
+          &WebDevToolsAgentImpl::BindRequest, WrapWeakPersistent(this)));
 }
 
 WebDevToolsAgentImpl::~WebDevToolsAgentImpl() {
@@ -225,6 +331,7 @@
 }
 
 void WebDevToolsAgentImpl::Trace(blink::Visitor* visitor) {
+  visitor->Trace(main_sessions_);
   visitor->Trace(web_local_frame_impl_);
   visitor->Trace(probe_sink_);
   visitor->Trace(resource_content_loader_);
@@ -249,12 +356,48 @@
 
   resource_content_loader_->Dispose();
   client_ = nullptr;
+  binding_.Close();
+}
+
+void WebDevToolsAgentImpl::BindRequest(
+    mojom::blink::DevToolsAgentAssociatedRequest request) {
+  binding_.Bind(std::move(request));
+}
+
+void WebDevToolsAgentImpl::AttachDevToolsSession(
+    mojom::blink::DevToolsSessionHostAssociatedPtrInfo host,
+    mojom::blink::DevToolsSessionAssociatedRequest session,
+    mojom::blink::DevToolsSessionRequest io_session,
+    const String& reattach_state) {
+  int session_id = ++last_session_id_;
+
+  if (!reattach_state.IsNull()) {
+    Reattach(session_id, reattach_state);
+  } else {
+    Attach(session_id);
+  }
+
+  main_sessions_.insert(session_id,
+                        new Session(session_id, this, std::move(session)));
+  io_sessions_.insert(
+      session_id,
+      new IOSession(session_id, Platform::Current()->GetIOTaskRunner(),
+                    web_local_frame_impl_->GetFrame()->GetTaskRunner(
+                        TaskType::kUnthrottled),
+                    WrapCrossThreadWeakPersistent(this),
+                    std::move(io_session)));
+
+  mojom::blink::DevToolsSessionHostAssociatedPtr host_ptr;
+  host_ptr.Bind(std::move(host));
+  host_ptr.set_connection_error_handler(
+      WTF::Bind(&WebDevToolsAgentImpl::DetachSession, WrapWeakPersistent(this),
+                session_id));
+  hosts_.insert(session_id, std::move(host_ptr));
 }
 
 InspectorSession* WebDevToolsAgentImpl::InitializeSession(int session_id,
                                                           String* state) {
-  DCHECK(client_);
-  ClientMessageLoopAdapter::EnsureMainThreadDebuggerCreated(client_);
+  ClientMessageLoopAdapter::EnsureMainThreadDebuggerCreated();
   MainThreadDebugger* main_thread_debugger = MainThreadDebugger::Instance();
   v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
 
@@ -365,14 +508,17 @@
     Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
 }
 
+void WebDevToolsAgentImpl::SetClient(WebDevToolsAgentImpl::Client* client) {
+  client_ = client;
+}
+
 void WebDevToolsAgentImpl::Attach(int session_id) {
   if (!session_id || sessions_.find(session_id) != sessions_.end())
     return;
   InitializeSession(session_id, nullptr);
 }
 
-void WebDevToolsAgentImpl::Reattach(int session_id,
-                                    const WebString& saved_state) {
+void WebDevToolsAgentImpl::Reattach(int session_id, const String& saved_state) {
   if (!session_id || sessions_.find(session_id) != sessions_.end())
     return;
   String state = saved_state;
@@ -386,6 +532,17 @@
   DestroySession(session_id);
 }
 
+void WebDevToolsAgentImpl::DetachSession(int session_id) {
+  Detach(session_id);
+  auto it = io_sessions_.find(session_id);
+  if (it != io_sessions_.end()) {
+    it->value->DeleteSoon();
+    io_sessions_.erase(it);
+  }
+  main_sessions_.erase(session_id);
+  hosts_.erase(session_id);
+}
+
 void WebDevToolsAgentImpl::DidCommitLoadForLocalFrame(LocalFrame* frame) {
   resource_container_->DidCommitLoadForLocalFrame(frame);
   resource_content_loader_->DidCommitLoadForLocalFrame(frame);
@@ -430,14 +587,13 @@
     it.value->HideReloadingBlanket();
 }
 
-void WebDevToolsAgentImpl::DispatchOnInspectorBackend(
-    int session_id,
-    int call_id,
-    const WebString& method,
-    const WebString& message) {
+void WebDevToolsAgentImpl::DispatchOnInspectorBackend(int session_id,
+                                                      int call_id,
+                                                      const String& method,
+                                                      const String& message) {
   if (!Attached())
     return;
-  if (WebDevToolsAgent::ShouldInterruptForMethod(method))
+  if (ShouldInterruptForMethod(method))
     MainThreadDebugger::Instance()->TaskRunner()->RunAllTasksDontWait();
   else
     DispatchMessageFromFrontend(session_id, method, message);
@@ -503,8 +659,32 @@
   // protocol response in any of them.
   if (LayoutTestSupport::IsRunningLayoutTest() && call_id)
     FlushProtocolNotifications();
-  if (client_)
+
+  if (client_) {
     client_->SendProtocolMessage(session_id, call_id, response, state);
+    return;
+  }
+
+  auto it = hosts_.find(session_id);
+  if (it == hosts_.end())
+    return;
+
+  bool single_chunk = response.length() < kMaxDevToolsMessageChunkSize;
+  for (size_t pos = 0; pos < response.length();
+       pos += kMaxDevToolsMessageChunkSize) {
+    mojom::blink::DevToolsMessageChunkPtr chunk =
+        mojom::blink::DevToolsMessageChunk::New();
+    chunk->is_first = pos == 0;
+    chunk->message_size = chunk->is_first ? response.length() * 2 : 0;
+    chunk->is_last = pos + kMaxDevToolsMessageChunkSize >= response.length();
+    chunk->call_id = chunk->is_last ? call_id : 0;
+    chunk->post_state =
+        chunk->is_last && !state.IsNull() ? state : g_empty_string;
+    chunk->data = single_chunk
+                      ? response
+                      : response.Substring(pos, kMaxDevToolsMessageChunkSize);
+    it->value->DispatchProtocolMessage(std::move(chunk));
+  }
 }
 
 void WebDevToolsAgentImpl::PageLayoutInvalidated(bool resized) {
@@ -576,38 +756,4 @@
   FlushProtocolNotifications();
 }
 
-void WebDevToolsAgentImpl::RunDebuggerTask(
-    int session_id,
-    std::unique_ptr<WebDevToolsAgent::MessageDescriptor> descriptor) {
-  WebDevToolsAgent* webagent = descriptor->Agent();
-  if (!webagent)
-    return;
-
-  WebDevToolsAgentImpl* agent_impl =
-      static_cast<WebDevToolsAgentImpl*>(webagent);
-  if (agent_impl->Attached()) {
-    agent_impl->DispatchMessageFromFrontend(session_id, descriptor->Method(),
-                                            descriptor->Message());
-  }
-}
-
-void WebDevToolsAgent::InterruptAndDispatch(int session_id,
-                                            MessageDescriptor* raw_descriptor) {
-  // rawDescriptor can't be a std::unique_ptr because interruptAndDispatch is a
-  // WebKit API function.
-  MainThreadDebugger::InterruptMainThreadAndRun(
-      CrossThreadBind(WebDevToolsAgentImpl::RunDebuggerTask, session_id,
-                      WTF::Passed(WTF::WrapUnique(raw_descriptor))));
-}
-
-bool WebDevToolsAgent::ShouldInterruptForMethod(const WebString& method) {
-  // Keep in sync with DevToolsSession::ShouldSendOnIO.
-  // TODO(dgozman): find a way to share this.
-  return method == "Debugger.pause" || method == "Debugger.setBreakpoint" ||
-         method == "Debugger.setBreakpointByUrl" ||
-         method == "Debugger.removeBreakpoint" ||
-         method == "Debugger.setBreakpointsActive" ||
-         method == "Performance.getMetrics";
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h
index de865c5..f13ae5f 100644
--- a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.h
@@ -38,11 +38,12 @@
 #include "core/inspector/InspectorPageAgent.h"
 #include "core/inspector/InspectorSession.h"
 #include "core/inspector/InspectorTracingAgent.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
 #include "public/platform/WebSize.h"
 #include "public/platform/WebThread.h"
-#include "public/web/WebDevToolsAgent.h"
+#include "public/web/devtools_agent.mojom-blink.h"
 
 namespace blink {
 
@@ -52,33 +53,52 @@
 class InspectorResourceContainer;
 class InspectorResourceContentLoader;
 class LocalFrame;
-class WebDevToolsAgentClient;
 class WebLayerTreeView;
 class WebLocalFrameImpl;
-class WebString;
 
 class CORE_EXPORT WebDevToolsAgentImpl final
     : public GarbageCollectedFinalized<WebDevToolsAgentImpl>,
-      public WebDevToolsAgent,
+      public mojom::blink::DevToolsAgent,
       public InspectorTracingAgent::Client,
       public InspectorPageAgent::Client,
       public InspectorSession::Client,
       public InspectorLayerTreeAgent::Client,
       private WebThread::TaskObserver {
  public:
-  static WebDevToolsAgentImpl* Create(WebLocalFrameImpl*,
-                                      WebDevToolsAgentClient*);
+  static WebDevToolsAgentImpl* Create(WebLocalFrameImpl*);
   ~WebDevToolsAgentImpl() override;
   virtual void Trace(blink::Visitor*);
 
   void WillBeDestroyed();
-  WebDevToolsAgentClient* Client() { return client_; }
   void FlushProtocolNotifications();
   void PaintOverlay();
   void LayoutOverlay();
   bool HandleInputEvent(const WebInputEvent&);
   void DispatchBufferedTouchEvents();
 
+  // ------ Deprecated ------
+  // These public methods and client are temporary,
+  // until shared/service workers inspection migrates to Mojo.
+  class Client {
+   public:
+    virtual ~Client() {}
+    virtual void SendProtocolMessage(int session_id,
+                                     int call_id,
+                                     const String& response,
+                                     const String& state) = 0;
+    virtual void ResumeStartup() = 0;
+  };
+  void SetClient(Client*);
+  Client* GetClient() { return client_; }
+  void Attach(int session_id);
+  void Reattach(int session_id, const String& saved_state);
+  void Detach(int session_id);
+  void DispatchOnInspectorBackend(int session_id,
+                                  int call_id,
+                                  const String& method,
+                                  const String& message);
+  // ------ End deprecated ------
+
   // Instrumentation from web/ layer.
   void DidCommitLoadForLocalFrame(LocalFrame*);
   void DidStartProvisionalLoad(LocalFrame*);
@@ -88,21 +108,19 @@
   bool CacheDisabled();
   String EvaluateInOverlayForTesting(const String& script);
 
-  // WebDevToolsAgent implementation.
-  void Attach(int session_id) override;
-  void Reattach(int session_id, const WebString& saved_state) override;
-  void Detach(int session_id) override;
-  void DispatchOnInspectorBackend(int session_id,
-                                  int call_id,
-                                  const WebString& method,
-                                  const WebString& message) override;
-  void InspectElementAt(int session_id, const WebPoint&) override;
-
  private:
   WebDevToolsAgentImpl(WebLocalFrameImpl*,
-                       WebDevToolsAgentClient*,
                        bool include_view_agents);
 
+  void BindRequest(mojom::blink::DevToolsAgentAssociatedRequest);
+
+  // mojom::blink::DevToolsAgent implementation.
+  void AttachDevToolsSession(
+      mojom::blink::DevToolsSessionHostAssociatedPtrInfo,
+      mojom::blink::DevToolsSessionAssociatedRequest main_session,
+      mojom::blink::DevToolsSessionRequest io_session,
+      const String& reattach_state) override;
+
   // InspectorTracingAgent::Client implementation.
   void ShowReloadingBlanket() override;
   void HideReloadingBlanket() override;
@@ -125,19 +143,26 @@
 
   InspectorSession* InitializeSession(int session_id,
                                       String* state);
+  void DetachSession(int session_id);
   void DestroySession(int session_id);
   void DispatchMessageFromFrontend(int session_id,
                                    const String& method,
                                    const String& message);
 
-  friend class WebDevToolsAgent;
-  static void RunDebuggerTask(
-      int session_id,
-      std::unique_ptr<WebDevToolsAgent::MessageDescriptor>);
-
   bool Attached() const { return !!sessions_.size(); }
+  void InspectElementAt(int session_id, const WebPoint&);
 
-  WebDevToolsAgentClient* client_;
+  class Session;
+  class IOSession;
+
+  mojo::AssociatedBinding<mojom::blink::DevToolsAgent> binding_;
+  // TODO(dgozman): drop session ids after workers migrate to Mojo.
+  int last_session_id_ = 0;
+  HeapHashMap<int, Member<Session>> main_sessions_;
+  HashMap<int, IOSession*> io_sessions_;
+  HashMap<int, mojom::blink::DevToolsSessionHostAssociatedPtr> hosts_;
+
+  Client* client_;
   Member<WebLocalFrameImpl> web_local_frame_impl_;
 
   Member<CoreProbeSink> probe_sink_;
diff --git a/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp b/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp
index 6ae7e05..b6135dd 100644
--- a/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp
@@ -68,7 +68,6 @@
 #include "public/platform/WebURLRequest.h"
 #include "public/platform/WebWorkerFetchContext.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
-#include "public/web/WebDevToolsAgent.h"
 #include "public/web/WebSettings.h"
 #include "services/network/public/interfaces/fetch_api.mojom-blink.h"
 
@@ -144,8 +143,8 @@
 
 void WebSharedWorkerImpl::SendProtocolMessage(int session_id,
                                               int call_id,
-                                              const WebString& message,
-                                              const WebString& state) {
+                                              const String& message,
+                                              const String& state) {
   DCHECK(IsMainThread());
   client_->SendDevToolsMessage(session_id, call_id, message, state);
 }
@@ -359,21 +358,21 @@
 }
 
 void WebSharedWorkerImpl::AttachDevTools(int session_id) {
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent)
     devtools_agent->Attach(session_id);
 }
 
 void WebSharedWorkerImpl::ReattachDevTools(int session_id,
                                            const WebString& saved_state) {
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent)
     devtools_agent->Reattach(session_id, saved_state);
   ResumeStartup();
 }
 
 void WebSharedWorkerImpl::DetachDevTools(int session_id) {
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent)
     devtools_agent->Detach(session_id);
 }
@@ -384,7 +383,7 @@
                                                   const WebString& message) {
   if (asked_to_terminate_)
     return;
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent) {
     devtools_agent->DispatchOnInspectorBackend(session_id, call_id, method,
                                                message);
diff --git a/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.h b/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.h
index 948242bf..250110d 100644
--- a/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.h
@@ -43,7 +43,6 @@
 #include "core/workers/WorkerThread.h"
 #include "platform/WebTaskRunner.h"
 #include "public/platform/WebContentSecurityPolicy.h"
-#include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebSharedWorkerClient.h"
 #include "public/web/worker_content_settings_proxy.mojom-blink.h"
 #include "services/service_manager/public/interfaces/interface_provider.mojom-blink.h"
@@ -73,11 +72,11 @@
       WebApplicationCacheHostClient*) override;
   void OnShadowPageInitialized() override;
 
-  // WebDevToolsAgentClient overrides.
+  // WebDevToolsAgentImpl::Client overrides.
   void SendProtocolMessage(int session_id,
                            int call_id,
-                           const WebString&,
-                           const WebString&) override;
+                           const String&,
+                           const String&) override;
   void ResumeStartup() override;
   const WebString& GetInstrumentationToken() override;
 
diff --git a/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp b/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
index 98f3b00..6752383 100644
--- a/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
+++ b/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
@@ -30,7 +30,7 @@
   // not create graphics layers.
   web_view_->GetSettings()->SetAcceleratedCompositingEnabled(false);
 
-  main_frame_->SetDevToolsAgentClient(client_);
+  main_frame_->DevToolsAgentImpl()->SetClient(client_);
 }
 
 WorkerShadowPage::~WorkerShadowPage() {
diff --git a/third_party/WebKit/Source/core/exported/WorkerShadowPage.h b/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
index 5aa32ce1..f7a72b2 100644
--- a/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
+++ b/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
@@ -5,8 +5,8 @@
 #ifndef WorkerShadowPage_h
 #define WorkerShadowPage_h
 
+#include "core/exported/WebDevToolsAgentImpl.h"
 #include "core/frame/WebLocalFrameImpl.h"
-#include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebDocumentLoader.h"
 #include "public/web/WebFrameClient.h"
 #include "public/web/WebView.h"
@@ -33,7 +33,7 @@
 // TODO(kinuko): Make this go away (https://crbug.com/538751).
 class CORE_EXPORT WorkerShadowPage : public WebFrameClient {
  public:
-  class CORE_EXPORT Client : public WebDevToolsAgentClient {
+  class CORE_EXPORT Client : public WebDevToolsAgentImpl::Client {
    public:
     virtual ~Client() {}
 
@@ -74,7 +74,9 @@
   WebDocumentLoader* DocumentLoader() {
     return main_frame_->GetDocumentLoader();
   }
-  WebDevToolsAgent* DevToolsAgent() { return main_frame_->DevToolsAgent(); }
+  WebDevToolsAgentImpl* DevToolsAgent() {
+    return main_frame_->DevToolsAgentImpl();
+  }
 
   bool WasInitialized() const;
 
diff --git a/third_party/WebKit/Source/core/fetch/FormDataBytesConsumerTest.cpp b/third_party/WebKit/Source/core/fetch/FormDataBytesConsumerTest.cpp
index 5ef1e5d3..75134e9 100644
--- a/third_party/WebKit/Source/core/fetch/FormDataBytesConsumerTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/FormDataBytesConsumerTest.cpp
@@ -7,7 +7,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "core/fetch/BytesConsumerTestUtil.h"
 #include "core/html/forms/FormData.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
 #include "core/typed_arrays/DOMTypedArray.h"
 #include "mojo/common/data_pipe_utils.h"
@@ -121,14 +121,9 @@
   String DebugName() const override { return "NoopClient"; }
 };
 
-class FormDataBytesConsumerTest : public ::testing::Test {
+class FormDataBytesConsumerTest : public PageTestBase {
  public:
-  FormDataBytesConsumerTest() : page_(DummyPageHolder::Create()) {}
-
- protected:
-  Document* GetDocument() { return &page_->GetDocument(); }
-
-  std::unique_ptr<DummyPageHolder> page_;
+  void SetUp() override { PageTestBase::SetUp(IntSize()); }
 };
 
 TEST_F(FormDataBytesConsumerTest, TwoPhaseReadFromString) {
@@ -188,7 +183,7 @@
   data->AppendData("hoge", 4);
 
   auto result = (new BytesConsumerTestUtil::TwoPhaseReader(
-                     new FormDataBytesConsumer(GetDocument(), data)))
+                     new FormDataBytesConsumer(&GetDocument(), data)))
                     ->Run();
   EXPECT_EQ(Result::kDone, result.first);
   EXPECT_EQ("foohoge",
@@ -199,7 +194,7 @@
   scoped_refptr<EncodedFormData> data = ComplexFormData();
   MockBytesConsumer* underlying = MockBytesConsumer::Create();
   BytesConsumer* consumer =
-      FormDataBytesConsumer::CreateForTesting(GetDocument(), data, underlying);
+      FormDataBytesConsumer::CreateForTesting(&GetDocument(), data, underlying);
   Checkpoint checkpoint;
 
   const char* buffer = nullptr;
@@ -272,7 +267,7 @@
       data->EncodeMultiPartFormData();
 
   BytesConsumer* consumer =
-      new FormDataBytesConsumer(GetDocument(), input_form_data);
+      new FormDataBytesConsumer(&GetDocument(), input_form_data);
   scoped_refptr<BlobDataHandle> blob_data_handle =
       consumer->DrainAsBlobDataHandle();
   ASSERT_TRUE(blob_data_handle);
@@ -291,7 +286,7 @@
   scoped_refptr<EncodedFormData> input_form_data = ComplexFormData();
 
   BytesConsumer* consumer =
-      new FormDataBytesConsumer(GetDocument(), input_form_data);
+      new FormDataBytesConsumer(&GetDocument(), input_form_data);
   scoped_refptr<BlobDataHandle> blob_data_handle =
       consumer->DrainAsBlobDataHandle();
   ASSERT_TRUE(blob_data_handle);
@@ -339,7 +334,7 @@
       data->EncodeMultiPartFormData();
 
   BytesConsumer* consumer =
-      new FormDataBytesConsumer(GetDocument(), input_form_data);
+      new FormDataBytesConsumer(&GetDocument(), input_form_data);
   EXPECT_EQ(input_form_data, consumer->DrainAsFormData());
   EXPECT_FALSE(consumer->DrainAsBlobDataHandle());
   const char* buffer = nullptr;
@@ -352,7 +347,7 @@
   scoped_refptr<EncodedFormData> input_form_data = ComplexFormData();
 
   BytesConsumer* consumer =
-      new FormDataBytesConsumer(GetDocument(), input_form_data);
+      new FormDataBytesConsumer(&GetDocument(), input_form_data);
   EXPECT_EQ(input_form_data, consumer->DrainAsFormData());
   EXPECT_FALSE(consumer->DrainAsBlobDataHandle());
   const char* buffer = nullptr;
@@ -378,7 +373,7 @@
 TEST_F(FormDataBytesConsumerTest, BeginReadAffectsDrainingWithComplexFormData) {
   MockBytesConsumer* underlying = MockBytesConsumer::Create();
   BytesConsumer* consumer = FormDataBytesConsumer::CreateForTesting(
-      GetDocument(), ComplexFormData(), underlying);
+      &GetDocument(), ComplexFormData(), underlying);
 
   const char* buffer = nullptr;
   size_t available = 0;
@@ -417,7 +412,7 @@
 
   MockBytesConsumer* underlying = MockBytesConsumer::Create();
   BytesConsumer* consumer = FormDataBytesConsumer::CreateForTesting(
-      GetDocument(), input_form_data, underlying);
+      &GetDocument(), input_form_data, underlying);
   Checkpoint checkpoint;
 
   InSequence s;
@@ -439,7 +434,7 @@
 
   MockBytesConsumer* underlying = MockBytesConsumer::Create();
   BytesConsumer* consumer = FormDataBytesConsumer::CreateForTesting(
-      GetDocument(), input_form_data, underlying);
+      &GetDocument(), input_form_data, underlying);
   Checkpoint checkpoint;
 
   InSequence s;
@@ -455,7 +450,7 @@
 // Tests consuming an EncodedFormData with data pipe elements.
 TEST_F(FormDataBytesConsumerTest, DataPipeFormData) {
   scoped_refptr<EncodedFormData> input_form_data = DataPipeFormData();
-  auto* consumer = new FormDataBytesConsumer(GetDocument(), input_form_data);
+  auto* consumer = new FormDataBytesConsumer(&GetDocument(), input_form_data);
   auto* reader = new BytesConsumerTestUtil::TwoPhaseReader(consumer);
   std::pair<BytesConsumer::Result, Vector<char>> result = reader->Run();
   EXPECT_EQ(Result::kDone, result.first);
@@ -466,7 +461,7 @@
 // Tests DrainAsFormData() on an EncodedFormData with data pipe elements.
 TEST_F(FormDataBytesConsumerTest, DataPipeFormData_DrainAsFormData) {
   scoped_refptr<EncodedFormData> input_form_data = DataPipeFormData();
-  auto* consumer = new FormDataBytesConsumer(GetDocument(), input_form_data);
+  auto* consumer = new FormDataBytesConsumer(&GetDocument(), input_form_data);
   scoped_refptr<EncodedFormData> drained_form_data =
       consumer->DrainAsFormData();
   EXPECT_EQ(*input_form_data, *drained_form_data);
@@ -479,7 +474,7 @@
        DataPipeFormData_DrainAsFormDataWhileReading) {
   // Create the consumer and start reading.
   scoped_refptr<EncodedFormData> input_form_data = DataPipeFormData();
-  auto* consumer = new FormDataBytesConsumer(GetDocument(), input_form_data);
+  auto* consumer = new FormDataBytesConsumer(&GetDocument(), input_form_data);
   const char* buffer = nullptr;
   size_t available = 0;
   EXPECT_EQ(BytesConsumer::Result::kOk,
diff --git a/third_party/WebKit/Source/core/frame/Screen.idl b/third_party/WebKit/Source/core/frame/Screen.idl
index 90fa671..44dee75 100644
--- a/third_party/WebKit/Source/core/frame/Screen.idl
+++ b/third_party/WebKit/Source/core/frame/Screen.idl
@@ -28,7 +28,9 @@
 
 // https://drafts.csswg.org/cssom-view/#the-screen-interface
 
-interface Screen {
+[
+    Exposed=Window
+] interface Screen {
     readonly attribute long availWidth;
     readonly attribute long availHeight;
     readonly attribute long width;
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
index 4dc5fc5f..1ed5b47 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
@@ -1755,6 +1755,9 @@
     frame_->GetDocument()->GetMutableSecurityOrigin()->GrantUniversalAccess();
   }
 
+  if (frame_->IsLocalRoot())
+    dev_tools_agent_ = WebDevToolsAgentImpl::Create(this);
+
   if (!owner) {
     // This trace event is needed to detect the main frame of the
     // renderer in telemetry metrics. See crbug.com/692112#c11.
@@ -1974,16 +1977,6 @@
   return autofill_client_;
 }
 
-void WebLocalFrameImpl::SetDevToolsAgentClient(
-    WebDevToolsAgentClient* dev_tools_client) {
-  DCHECK(dev_tools_client);
-  dev_tools_agent_ = WebDevToolsAgentImpl::Create(this, dev_tools_client);
-}
-
-WebDevToolsAgent* WebLocalFrameImpl::DevToolsAgent() {
-  return dev_tools_agent_.Get();
-}
-
 WebLocalFrameImpl* WebLocalFrameImpl::LocalRoot() {
   // This can't use the LocalFrame::localFrameRoot, since it may be called
   // when the WebLocalFrame exists but the core LocalFrame does not.
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
index ccca4750..95191dd9 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
@@ -244,8 +244,6 @@
                                       blink::InterfaceRegistry*) override;
   void SetAutofillClient(WebAutofillClient*) override;
   WebAutofillClient* AutofillClient() override;
-  void SetDevToolsAgentClient(WebDevToolsAgentClient*) override;
-  WebDevToolsAgent* DevToolsAgent() override;
   WebLocalFrameImpl* LocalRoot() override;
   WebFrame* FindFrameByName(const WebString& name) override;
   void SendPings(const WebURL& destination_url) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
index 67f3ab0..be57cf0 100644
--- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
@@ -52,7 +52,8 @@
     : HTMLElement(tag_name, document),
       link_relations_(0),
       was_focused_by_mouse_(false),
-      cached_visited_link_hash_(0) {}
+      cached_visited_link_hash_(0),
+      rel_list_(RelList::Create(this)) {}
 
 HTMLAnchorElement* HTMLAnchorElement::Create(Document& document) {
   return new HTMLAnchorElement(aTag, document);
@@ -220,6 +221,7 @@
     // Do nothing.
   } else if (params.name == relAttr) {
     SetRel(params.new_value);
+    rel_list_->DidUpdateAttributeValue(params.old_value, params.new_value);
   } else {
     HTMLElement::ParseAttribute(params);
   }
@@ -438,4 +440,15 @@
   return request;
 }
 
+void HTMLAnchorElement::Trace(blink::Visitor* visitor) {
+  visitor->Trace(rel_list_);
+  HTMLElement::Trace(visitor);
+}
+
+void HTMLAnchorElement::TraceWrappers(
+    const ScriptWrappableVisitor* visitor) const {
+  visitor->TraceWrappers(rel_list_);
+  HTMLElement::TraceWrappers(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.h b/third_party/WebKit/Source/core/html/HTMLAnchorElement.h
index 9fbd829..0d4fc614 100644
--- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.h
@@ -27,6 +27,7 @@
 #include "core/CoreExport.h"
 #include "core/dom/Document.h"
 #include "core/html/HTMLElement.h"
+#include "core/html/RelList.h"
 #include "core/html_names.h"
 #include "core/url/DOMURLUtils.h"
 #include "platform/LinkHash.h"
@@ -82,12 +83,18 @@
 
   bool HasRel(uint32_t relation) const;
   void SetRel(const AtomicString&);
+  DOMTokenList& relList() const {
+    return static_cast<DOMTokenList&>(*rel_list_);
+  }
 
   LinkHash VisitedLinkHash() const;
   void InvalidateCachedVisitedLinkHash() { cached_visited_link_hash_ = 0; }
 
   void SendPings(const KURL& destination_url) const;
 
+  virtual void Trace(blink::Visitor*);
+  virtual void TraceWrappers(const ScriptWrappableVisitor*) const;
+
  protected:
   HTMLAnchorElement(const QualifiedName&, Document&);
 
@@ -123,6 +130,7 @@
   unsigned link_relations_ : 31;
   unsigned was_focused_by_mouse_ : 1;
   mutable LinkHash cached_visited_link_hash_;
+  TraceWrapperMember<RelList> rel_list_;
 };
 
 inline LinkHash HTMLAnchorElement::VisitedLinkHash() const {
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.idl b/third_party/WebKit/Source/core/html/HTMLAnchorElement.idl
index dc8ef29..d05067c 100644
--- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.idl
@@ -26,7 +26,7 @@
     // FIXME: ping should be a DOMTokenList.
     [CEReactions, Reflect] attribute USVString ping;
     [CEReactions, Reflect] attribute DOMString rel;
-    // FIXME: readonly attribute DOMTokenList relList;
+    [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
     [CEReactions, Reflect] attribute DOMString hreflang;
     [CEReactions, Reflect] attribute DOMString type;
     [CEReactions, Reflect, ReflectOnly=("","no-referrer","origin","no-referrer-when-downgrade","origin-when-cross-origin","unsafe-url"), ReflectMissing="", ReflectInvalid=""] attribute DOMString referrerPolicy;
diff --git a/third_party/WebKit/Source/core/html/RelList.cpp b/third_party/WebKit/Source/core/html/RelList.cpp
index 7726997..f82234e 100644
--- a/third_party/WebKit/Source/core/html/RelList.cpp
+++ b/third_party/WebKit/Source/core/html/RelList.cpp
@@ -6,6 +6,7 @@
 
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
+#include "core/html/HTMLElement.h"
 #include "core/html_names.h"
 #include "core/origin_trials/origin_trials.h"
 #include "platform/runtime_enabled_features.h"
@@ -13,10 +14,12 @@
 
 namespace blink {
 
+using namespace HTMLNames;
+
 RelList::RelList(Element* element)
     : DOMTokenList(*element, HTMLNames::relAttr) {}
 
-static HashSet<AtomicString>& SupportedTokens() {
+static HashSet<AtomicString>& SupportedTokensLink() {
   DEFINE_STATIC_LOCAL(
       HashSet<AtomicString>, tokens,
       ({
@@ -28,13 +31,28 @@
   return tokens;
 }
 
+static HashSet<AtomicString>& SupportedTokensAnchor() {
+  DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tokens,
+                      ({
+                          "noreferrer", "noopener",
+                      }));
+
+  return tokens;
+}
+
 bool RelList::ValidateTokenValue(const AtomicString& token_value,
                                  ExceptionState&) const {
-  if (SupportedTokens().Contains(token_value))
+  //  https://html.spec.whatwg.org/multipage/links.html#linkTypes
+  if (GetElement().HasTagName(linkTag)) {
+    if (SupportedTokensLink().Contains(token_value) ||
+        (RuntimeEnabledFeatures::ModulePreloadEnabled() &&
+         token_value == "modulepreload")) {
+      return true;
+    }
+  } else if (GetElement().HasTagName(aTag) &&
+             SupportedTokensAnchor().Contains(token_value)) {
     return true;
-  if (RuntimeEnabledFeatures::ModulePreloadEnabled() &&
-      token_value == "modulepreload")
-    return true;
+  }
   return false;
 }
 
diff --git a/third_party/WebKit/Source/core/html/media/HTMLVideoElementPersistentTest.cpp b/third_party/WebKit/Source/core/html/media/HTMLVideoElementPersistentTest.cpp
index 9fbf9404..38da1ad 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLVideoElementPersistentTest.cpp
+++ b/third_party/WebKit/Source/core/html/media/HTMLVideoElementPersistentTest.cpp
@@ -11,7 +11,7 @@
 #include "core/html/HTMLDivElement.h"
 #include "core/layout/LayoutFullScreen.h"
 #include "core/loader/EmptyClients.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "platform/testing/UnitTestHelpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -31,7 +31,7 @@
 
 }  // anonymous namespace
 
-class HTMLVideoElementPersistentTest : public ::testing::Test {
+class HTMLVideoElementPersistentTest : public PageTestBase {
  protected:
   void SetUp() override {
     chrome_client_ = new FullscreenMockChromeClient();
@@ -40,13 +40,11 @@
     FillWithEmptyClients(clients);
     clients.chrome_client = chrome_client_.Get();
 
-    page_holder_ = DummyPageHolder::Create(IntSize(800, 600), &clients);
+    PageTestBase::SetupPageWithClients(&clients);
     GetDocument().body()->SetInnerHTMLFromString(
         "<body><div><video></video></div></body>");
   }
 
-  Document& GetDocument() { return page_holder_->GetDocument(); }
-
   HTMLVideoElement* VideoElement() {
     return ToHTMLVideoElement(GetDocument().QuerySelector("video"));
   }
@@ -74,7 +72,6 @@
   }
 
  private:
-  std::unique_ptr<DummyPageHolder> page_holder_;
   Persistent<FullscreenMockChromeClient> chrome_client_;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
index 2bab6b5..d90573d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.cpp
@@ -2033,6 +2033,7 @@
 
 bool LayoutTableSection::GroupShouldRepeat() const {
   DCHECK(Table()->Header() == this || Table()->Footer() == this);
+  LOG(ERROR) << "PaginationBreakability=" << GetPaginationBreakability();
   if (GetPaginationBreakability() == kAllowAnyBreaks)
     return false;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
index ca0f0a65..a257cfa0 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
@@ -86,9 +86,10 @@
     return *GetDocument().View()->GetLayoutView();
   }
 
-  Document& ChildDocument() {
-    return *ToLocalFrame(GetFrame().Tree().FirstChild())->GetDocument();
+  LocalFrame& ChildFrame() {
+    return *ToLocalFrame(GetFrame().Tree().FirstChild());
   }
+  Document& ChildDocument() { return *ChildFrame().GetDocument(); }
 
   void SetChildFrameHTML(const String&);
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
index 93fdcda..0f9731d 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -544,6 +544,43 @@
   EXPECT_EQ(expectation, dump);
 }
 
+TEST_F(NGColumnLayoutAlgorithmTest, FloatWithForcedBreak) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #parent {
+        columns: 3;
+        column-fill: auto;
+        column-gap: 10px;
+        width: 320px;
+        height: 100px;
+      }
+    </style>
+    <div id="container">
+      <div id="parent">
+        <div style="height:50px;"></div>
+        <div style="float:left; width:77px;">
+           <div style="width:66px; height:30px;"></div>
+           <div style="break-before:column; width:55px; height:30px;"></div>
+        </div>
+      </div>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:100x50
+        offset:0,50 size:77x50
+          offset:0,0 size:66x30
+      offset:110,0 size:100x30
+        offset:0,0 size:77x30
+          offset:0,0 size:55x30
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 TEST_F(NGColumnLayoutAlgorithmTest, BlockWithTopMarginInThreeColumns) {
   SetBodyInnerHTML(R"HTML(
     <style>
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc
index 9584f14..f4819e2 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc
@@ -71,37 +71,10 @@
   return NGExclusion::Create(NGBfcRect(start_offset, end_offset), type);
 }
 
-// TODO(ikilpatrick): origin_block_offset looks wrong for fragmentation here.
-WTF::Optional<LayoutUnit> CalculateFragmentationOffset(
-    const LayoutUnit origin_block_offset,
+scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloatFromBuilder(
     const NGUnpositionedFloat& unpositioned_float,
-    const NGConstraintSpace& parent_space) {
+    NGConstraintSpaceBuilder& builder) {
   const ComputedStyle& style = unpositioned_float.node.Style();
-  DCHECK(style.GetWritingMode() == parent_space.GetWritingMode());
-
-  if (parent_space.HasBlockFragmentation()) {
-    return parent_space.FragmentainerSpaceAtBfcStart() - origin_block_offset;
-  }
-
-  return WTF::nullopt;
-}
-
-// Creates a constraint space for an unpositioned float.
-scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloat(
-    const NGUnpositionedFloat& unpositioned_float,
-    const NGConstraintSpace& parent_space,
-    WTF::Optional<LayoutUnit> fragmentation_offset = WTF::nullopt) {
-  const ComputedStyle& style = unpositioned_float.node.Style();
-
-  NGConstraintSpaceBuilder builder(parent_space);
-
-  if (fragmentation_offset) {
-    builder.SetFragmentainerSpaceAtBfcStart(fragmentation_offset.value())
-        .SetFragmentationType(parent_space.BlockFragmentationType());
-  } else {
-    builder.SetFragmentationType(NGFragmentationType::kFragmentNone);
-  }
-
   return builder.SetPercentageResolutionSize(unpositioned_float.percentage_size)
       .SetAvailableSize(unpositioned_float.available_size)
       .SetIsNewFormattingContext(true)
@@ -110,6 +83,38 @@
       .ToConstraintSpace(style.GetWritingMode());
 }
 
+// Creates a constraint space for an unpositioned float, with the intent to
+// position it.
+scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloat(
+    const NGUnpositionedFloat& unpositioned_float,
+    const NGConstraintSpace& parent_space,
+    LayoutUnit origin_block_offset) {
+  NGConstraintSpaceBuilder builder(parent_space);
+
+  DCHECK_EQ(unpositioned_float.node.Style().GetWritingMode(),
+            parent_space.GetWritingMode());
+  if (parent_space.HasBlockFragmentation()) {
+    LayoutUnit fragmentation_offset =
+        parent_space.FragmentainerSpaceAtBfcStart() - origin_block_offset;
+    builder.SetFragmentainerBlockSize(parent_space.FragmentainerBlockSize());
+    builder.SetFragmentainerSpaceAtBfcStart(fragmentation_offset);
+    builder.SetFragmentationType(parent_space.BlockFragmentationType());
+  } else {
+    builder.SetFragmentationType(NGFragmentationType::kFragmentNone);
+  }
+  return CreateConstraintSpaceForFloatFromBuilder(unpositioned_float, builder);
+}
+
+// Creates a constraint space for an unpositioned float, with the intent to
+// simply calculate its inline size.
+scoped_refptr<NGConstraintSpace>
+CreateConstraintSpaceForFloatForInlineSizeCalculation(
+    const NGUnpositionedFloat& unpositioned_float,
+    const NGConstraintSpace& parent_space) {
+  NGConstraintSpaceBuilder builder(parent_space);
+  return CreateConstraintSpaceForFloatFromBuilder(unpositioned_float, builder);
+}
+
 }  // namespace
 
 LayoutUnit ComputeInlineSizeForUnpositionedFloat(
@@ -133,7 +138,8 @@
   }
 
   const scoped_refptr<NGConstraintSpace> space =
-      CreateConstraintSpaceForFloat(*unpositioned_float, parent_space);
+      CreateConstraintSpaceForFloatForInlineSizeCalculation(*unpositioned_float,
+                                                            parent_space);
 
   // If the float has the same writing mode as the block formatting context we
   // shouldn't perform a full layout just yet. Our position may determine where
@@ -197,12 +203,8 @@
 #if DCHECK_IS_ON()
     DCHECK(is_same_writing_mode);
 #endif
-    WTF::Optional<LayoutUnit> fragmentation_offset =
-        CalculateFragmentationOffset(origin_block_offset, *unpositioned_float,
-                                     parent_space);
-
     scoped_refptr<NGConstraintSpace> space = CreateConstraintSpaceForFloat(
-        *unpositioned_float, parent_space, fragmentation_offset);
+        *unpositioned_float, parent_space, origin_block_offset);
     layout_result = unpositioned_float->node.Layout(
         *space, unpositioned_float->token.get());
   }
diff --git a/third_party/WebKit/Source/core/loader/IdlenessDetectorTest.cpp b/third_party/WebKit/Source/core/loader/IdlenessDetectorTest.cpp
index 3dfa879..a402a411 100644
--- a/third_party/WebKit/Source/core/loader/IdlenessDetectorTest.cpp
+++ b/third_party/WebKit/Source/core/loader/IdlenessDetectorTest.cpp
@@ -4,23 +4,21 @@
 
 #include "core/loader/IdlenessDetector.h"
 
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "platform/testing/TestingPlatformSupportWithMockScheduler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class IdlenessDetectorTest : public ::testing::Test {
+class IdlenessDetectorTest : public PageTestBase {
  protected:
   void SetUp() override {
     platform_time_ = 1;
     platform_->AdvanceClockSeconds(platform_time_);
-    page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
+    PageTestBase::SetUp();
   }
 
-  IdlenessDetector* Detector() {
-    return page_holder_->GetFrame().GetIdlenessDetector();
-  }
+  IdlenessDetector* Detector() { return GetFrame().GetIdlenessDetector(); }
 
   bool IsNetworkQuietTimerActive() {
     return Detector()->network_quiet_timer_.IsActive();
@@ -55,7 +53,6 @@
 
  private:
   double platform_time_;
-  std::unique_ptr<DummyPageHolder> page_holder_;
 };
 
 TEST_F(IdlenessDetectorTest, NetworkQuietBasic) {
diff --git a/third_party/WebKit/Source/core/loader/InteractiveDetectorTest.cpp b/third_party/WebKit/Source/core/loader/InteractiveDetectorTest.cpp
index 3565017..80b2c9f7 100644
--- a/third_party/WebKit/Source/core/loader/InteractiveDetectorTest.cpp
+++ b/third_party/WebKit/Source/core/loader/InteractiveDetectorTest.cpp
@@ -5,7 +5,7 @@
 #include "core/loader/InteractiveDetector.h"
 
 #include "core/dom/Document.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "platform/CrossThreadFunctional.h"
 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
 #include "platform/testing/TestingPlatformSupportWithMockScheduler.h"
@@ -395,7 +395,7 @@
   EXPECT_EQ(GetDetector()->GetFirstInvalidatingInputTime(), t0 + 5.0);
 }
 
-class InteractiveDetectorTestWithDummyPage : public ::testing::Test {
+class InteractiveDetectorTestWithDummyPage : public PageTestBase {
  public:
   // Public because it's executed on a task queue.
   void DummyTaskWithDuration(double duration_seconds) {
@@ -406,17 +406,15 @@
  protected:
   void SetUp() override {
     platform_->AdvanceClockSeconds(1);
-    dummy_page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
+    PageTestBase::SetUp();
   }
 
   double GetDummyTaskEndTime() { return dummy_task_end_time_; }
 
-  Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
 
  private:
-  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
   double dummy_task_end_time_ = 0.0;
 };
 
diff --git a/third_party/WebKit/Source/core/paint/AdjustPaintOffsetScope.cpp b/third_party/WebKit/Source/core/paint/AdjustPaintOffsetScope.cpp
index d19cf89..98cbd80e 100644
--- a/third_party/WebKit/Source/core/paint/AdjustPaintOffsetScope.cpp
+++ b/third_party/WebKit/Source/core/paint/AdjustPaintOffsetScope.cpp
@@ -40,7 +40,8 @@
     return true;
   }
 
-  if (box.IsTableSection()) {
+  if (box.IsTableSection() &&
+      (!old_paint_info_.IsPrinting() || box.FirstFragment().NextFragment())) {
     const auto& section = ToLayoutTableSection(box);
     if (section.IsRepeatingHeaderGroup() || section.IsRepeatingFooterGroup()) {
       adjusted_paint_offset_ = fragment->PaintOffset();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 34d0e3e..2357e11 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -1089,15 +1089,20 @@
   Optional<ScrollRecorder> scroll_recorder;
   LayoutPoint paint_offset = -paint_layer_.LayoutBoxLocation();
   if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
-    paint_offset += fragment.fragment_data->PaintOffset();
-    // For SPv175+, we paint in the containing transform node's space. Now
-    // |new_cull_rect| is in the pixel-snapped border box space of
-    // |painting_info.root_layer|. Adjust it to the correct space.
-    // |paint_offset| is already in the correct space.
-    new_cull_rect.MoveBy(
-        RoundedIntPoint(painting_info.root_layer->GetLayoutObject()
-                            .FirstFragment()
-                            .PaintOffset()));
+    if (paint_layer_.GetLayoutObject().IsFixedPositionObjectInPagedMedia()) {
+      // TODO(wangxianzhu): Use full SPv175 path here.
+      paint_offset += ToSize(fragment.layer_bounds.Location());
+    } else {
+      paint_offset += fragment.fragment_data->PaintOffset();
+      // For SPv175+, we paint in the containing transform node's space. Now
+      // |new_cull_rect| is in the pixel-snapped border box space of
+      // |painting_info.root_layer|. Adjust it to the correct space.
+      // |paint_offset| is already in the correct space.
+      new_cull_rect.MoveBy(
+          RoundedIntPoint(painting_info.root_layer->GetLayoutObject()
+                              .FirstFragment()
+                              .PaintOffset()));
+    }
   } else {
     paint_offset += ToSize(fragment.layer_bounds.Location());
     if (!painting_info.scroll_offset_accumulation.IsZero()) {
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index f7c23ab..9765dfc 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -45,6 +45,24 @@
       ScrollPaintPropertyNode::Root();
 }
 
+static bool NeedsFrameContentClip(const LocalFrame& frame) {
+  if (!frame.GetDocument()->Printing())
+    return true;
+
+  // Don't issue frame content clip the frame is the root frame of printing.
+  // WebLocalFrameImpl will issue artificial page clip for each page instead.
+  const auto* parent_frame = frame.Tree().Parent();
+  if (!parent_frame)
+    return false;
+  // TODO(crbug.com/455764): The local frame may be not the root frame of
+  // printing when it's printing under a remote frame.
+  if (!parent_frame->IsLocalFrame())
+    return false;
+
+  // If the parent frame is printing, this frame should clip normally.
+  return ToLocalFrame(parent_frame)->GetDocument()->Printing();
+}
+
 // True if a new property was created, false if an existing one was updated.
 static bool UpdatePreTranslation(
     LocalFrameView& frame_view,
@@ -189,7 +207,9 @@
         frame_view, context.current.transform, frame_translate, FloatPoint3D());
 
     FloatRoundedRect content_clip(
-        IntRect(IntPoint(), frame_view.VisibleContentSize()));
+        NeedsFrameContentClip(frame_view.GetFrame())
+            ? IntRect(IntPoint(), frame_view.VisibleContentSize())
+            : LayoutRect::InfiniteIntRect());
     full_context.force_subtree_update |= UpdateContentClip(
         frame_view, context.current.clip, frame_view.PreTranslation(),
         content_clip, full_context.clip_changed);
@@ -940,7 +960,9 @@
 }
 
 static bool NeedsOverflowClip(const LayoutObject& object) {
-  return object.IsBox() && ToLayoutBox(object).ShouldClipOverflow();
+  return object.IsBox() && ToLayoutBox(object).ShouldClipOverflow() &&
+         (!object.IsLayoutView() ||
+          NeedsFrameContentClip(*ToLayoutView(object).GetFrame()));
 }
 
 static bool NeedsInnerBorderRadiusClip(const LayoutObject& object) {
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index 2e9c2d1..147046bf 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -21,8 +21,10 @@
 }
 
 const TransformPaintPropertyNode*
-PaintPropertyTreeBuilderTest::FramePreTranslation() {
-  LocalFrameView* frame_view = GetDocument().View();
+PaintPropertyTreeBuilderTest::FramePreTranslation(
+    const LocalFrameView* frame_view) {
+  if (!frame_view)
+    frame_view = GetDocument().View();
   if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
     return frame_view->GetLayoutView()
         ->FirstFragment()
@@ -33,8 +35,10 @@
 }
 
 const TransformPaintPropertyNode*
-PaintPropertyTreeBuilderTest::FrameScrollTranslation() {
-  LocalFrameView* frame_view = GetDocument().View();
+PaintPropertyTreeBuilderTest::FrameScrollTranslation(
+    const LocalFrameView* frame_view) {
+  if (!frame_view)
+    frame_view = GetDocument().View();
   if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
     return frame_view->GetLayoutView()
         ->FirstFragment()
@@ -44,8 +48,10 @@
   return frame_view->ScrollTranslation();
 }
 
-const ClipPaintPropertyNode* PaintPropertyTreeBuilderTest::FrameContentClip() {
-  LocalFrameView* frame_view = GetDocument().View();
+const ClipPaintPropertyNode* PaintPropertyTreeBuilderTest::FrameContentClip(
+    const LocalFrameView* frame_view) {
+  if (!frame_view)
+    frame_view = GetDocument().View();
   if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
     return frame_view->GetLayoutView()
         ->FirstFragment()
@@ -56,7 +62,7 @@
 }
 
 const ScrollPaintPropertyNode* PaintPropertyTreeBuilderTest::FrameScroll(
-    LocalFrameView* frame_view) {
+    const LocalFrameView* frame_view) {
   if (!frame_view)
     frame_view = GetDocument().View();
   if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
@@ -4699,4 +4705,51 @@
   EXPECT_EQ(nullptr, properties->OverflowClip());
 }
 
+TEST_P(PaintPropertyTreeBuilderTest, FrameClipWhenPrinting) {
+  SetBodyInnerHTML("<iframe></iframe>");
+  SetChildFrameHTML("");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  // When not printing, both main and child frame views have content clip.
+  const auto& main_frame_view = GetDocument().View();
+  const auto& child_frame_view = ChildDocument().View();
+  ASSERT_NE(nullptr, FrameContentClip(main_frame_view));
+  EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
+            FrameContentClip(main_frame_view)->ClipRect().Rect());
+  ASSERT_NE(nullptr, FrameContentClip(child_frame_view));
+  EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
+            FrameContentClip(child_frame_view)->ClipRect().Rect());
+
+  // When the main frame is printing, it should not have content clip.
+  FloatSize page_size(100, 100);
+  GetFrame().SetPrinting(true, page_size, page_size, 1);
+  GetDocument().View()->UpdateLifecyclePhasesForPrinting();
+  if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
+    EXPECT_EQ(nullptr, FrameContentClip(main_frame_view));
+  } else {
+    EXPECT_EQ(FloatRect(LayoutRect::InfiniteIntRect()),
+              FrameContentClip(main_frame_view)->ClipRect().Rect());
+  }
+  ASSERT_NE(nullptr, FrameContentClip(child_frame_view));
+  EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
+            FrameContentClip(child_frame_view)->ClipRect().Rect());
+
+  GetFrame().SetPrinting(false, page_size, page_size, 1);
+  GetDocument().View()->UpdateAllLifecyclePhases();
+
+  // When only the child frame is printing, it should not have content clip but
+  // the main frame still have (which doesn't matter though).
+  ChildFrame().SetPrinting(true, page_size, page_size, 1);
+  GetDocument().View()->UpdateLifecyclePhasesForPrinting();
+  ASSERT_NE(nullptr, FrameContentClip(main_frame_view));
+  EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
+            FrameContentClip(main_frame_view)->ClipRect().Rect());
+  if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
+    EXPECT_EQ(nullptr, FrameContentClip(child_frame_view));
+  } else {
+    EXPECT_EQ(FloatRect(LayoutRect::InfiniteIntRect()),
+              FrameContentClip(child_frame_view)->ClipRect().Rect());
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h
index 501dc6f0..33f9fc1 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h
@@ -29,10 +29,13 @@
   // The following helpers return paint property nodes associated with the main
   // LocalFrameView, accounting for differences from the RootLayerScrolls
   // setting.
-  const TransformPaintPropertyNode* FramePreTranslation();
-  const TransformPaintPropertyNode* FrameScrollTranslation();
-  const ClipPaintPropertyNode* FrameContentClip();
-  const ScrollPaintPropertyNode* FrameScroll(LocalFrameView* = nullptr);
+  const TransformPaintPropertyNode* FramePreTranslation(
+      const LocalFrameView* = nullptr);
+  const TransformPaintPropertyNode* FrameScrollTranslation(
+      const LocalFrameView* = nullptr);
+  const ClipPaintPropertyNode* FrameContentClip(
+      const LocalFrameView* = nullptr);
+  const ScrollPaintPropertyNode* FrameScroll(const LocalFrameView* = nullptr);
 
   // Return the local border box's paint offset. For more details, see
   // ObjectPaintProperties::localBorderBoxProperties().
diff --git a/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp b/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
index efbeb5d6..21be8f2 100644
--- a/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
@@ -26,7 +26,10 @@
     const PaintInfo& paint_info,
     const LayoutPoint& paint_offset,
     ItemToPaint item_to_paint) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+      // TODO(wangxianzhu): Use the PaintPropertyTreeBuilder path for printing.
+      (!paint_info.IsPrinting() ||
+       layout_table_section_.FirstFragment().NextFragment()))
     return;
 
   if (!layout_table_section_.IsRepeatingHeaderGroup())
@@ -94,7 +97,10 @@
     const PaintInfo& paint_info,
     const LayoutPoint& paint_offset,
     ItemToPaint item_to_paint) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+      // TODO(wangxianzhu): Use the PaintPropertyTreeBuilder path for printing.
+      (!paint_info.IsPrinting() ||
+       layout_table_section_.FirstFragment().NextFragment()))
     return;
 
   if (!layout_table_section_.IsRepeatingFooterGroup())
diff --git a/third_party/WebKit/Source/core/paint/TextPainterTest.cpp b/third_party/WebKit/Source/core/paint/TextPainterTest.cpp
index faaf109..fff252d 100644
--- a/third_party/WebKit/Source/core/paint/TextPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/TextPainterTest.cpp
@@ -132,7 +132,8 @@
   GetDocument().body()->SetInlineStyleProperty(
       CSSPropertyWebkitPrintColorAdjust, CSSValueEconomy);
   GetDocument().GetSettings()->SetShouldPrintBackgrounds(false);
-  GetDocument().SetPrinting(Document::kPrinting);
+  FloatSize page_size(500, 800);
+  GetFrame().SetPrinting(true, page_size, page_size, 1);
   GetDocument().View()->UpdateAllLifecyclePhases();
 
   TextPaintStyle text_style = TextPainter::TextPaintingStyle(
@@ -153,8 +154,9 @@
   GetDocument().body()->SetInlineStyleProperty(
       CSSPropertyWebkitPrintColorAdjust, CSSValueEconomy);
   GetDocument().GetSettings()->SetShouldPrintBackgrounds(false);
-  GetDocument().SetPrinting(Document::kPrinting);
-  GetDocument().View()->UpdateAllLifecyclePhases();
+  FloatSize page_size(500, 800);
+  GetFrame().SetPrinting(true, page_size, page_size, 1);
+  GetDocument().View()->UpdateLifecyclePhasesForPrinting();
 
   TextPaintStyle text_style = TextPainter::TextPaintingStyle(
       GetLineLayoutText().GetDocument(), GetLineLayoutText().StyleRef(),
diff --git a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
index 6426d33a..53beaa5 100644
--- a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
+++ b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
@@ -327,7 +327,7 @@
     letter-spacing: 39.5px;
     margin-top: 8px;
     display: block;
-    color: #deb7b7;
+    color: #969696;
     margin-left: 16px;
     width: 174px;
 }
diff --git a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
index 3a26fd9..a7f0173 100644
--- a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
@@ -66,7 +66,6 @@
 #include "public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerProvider.h"
 #include "public/web/WebConsoleMessage.h"
-#include "public/web/WebDevToolsAgent.h"
 #include "public/web/WebSettings.h"
 #include "public/web/modules/serviceworker/WebServiceWorkerContextClient.h"
 
@@ -199,21 +198,21 @@
 }
 
 void WebEmbeddedWorkerImpl::AttachDevTools(int session_id) {
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent)
     devtools_agent->Attach(session_id);
 }
 
 void WebEmbeddedWorkerImpl::ReattachDevTools(int session_id,
                                              const WebString& saved_state) {
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent)
     devtools_agent->Reattach(session_id, saved_state);
   ResumeStartup();
 }
 
 void WebEmbeddedWorkerImpl::DetachDevTools(int session_id) {
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent)
     devtools_agent->Detach(session_id);
 }
@@ -224,7 +223,7 @@
                                                     const WebString& message) {
   if (asked_to_terminate_)
     return;
-  WebDevToolsAgent* devtools_agent = shadow_page_->DevToolsAgent();
+  WebDevToolsAgentImpl* devtools_agent = shadow_page_->DevToolsAgent();
   if (devtools_agent) {
     devtools_agent->DispatchOnInspectorBackend(session_id, call_id, method,
                                                message);
@@ -311,8 +310,8 @@
 
 void WebEmbeddedWorkerImpl::SendProtocolMessage(int session_id,
                                                 int call_id,
-                                                const WebString& message,
-                                                const WebString& state) {
+                                                const String& message,
+                                                const String& state) {
   worker_context_client_->SendDevToolsMessage(session_id, call_id, message,
                                               state);
 }
diff --git a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h
index befbf04..537ced4 100644
--- a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h
+++ b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.h
@@ -39,7 +39,6 @@
 #include "modules/serviceworkers/ServiceWorkerContentSettingsProxy.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/heap/Handle.h"
-#include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebEmbeddedWorker.h"
 #include "public/web/WebEmbeddedWorkerStartData.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -94,11 +93,11 @@
   void OnShadowPageInitialized() override;
 
  private:
-  // WebDevToolsAgentClient overrides.
+  // WebDevToolsAgentImpl::Client overrides.
   void SendProtocolMessage(int session_id,
                            int call_id,
-                           const WebString&,
-                           const WebString&) override;
+                           const String&,
+                           const String&) override;
   void ResumeStartup() override;
   const WebString& GetInstrumentationToken() override;
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 46ab62f..34ae1a8 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -5382,10 +5382,12 @@
     GLint xoffset,
     GLint yoffset,
     const IntRect& source_sub_rect) {
+  // We hard-code premultiply_alpha and flip_y values because these values
+  // should have been already manipulated during construction of ImageBitmap.
   bitmap->BitmapImage()->CopyToTexture(
       GetDrawingBuffer()->ContextProvider()->ContextGL(), target,
-      target_texture, true /* unpack_premultiply_alpha */, unpack_flip_y_,
-      IntPoint(xoffset, yoffset), source_sub_rect);
+      target_texture, true /* unpack_premultiply_alpha */,
+      false /* unpack_flip_y_ */, IntPoint(xoffset, yoffset), source_sub_rect);
 }
 
 void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
diff --git a/third_party/WebKit/Source/platform/AsyncFileSystemCallbacks.h b/third_party/WebKit/Source/platform/AsyncFileSystemCallbacks.h
index 1d4499f..4cde96e5 100644
--- a/third_party/WebKit/Source/platform/AsyncFileSystemCallbacks.h
+++ b/third_party/WebKit/Source/platform/AsyncFileSystemCallbacks.h
@@ -105,7 +105,7 @@
     block_until_completion_ = flag;
   }
 
-  virtual ~AsyncFileSystemCallbacks() {}
+  virtual ~AsyncFileSystemCallbacks() = default;
 
  private:
   bool block_until_completion_;
diff --git a/third_party/WebKit/Source/platform/AsyncMethodRunner.h b/third_party/WebKit/Source/platform/AsyncMethodRunner.h
index 55fbc71..73a8cb4 100644
--- a/third_party/WebKit/Source/platform/AsyncMethodRunner.h
+++ b/third_party/WebKit/Source/platform/AsyncMethodRunner.h
@@ -51,7 +51,7 @@
     return new AsyncMethodRunner(object, method, std::move(task_runner));
   }
 
-  ~AsyncMethodRunner() {}
+  ~AsyncMethodRunner() = default;
 
   // Schedules to run the method asynchronously. Do nothing if it's already
   // scheduled. If it's suspended, remember to schedule to run the method when
diff --git a/third_party/WebKit/Source/platform/ContentDecryptionModuleResult.h b/third_party/WebKit/Source/platform/ContentDecryptionModuleResult.h
index 8065aa8..72999afc 100644
--- a/third_party/WebKit/Source/platform/ContentDecryptionModuleResult.h
+++ b/third_party/WebKit/Source/platform/ContentDecryptionModuleResult.h
@@ -19,7 +19,7 @@
 class ContentDecryptionModuleResult
     : public GarbageCollectedFinalized<ContentDecryptionModuleResult> {
  public:
-  virtual ~ContentDecryptionModuleResult() {}
+  virtual ~ContentDecryptionModuleResult() = default;
 
   virtual void Complete() = 0;
   virtual void CompleteWithContentDecryptionModule(
diff --git a/third_party/WebKit/Source/platform/ContentSettingCallbacks.h b/third_party/WebKit/Source/platform/ContentSettingCallbacks.h
index 561a207..db17746 100644
--- a/third_party/WebKit/Source/platform/ContentSettingCallbacks.h
+++ b/third_party/WebKit/Source/platform/ContentSettingCallbacks.h
@@ -21,7 +21,7 @@
   static std::unique_ptr<ContentSettingCallbacks> Create(
       base::OnceClosure allowed,
       base::OnceClosure denied);
-  virtual ~ContentSettingCallbacks() {}
+  virtual ~ContentSettingCallbacks() = default;
 
   void OnAllowed() { std::move(allowed_).Run(); }
   void OnDenied() { std::move(denied_).Run(); }
diff --git a/third_party/WebKit/Source/platform/ContextMenu.h b/third_party/WebKit/Source/platform/ContextMenu.h
index 3bf6c21..75bb6c6 100644
--- a/third_party/WebKit/Source/platform/ContextMenu.h
+++ b/third_party/WebKit/Source/platform/ContextMenu.h
@@ -38,7 +38,7 @@
   USING_FAST_MALLOC(ContextMenu);
 
  public:
-  ContextMenu() {}
+  ContextMenu() = default;
   const ContextMenuItem* ItemWithAction(unsigned) const;
   const Vector<ContextMenuItem>& Items() const { return items_; }
   void AppendItem(const ContextMenuItem& item) { items_.push_back(item); }
diff --git a/third_party/WebKit/Source/platform/ContextMenuItem.cpp b/third_party/WebKit/Source/platform/ContextMenuItem.cpp
index 8a806c81..c174989 100644
--- a/third_party/WebKit/Source/platform/ContextMenuItem.cpp
+++ b/third_party/WebKit/Source/platform/ContextMenuItem.cpp
@@ -65,7 +65,7 @@
       checked_(checked),
       sub_menu_items_(sub_menu_items) {}
 
-ContextMenuItem::~ContextMenuItem() {}
+ContextMenuItem::~ContextMenuItem() = default;
 
 void ContextMenuItem::SetSubMenu(ContextMenu* sub_menu) {
   if (sub_menu) {
diff --git a/third_party/WebKit/Source/platform/CryptoResult.h b/third_party/WebKit/Source/platform/CryptoResult.h
index 1f09e7a..a1d55d9 100644
--- a/third_party/WebKit/Source/platform/CryptoResult.h
+++ b/third_party/WebKit/Source/platform/CryptoResult.h
@@ -41,7 +41,7 @@
 // to query for status.
 class CryptoResultCancel : public ThreadSafeRefCounted<CryptoResultCancel> {
  public:
-  virtual ~CryptoResultCancel() {}
+  virtual ~CryptoResultCancel() = default;
 
   virtual bool Cancelled() const = 0;
 };
@@ -50,7 +50,7 @@
 class PLATFORM_EXPORT CryptoResult
     : public GarbageCollectedFinalized<CryptoResult> {
  public:
-  virtual ~CryptoResult() {}
+  virtual ~CryptoResult() = default;
 
   virtual void CompleteWithError(WebCryptoErrorType, const WebString&) = 0;
   virtual void CompleteWithBuffer(const void* bytes, unsigned bytes_size) = 0;
diff --git a/third_party/WebKit/Source/platform/Cursor.cpp b/third_party/WebKit/Source/platform/Cursor.cpp
index a21f9ec0..f13043e2 100644
--- a/third_party/WebKit/Source/platform/Cursor.cpp
+++ b/third_party/WebKit/Source/platform/Cursor.cpp
@@ -77,11 +77,7 @@
 
 Cursor::Cursor(Type type) : type_(type), image_scale_factor_(1) {}
 
-Cursor::Cursor(const Cursor& other)
-    : type_(other.type_),
-      image_(other.image_),
-      hot_spot_(other.hot_spot_),
-      image_scale_factor_(other.image_scale_factor_) {}
+Cursor::Cursor(const Cursor& other) = default;
 
 Cursor& Cursor::operator=(const Cursor& other) {
   type_ = other.type_;
@@ -91,7 +87,7 @@
   return *this;
 }
 
-Cursor::~Cursor() {}
+Cursor::~Cursor() = default;
 
 const Cursor& PointerCursor() {
   DEFINE_STATIC_LOCAL(Cursor, c, (Cursor::kPointer));
diff --git a/third_party/WebKit/Source/platform/Decimal.cpp b/third_party/WebKit/Source/platform/Decimal.cpp
index b0424d1d..1253f3e 100644
--- a/third_party/WebKit/Source/platform/Decimal.cpp
+++ b/third_party/WebKit/Source/platform/Decimal.cpp
@@ -279,12 +279,9 @@
 
 Decimal::Decimal(const EncodedData& data) : data_(data) {}
 
-Decimal::Decimal(const Decimal& other) : data_(other.data_) {}
+Decimal::Decimal(const Decimal& other) = default;
 
-Decimal& Decimal::operator=(const Decimal& other) {
-  data_ = other.data_;
-  return *this;
-}
+Decimal& Decimal::operator=(const Decimal& other) = default;
 
 Decimal& Decimal::operator+=(const Decimal& other) {
   data_ = (*this + other).data_;
diff --git a/third_party/WebKit/Source/platform/DragImage.cpp b/third_party/WebKit/Source/platform/DragImage.cpp
index 3a4a452..6d0001d 100644
--- a/third_party/WebKit/Source/platform/DragImage.cpp
+++ b/third_party/WebKit/Source/platform/DragImage.cpp
@@ -324,7 +324,7 @@
       resolution_scale_(resolution_scale),
       interpolation_quality_(interpolation_quality) {}
 
-DragImage::~DragImage() {}
+DragImage::~DragImage() = default;
 
 void DragImage::Scale(float scale_x, float scale_y) {
   skia::ImageOperations::ResizeMethod resize_method =
diff --git a/third_party/WebKit/Source/platform/EncryptedMediaRequest.h b/third_party/WebKit/Source/platform/EncryptedMediaRequest.h
index 438f2eb..cd1ff89 100644
--- a/third_party/WebKit/Source/platform/EncryptedMediaRequest.h
+++ b/third_party/WebKit/Source/platform/EncryptedMediaRequest.h
@@ -19,7 +19,7 @@
 class EncryptedMediaRequest
     : public GarbageCollectedFinalized<EncryptedMediaRequest> {
  public:
-  virtual ~EncryptedMediaRequest() {}
+  virtual ~EncryptedMediaRequest() = default;
 
   virtual WebString KeySystem() const = 0;
   virtual const WebVector<WebMediaKeySystemConfiguration>&
diff --git a/third_party/WebKit/Source/platform/InstanceCountersMemoryDumpProvider.h b/third_party/WebKit/Source/platform/InstanceCountersMemoryDumpProvider.h
index 91148bb..8186b04 100644
--- a/third_party/WebKit/Source/platform/InstanceCountersMemoryDumpProvider.h
+++ b/third_party/WebKit/Source/platform/InstanceCountersMemoryDumpProvider.h
@@ -18,14 +18,14 @@
 
  public:
   static InstanceCountersMemoryDumpProvider* Instance();
-  ~InstanceCountersMemoryDumpProvider() override {}
+  ~InstanceCountersMemoryDumpProvider() override = default;
 
   // MemoryDumpProvider implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
                     base::trace_event::ProcessMemoryDump*) override;
 
  private:
-  InstanceCountersMemoryDumpProvider() {}
+  InstanceCountersMemoryDumpProvider() = default;
 
   WTF_MAKE_NONCOPYABLE(InstanceCountersMemoryDumpProvider);
 };
diff --git a/third_party/WebKit/Source/platform/LengthBox.h b/third_party/WebKit/Source/platform/LengthBox.h
index 95077619..c781e7e8 100644
--- a/third_party/WebKit/Source/platform/LengthBox.h
+++ b/third_party/WebKit/Source/platform/LengthBox.h
@@ -34,7 +34,7 @@
   DISALLOW_NEW();
 
  public:
-  LengthBox() {}
+  LengthBox() = default;
 
   LengthBox(LengthType t) : left_(t), right_(t), top_(t), bottom_(t) {}
 
diff --git a/third_party/WebKit/Source/platform/LengthPoint.h b/third_party/WebKit/Source/platform/LengthPoint.h
index 05808f99..114aedce 100644
--- a/third_party/WebKit/Source/platform/LengthPoint.h
+++ b/third_party/WebKit/Source/platform/LengthPoint.h
@@ -39,7 +39,7 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  LengthPoint() {}
+  LengthPoint() = default;
 
   LengthPoint(const Length& x, const Length& y) : x_(x), y_(y) {}
 
diff --git a/third_party/WebKit/Source/platform/LengthSize.h b/third_party/WebKit/Source/platform/LengthSize.h
index ddba35a..c4efb6a 100644
--- a/third_party/WebKit/Source/platform/LengthSize.h
+++ b/third_party/WebKit/Source/platform/LengthSize.h
@@ -30,7 +30,7 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  LengthSize() {}
+  LengthSize() = default;
 
   LengthSize(const Length& width, const Length& height)
       : width_(width), height_(height) {}
diff --git a/third_party/WebKit/Source/platform/LongTaskDetector.cpp b/third_party/WebKit/Source/platform/LongTaskDetector.cpp
index 96da057..61416f0 100644
--- a/third_party/WebKit/Source/platform/LongTaskDetector.cpp
+++ b/third_party/WebKit/Source/platform/LongTaskDetector.cpp
@@ -17,7 +17,7 @@
   return *long_task_detector;
 }
 
-LongTaskDetector::LongTaskDetector() {}
+LongTaskDetector::LongTaskDetector() = default;
 
 void LongTaskDetector::RegisterObserver(LongTaskObserver* observer) {
   DCHECK(IsMainThread());
diff --git a/third_party/WebKit/Source/platform/LongTaskDetector.h b/third_party/WebKit/Source/platform/LongTaskDetector.h
index 187521f..ed026a57 100644
--- a/third_party/WebKit/Source/platform/LongTaskDetector.h
+++ b/third_party/WebKit/Source/platform/LongTaskDetector.h
@@ -15,7 +15,7 @@
 
 class PLATFORM_EXPORT LongTaskObserver : public GarbageCollectedMixin {
  public:
-  virtual ~LongTaskObserver() {}
+  virtual ~LongTaskObserver() = default;
 
   virtual void OnLongTaskDetected(double start_time, double end_time) = 0;
 };
diff --git a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
index f9653e7..48dc857 100644
--- a/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/MemoryCoordinator.cpp
@@ -71,7 +71,7 @@
   MemoryCoordinator::Instance().web_threads_.erase(thread);
 }
 
-MemoryCoordinator::MemoryCoordinator() {}
+MemoryCoordinator::MemoryCoordinator() = default;
 
 void MemoryCoordinator::RegisterClient(MemoryCoordinatorClient* client) {
   DCHECK(IsMainThread());
diff --git a/third_party/WebKit/Source/platform/MemoryCoordinator.h b/third_party/WebKit/Source/platform/MemoryCoordinator.h
index 7f36832..5a0f9dd 100644
--- a/third_party/WebKit/Source/platform/MemoryCoordinator.h
+++ b/third_party/WebKit/Source/platform/MemoryCoordinator.h
@@ -16,7 +16,7 @@
 
 class PLATFORM_EXPORT MemoryCoordinatorClient : public GarbageCollectedMixin {
  public:
-  virtual ~MemoryCoordinatorClient() {}
+  virtual ~MemoryCoordinatorClient() = default;
 
   // TODO(bashi): Deprecating. Remove this when MemoryPressureListener is
   // gone.
diff --git a/third_party/WebKit/Source/platform/PODArena.h b/third_party/WebKit/Source/platform/PODArena.h
index 200f8619..15fae8a48 100644
--- a/third_party/WebKit/Source/platform/PODArena.h
+++ b/third_party/WebKit/Source/platform/PODArena.h
@@ -53,7 +53,7 @@
     virtual void Free(void* ptr) = 0;
 
    protected:
-    virtual ~Allocator() {}
+    virtual ~Allocator() = default;
     friend class WTF::RefCounted<Allocator>;
   };
 
@@ -72,7 +72,7 @@
     void Free(void* ptr) override { WTF::Partitions::FastFree(ptr); }
 
    protected:
-    FastMallocAllocator() {}
+    FastMallocAllocator() = default;
   };
 
   // Creates a new PODArena configured with a FastMallocAllocator.
diff --git a/third_party/WebKit/Source/platform/PODFreeListArena.h b/third_party/WebKit/Source/platform/PODFreeListArena.h
index 25a4628..bb1b5bc 100644
--- a/third_party/WebKit/Source/platform/PODFreeListArena.h
+++ b/third_party/WebKit/Source/platform/PODFreeListArena.h
@@ -86,7 +86,7 @@
   explicit PODFreeListArena(scoped_refptr<PODArena::Allocator> allocator)
       : arena_(PODArena::Create(std::move(allocator))), free_list_(nullptr) {}
 
-  ~PODFreeListArena() {}
+  ~PODFreeListArena() = default;
 
   void* AllocateFromFreeList() {
     if (free_list_) {
diff --git a/third_party/WebKit/Source/platform/PODRedBlackTree.h b/third_party/WebKit/Source/platform/PODRedBlackTree.h
index 0fbe655..923152c 100644
--- a/third_party/WebKit/Source/platform/PODRedBlackTree.h
+++ b/third_party/WebKit/Source/platform/PODRedBlackTree.h
@@ -105,7 +105,7 @@
     virtual void Visit(const T& data) = 0;
 
    protected:
-    virtual ~Visitor() {}
+    virtual ~Visitor() = default;
   };
 
   // Constructs a new red-black tree without allocating an arena.
@@ -148,7 +148,7 @@
   {
   }
 
-  virtual ~PODRedBlackTree() {}
+  virtual ~PODRedBlackTree() = default;
 
   // Clearing will delete the contents of the tree. After this call
   // isInitialized will return false.
@@ -251,7 +251,7 @@
           color_(kRed),
           data_(data) {}
 
-    virtual ~Node() {}
+    virtual ~Node() = default;
 
     NodeColor GetColor() const { return color_; }
     void SetColor(NodeColor color) { color_ = color; }
diff --git a/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp b/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
index 59269a2..e382ff2 100644
--- a/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
+++ b/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
@@ -172,9 +172,9 @@
 
 // |m_allocationRegister| should be initialized only when necessary to avoid
 // waste of memory.
-PartitionAllocMemoryDumpProvider::PartitionAllocMemoryDumpProvider() {}
+PartitionAllocMemoryDumpProvider::PartitionAllocMemoryDumpProvider() = default;
 
-PartitionAllocMemoryDumpProvider::~PartitionAllocMemoryDumpProvider() {}
+PartitionAllocMemoryDumpProvider::~PartitionAllocMemoryDumpProvider() = default;
 
 void PartitionAllocMemoryDumpProvider::OnHeapProfilingEnabled(bool enabled) {
   if (enabled) {
diff --git a/third_party/WebKit/Source/platform/PlatformChromeClient.h b/third_party/WebKit/Source/platform/PlatformChromeClient.h
index b4449b4..2cdca84 100644
--- a/third_party/WebKit/Source/platform/PlatformChromeClient.h
+++ b/third_party/WebKit/Source/platform/PlatformChromeClient.h
@@ -41,8 +41,8 @@
   WTF_MAKE_NONCOPYABLE(PlatformChromeClient);
 
  public:
-  PlatformChromeClient() {}
-  virtual ~PlatformChromeClient() {}
+  PlatformChromeClient() = default;
+  virtual ~PlatformChromeClient() = default;
   virtual void Trace(blink::Visitor* visitor) {}
 
   // Requests the host invalidate the contents.
diff --git a/third_party/WebKit/Source/platform/PlatformFrameView.h b/third_party/WebKit/Source/platform/PlatformFrameView.h
index 6848a46..d861220 100644
--- a/third_party/WebKit/Source/platform/PlatformFrameView.h
+++ b/third_party/WebKit/Source/platform/PlatformFrameView.h
@@ -14,8 +14,8 @@
 // of LocalFrameView.
 class PLATFORM_EXPORT PlatformFrameView {
  public:
-  PlatformFrameView() {}
-  virtual ~PlatformFrameView() {}
+  PlatformFrameView() = default;
+  virtual ~PlatformFrameView() = default;
 
   virtual bool IsLocalFrameView() const { return false; }
 };
diff --git a/third_party/WebKit/Source/platform/Prerender.cpp b/third_party/WebKit/Source/platform/Prerender.cpp
index d094800..40190ef6 100644
--- a/third_party/WebKit/Source/platform/Prerender.cpp
+++ b/third_party/WebKit/Source/platform/Prerender.cpp
@@ -43,7 +43,7 @@
                      const Referrer& referrer)
     : client_(client), url_(url), rel_types_(rel_types), referrer_(referrer) {}
 
-Prerender::~Prerender() {}
+Prerender::~Prerender() = default;
 
 void Prerender::Trace(blink::Visitor* visitor) {
   visitor->Trace(client_);
diff --git a/third_party/WebKit/Source/platform/Prerender.h b/third_party/WebKit/Source/platform/Prerender.h
index 297266f..61b50fb 100644
--- a/third_party/WebKit/Source/platform/Prerender.h
+++ b/third_party/WebKit/Source/platform/Prerender.h
@@ -52,7 +52,7 @@
  public:
   class ExtraData : public RefCounted<ExtraData> {
    public:
-    virtual ~ExtraData() {}
+    virtual ~ExtraData() = default;
   };
 
   static Prerender* Create(PrerenderClient* client,
diff --git a/third_party/WebKit/Source/platform/PrerenderClient.h b/third_party/WebKit/Source/platform/PrerenderClient.h
index e76e88f..9b2bf29 100644
--- a/third_party/WebKit/Source/platform/PrerenderClient.h
+++ b/third_party/WebKit/Source/platform/PrerenderClient.h
@@ -39,7 +39,7 @@
 
 class PLATFORM_EXPORT PrerenderClient : public GarbageCollectedMixin {
  public:
-  virtual ~PrerenderClient() {}
+  virtual ~PrerenderClient() = default;
 
   virtual void DidStartPrerender() = 0;
   virtual void DidStopPrerender() = 0;
diff --git a/third_party/WebKit/Source/platform/Theme.h b/third_party/WebKit/Source/platform/Theme.h
index a23c2f7..9073eac 100644
--- a/third_party/WebKit/Source/platform/Theme.h
+++ b/third_party/WebKit/Source/platform/Theme.h
@@ -50,8 +50,8 @@
   WTF_MAKE_NONCOPYABLE(Theme);
 
  public:
-  Theme() {}
-  virtual ~Theme() {}
+  Theme() = default;
+  virtual ~Theme() = default;
 
   // A method to obtain the baseline position adjustment for a "leaf" control.
   // This will only be used if a baseline position cannot be determined by
diff --git a/third_party/WebKit/Source/platform/Timer.h b/third_party/WebKit/Source/platform/Timer.h
index 5f0e8a0..f1c201a 100644
--- a/third_party/WebKit/Source/platform/Timer.h
+++ b/third_party/WebKit/Source/platform/Timer.h
@@ -155,7 +155,7 @@
                   TimerFiredFunction f)
       : TimerBase(std::move(web_task_runner)), object_(o), function_(f) {}
 
-  ~TaskRunnerTimer() override {}
+  ~TaskRunnerTimer() override = default;
 
  protected:
   void Fired() override { (object_->*function_)(this); }
@@ -186,7 +186,7 @@
   using TimerFiredFunction =
       typename TaskRunnerTimer<TimerFiredClass>::TimerFiredFunction;
 
-  ~Timer() override {}
+  ~Timer() override = default;
 
   Timer(TimerFiredClass* timer_fired_class,
         TimerFiredFunction timer_fired_function)
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp
index 2f34557..0745a38 100644
--- a/third_party/WebKit/Source/platform/TimerTest.cpp
+++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -526,7 +526,7 @@
   using TimerFiredFunction =
       typename TaskRunnerTimer<TimerFiredClass>::TimerFiredFunction;
 
-  ~TimerForTest() override {}
+  ~TimerForTest() override = default;
 
   TimerForTest(scoped_refptr<WebTaskRunner> web_task_runner,
                TimerFiredClass* timer_fired_class,
diff --git a/third_party/WebKit/Source/platform/WaitableEvent.cpp b/third_party/WebKit/Source/platform/WaitableEvent.cpp
index c00f606..271974f1 100644
--- a/third_party/WebKit/Source/platform/WaitableEvent.cpp
+++ b/third_party/WebKit/Source/platform/WaitableEvent.cpp
@@ -23,7 +23,7 @@
           : base::WaitableEvent::InitialState::NOT_SIGNALED));
 }
 
-WaitableEvent::~WaitableEvent() {}
+WaitableEvent::~WaitableEvent() = default;
 
 void WaitableEvent::Reset() {
   impl_->Reset();
diff --git a/third_party/WebKit/Source/platform/WebFrameScheduler.h b/third_party/WebKit/Source/platform/WebFrameScheduler.h
index 3c10064..b48924fb 100644
--- a/third_party/WebKit/Source/platform/WebFrameScheduler.h
+++ b/third_party/WebKit/Source/platform/WebFrameScheduler.h
@@ -18,7 +18,7 @@
 
 class WebFrameScheduler {
  public:
-  virtual ~WebFrameScheduler() {}
+  virtual ~WebFrameScheduler() = default;
 
   // Observer type that regulates conditions to invoke callbacks.
   enum class ObserverType { kLoader };
@@ -38,8 +38,8 @@
 
   class ActiveConnectionHandle {
    public:
-    ActiveConnectionHandle() {}
-    virtual ~ActiveConnectionHandle() {}
+    ActiveConnectionHandle() = default;
+    virtual ~ActiveConnectionHandle() = default;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(ActiveConnectionHandle);
diff --git a/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp b/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp
index 7c22997d..0e68330 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp
@@ -37,7 +37,7 @@
                                  group_id, target_property);
 }
 
-CompositorAnimation::~CompositorAnimation() {}
+CompositorAnimation::~CompositorAnimation() = default;
 
 int CompositorAnimation::Id() const {
   return animation_->id();
diff --git a/third_party/WebKit/Source/platform/animation/CompositorAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorAnimationCurve.h
index 2219679..b31de73d 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorAnimationCurve.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorAnimationCurve.h
@@ -17,7 +17,7 @@
 
 class PLATFORM_EXPORT CompositorAnimationCurve {
  public:
-  virtual ~CompositorAnimationCurve() {}
+  virtual ~CompositorAnimationCurve() = default;
   virtual std::unique_ptr<cc::AnimationCurve> CloneToAnimationCurve() const = 0;
 };
 
diff --git a/third_party/WebKit/Source/platform/animation/CompositorAnimationDelegate.h b/third_party/WebKit/Source/platform/animation/CompositorAnimationDelegate.h
index 69c0ad0c..7239d494 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorAnimationDelegate.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorAnimationDelegate.h
@@ -14,7 +14,7 @@
 
 class PLATFORM_EXPORT CompositorAnimationDelegate {
  public:
-  virtual ~CompositorAnimationDelegate() {}
+  virtual ~CompositorAnimationDelegate() = default;
 
   virtual void NotifyAnimationStarted(double monotonic_time, int group) = 0;
   virtual void NotifyAnimationFinished(double monotonic_time, int group) = 0;
diff --git a/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayerClient.cpp b/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayerClient.cpp
index a2620800..3189e69 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayerClient.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayerClient.cpp
@@ -6,6 +6,6 @@
 
 namespace blink {
 
-CompositorAnimationPlayerClient::~CompositorAnimationPlayerClient() {}
+CompositorAnimationPlayerClient::~CompositorAnimationPlayerClient() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
index aff8318..89101b4 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
@@ -14,7 +14,7 @@
 CompositorFilterAnimationCurve::CompositorFilterAnimationCurve()
     : curve_(cc::KeyframedFilterAnimationCurve::Create()) {}
 
-CompositorFilterAnimationCurve::~CompositorFilterAnimationCurve() {}
+CompositorFilterAnimationCurve::~CompositorFilterAnimationCurve() = default;
 
 void CompositorFilterAnimationCurve::AddKeyframe(
     const CompositorFilterKeyframe& keyframe) {
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp
index bbda8f8..5d08726 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp
@@ -18,7 +18,7 @@
                                      value.ReleaseCcFilterOperations(),
                                      timing_function.CloneToCC())) {}
 
-CompositorFilterKeyframe::~CompositorFilterKeyframe() {}
+CompositorFilterKeyframe::~CompositorFilterKeyframe() = default;
 
 double CompositorFilterKeyframe::Time() const {
   return filter_keyframe_->Time().InSecondsF();
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
index 4c2bf2d..b7aa4af 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
@@ -19,7 +19,7 @@
     std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve)
     : curve_(std::move(curve)) {}
 
-CompositorFloatAnimationCurve::~CompositorFloatAnimationCurve() {}
+CompositorFloatAnimationCurve::~CompositorFloatAnimationCurve() = default;
 
 std::unique_ptr<CompositorFloatAnimationCurve>
 CompositorFloatAnimationCurve::CreateForTesting(
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp
index 3dedd0e02..270ced42 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp
@@ -21,7 +21,7 @@
     std::unique_ptr<cc::FloatKeyframe> float_keyframe)
     : float_keyframe_(std::move(float_keyframe)) {}
 
-CompositorFloatKeyframe::~CompositorFloatKeyframe() {}
+CompositorFloatKeyframe::~CompositorFloatKeyframe() = default;
 
 double CompositorFloatKeyframe::Time() const {
   return float_keyframe_->Time().InSecondsF();
diff --git a/third_party/WebKit/Source/platform/animation/CompositorKeyframe.h b/third_party/WebKit/Source/platform/animation/CompositorKeyframe.h
index e333e82..e15bd73 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorKeyframe.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorKeyframe.h
@@ -18,7 +18,7 @@
 
 class PLATFORM_EXPORT CompositorKeyframe {
  public:
-  virtual ~CompositorKeyframe() {}
+  virtual ~CompositorKeyframe() = default;
 
   virtual double Time() const = 0;
 
diff --git a/third_party/WebKit/Source/platform/animation/CompositorScrollOffsetAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorScrollOffsetAnimationCurve.cpp
index 3671bba..d853acf 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorScrollOffsetAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorScrollOffsetAnimationCurve.cpp
@@ -43,7 +43,8 @@
     cc::ScrollOffsetAnimationCurve* curve)
     : curve_(curve->CloneToScrollOffsetAnimationCurve()) {}
 
-CompositorScrollOffsetAnimationCurve::~CompositorScrollOffsetAnimationCurve() {}
+CompositorScrollOffsetAnimationCurve::~CompositorScrollOffsetAnimationCurve() =
+    default;
 
 void CompositorScrollOffsetAnimationCurve::SetInitialValue(
     FloatPoint initial_value) {
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
index 3cc5ccc..3a9479c2 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
@@ -14,7 +14,8 @@
 CompositorTransformAnimationCurve::CompositorTransformAnimationCurve()
     : curve_(cc::KeyframedTransformAnimationCurve::Create()) {}
 
-CompositorTransformAnimationCurve::~CompositorTransformAnimationCurve() {}
+CompositorTransformAnimationCurve::~CompositorTransformAnimationCurve() =
+    default;
 
 void CompositorTransformAnimationCurve::AddKeyframe(
     const CompositorTransformKeyframe& keyframe) {
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp
index 75100e98..70a56a6 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp
@@ -17,7 +17,7 @@
                                         value.ReleaseCcTransformOperations(),
                                         timing_function.CloneToCC())) {}
 
-CompositorTransformKeyframe::~CompositorTransformKeyframe() {}
+CompositorTransformKeyframe::~CompositorTransformKeyframe() = default;
 
 double CompositorTransformKeyframe::Time() const {
   return transform_keyframe_->Time().InSecondsF();
diff --git a/third_party/WebKit/Source/platform/animation/TimingFunction.h b/third_party/WebKit/Source/platform/animation/TimingFunction.h
index 5824d27..4cf3b9f 100644
--- a/third_party/WebKit/Source/platform/animation/TimingFunction.h
+++ b/third_party/WebKit/Source/platform/animation/TimingFunction.h
@@ -40,7 +40,7 @@
  public:
   using Type = cc::TimingFunction::Type;
 
-  virtual ~TimingFunction() {}
+  virtual ~TimingFunction() = default;
 
   Type GetType() const { return type_; }
 
@@ -72,7 +72,7 @@
     return linear;
   }
 
-  ~LinearTimingFunction() override {}
+  ~LinearTimingFunction() override = default;
 
   // TimingFunction implementation.
   String ToString() const override;
@@ -97,7 +97,7 @@
 
   static CubicBezierTimingFunction* Preset(EaseType);
 
-  ~CubicBezierTimingFunction() override {}
+  ~CubicBezierTimingFunction() override = default;
 
   // TimingFunction implementation.
   String ToString() const override;
@@ -177,7 +177,7 @@
     }
   }
 
-  ~StepsTimingFunction() override {}
+  ~StepsTimingFunction() override = default;
 
   // TimingFunction implementation.
   String ToString() const override;
@@ -202,7 +202,7 @@
     return base::AdoptRef(new FramesTimingFunction(frames));
   }
 
-  ~FramesTimingFunction() override {}
+  ~FramesTimingFunction() override = default;
 
   // TimingFunction implementation.
   String ToString() const override;
diff --git a/third_party/WebKit/Source/platform/audio/AudioBus.h b/third_party/WebKit/Source/platform/audio/AudioBus.h
index 29e817b6..e119992 100644
--- a/third_party/WebKit/Source/platform/audio/AudioBus.h
+++ b/third_party/WebKit/Source/platform/audio/AudioBus.h
@@ -174,7 +174,7 @@
                                                  float sample_rate);
 
  protected:
-  AudioBus() {}
+  AudioBus() = default;
 
   AudioBus(unsigned number_of_channels, size_t length, bool allocate);
 
diff --git a/third_party/WebKit/Source/platform/audio/AudioDSPKernel.cpp b/third_party/WebKit/Source/platform/audio/AudioDSPKernel.cpp
index b525933..59e4baf9 100644
--- a/third_party/WebKit/Source/platform/audio/AudioDSPKernel.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioDSPKernel.cpp
@@ -32,6 +32,6 @@
 
 namespace blink {
 
-AudioDSPKernel::~AudioDSPKernel() {}
+AudioDSPKernel::~AudioDSPKernel() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioIOCallback.h b/third_party/WebKit/Source/platform/audio/AudioIOCallback.h
index 027c4ed..5e76cee 100644
--- a/third_party/WebKit/Source/platform/audio/AudioIOCallback.h
+++ b/third_party/WebKit/Source/platform/audio/AudioIOCallback.h
@@ -54,7 +54,7 @@
                       size_t frames_to_process,
                       const AudioIOPosition& output_position) = 0;
 
-  virtual ~AudioIOCallback() {}
+  virtual ~AudioIOCallback() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioProcessor.cpp b/third_party/WebKit/Source/platform/audio/AudioProcessor.cpp
index be2042e..104af91 100644
--- a/third_party/WebKit/Source/platform/audio/AudioProcessor.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioProcessor.cpp
@@ -32,6 +32,6 @@
 
 namespace blink {
 
-AudioProcessor::~AudioProcessor() {}
+AudioProcessor::~AudioProcessor() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioResampler.h b/third_party/WebKit/Source/platform/audio/AudioResampler.h
index fe817b0..7caa3a05 100644
--- a/third_party/WebKit/Source/platform/audio/AudioResampler.h
+++ b/third_party/WebKit/Source/platform/audio/AudioResampler.h
@@ -47,7 +47,7 @@
  public:
   AudioResampler();
   AudioResampler(unsigned number_of_channels);
-  ~AudioResampler() {}
+  ~AudioResampler() = default;
 
   // Given an AudioSourceProvider, process() resamples the source stream into
   // destinationBus.
diff --git a/third_party/WebKit/Source/platform/audio/AudioSourceProvider.h b/third_party/WebKit/Source/platform/audio/AudioSourceProvider.h
index 6f20c5b..e1fb71d 100644
--- a/third_party/WebKit/Source/platform/audio/AudioSourceProvider.h
+++ b/third_party/WebKit/Source/platform/audio/AudioSourceProvider.h
@@ -45,7 +45,7 @@
   DISALLOW_COPY_AND_ASSIGN(AudioSourceProvider);
 
  public:
-  AudioSourceProvider() {}
+  AudioSourceProvider() = default;
 
   // provideInput() gets called repeatedly to render time-slices of a continuous
   // audio stream.
@@ -55,7 +55,7 @@
   // changes.
   virtual void SetClient(AudioSourceProviderClient*){};
 
-  virtual ~AudioSourceProvider() {}
+  virtual ~AudioSourceProvider() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioSourceProviderClient.h b/third_party/WebKit/Source/platform/audio/AudioSourceProviderClient.h
index 28f62dfb..5d9df6fa 100644
--- a/third_party/WebKit/Source/platform/audio/AudioSourceProviderClient.h
+++ b/third_party/WebKit/Source/platform/audio/AudioSourceProviderClient.h
@@ -45,7 +45,7 @@
   void Trace(blink::Visitor* visitor) override {}
 
  protected:
-  virtual ~AudioSourceProviderClient() {}
+  virtual ~AudioSourceProviderClient() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/Biquad.cpp b/third_party/WebKit/Source/platform/audio/Biquad.cpp
index 19b10f6..74d9cd5f 100644
--- a/third_party/WebKit/Source/platform/audio/Biquad.cpp
+++ b/third_party/WebKit/Source/platform/audio/Biquad.cpp
@@ -67,7 +67,7 @@
   Reset();  // clear filter memory
 }
 
-Biquad::~Biquad() {}
+Biquad::~Biquad() = default;
 
 void Biquad::Process(const float* source_p,
                      float* dest_p,
diff --git a/third_party/WebKit/Source/platform/audio/HRTFPanner.cpp b/third_party/WebKit/Source/platform/audio/HRTFPanner.cpp
index ec948f63..d1ba39a 100644
--- a/third_party/WebKit/Source/platform/audio/HRTFPanner.cpp
+++ b/third_party/WebKit/Source/platform/audio/HRTFPanner.cpp
@@ -63,7 +63,7 @@
   DCHECK(database_loader);
 }
 
-HRTFPanner::~HRTFPanner() {}
+HRTFPanner::~HRTFPanner() = default;
 
 size_t HRTFPanner::FftSizeForSampleRate(float sample_rate) {
   // The HRTF impulse responses (loaded as audio resources) are 512
diff --git a/third_party/WebKit/Source/platform/audio/IIRFilter.cpp b/third_party/WebKit/Source/platform/audio/IIRFilter.cpp
index 38c15c4..2c3e8e5 100644
--- a/third_party/WebKit/Source/platform/audio/IIRFilter.cpp
+++ b/third_party/WebKit/Source/platform/audio/IIRFilter.cpp
@@ -28,7 +28,7 @@
   y_buffer_.Allocate(kBufferLength);
 }
 
-IIRFilter::~IIRFilter() {}
+IIRFilter::~IIRFilter() = default;
 
 void IIRFilter::Reset() {
   x_buffer_.Zero();
diff --git a/third_party/WebKit/Source/platform/audio/Panner.h b/third_party/WebKit/Source/platform/audio/Panner.h
index cfe5be6..ffd3497bb 100644
--- a/third_party/WebKit/Source/platform/audio/Panner.h
+++ b/third_party/WebKit/Source/platform/audio/Panner.h
@@ -55,7 +55,8 @@
                                         float sample_rate,
                                         HRTFDatabaseLoader*);
 
-  virtual ~Panner(){};
+  virtual ~Panner() = default;
+  ;
 
   virtual void Pan(double azimuth,
                    double elevation,
diff --git a/third_party/WebKit/Source/platform/audio/StereoPanner.h b/third_party/WebKit/Source/platform/audio/StereoPanner.h
index be6067b..c0d1512 100644
--- a/third_party/WebKit/Source/platform/audio/StereoPanner.h
+++ b/third_party/WebKit/Source/platform/audio/StereoPanner.h
@@ -22,7 +22,8 @@
 
  public:
   static std::unique_ptr<StereoPanner> Create(float sample_rate);
-  ~StereoPanner(){};
+  ~StereoPanner() = default;
+  ;
 
   void PanWithSampleAccurateValues(const AudioBus* input_bus,
                                    AudioBus* output_bus,
diff --git a/third_party/WebKit/Source/platform/bindings/DOMWrapperWorld.h b/third_party/WebKit/Source/platform/bindings/DOMWrapperWorld.h
index 48baf31..88c42d3 100644
--- a/third_party/WebKit/Source/platform/bindings/DOMWrapperWorld.h
+++ b/third_party/WebKit/Source/platform/bindings/DOMWrapperWorld.h
@@ -155,7 +155,7 @@
    public:
     DOMObjectHolderBase(v8::Isolate* isolate, v8::Local<v8::Value> wrapper)
         : wrapper_(isolate, wrapper), world_(nullptr) {}
-    virtual ~DOMObjectHolderBase() {}
+    virtual ~DOMObjectHolderBase() = default;
 
     DOMWrapperWorld* World() const { return world_; }
     void SetWorld(DOMWrapperWorld* world) { world_ = world; }
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
index c6ea9b0..72464ed7 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
@@ -48,7 +48,7 @@
   void Dump(TracedValue&) const;
 
  private:
-  RuntimeCallCounter() {}
+  RuntimeCallCounter() = default;
 
   uint64_t count_;
   TimeDelta time_;
diff --git a/third_party/WebKit/Source/platform/bindings/ScopedPersistent.h b/third_party/WebKit/Source/platform/bindings/ScopedPersistent.h
index 559b82f..d6ac533 100644
--- a/third_party/WebKit/Source/platform/bindings/ScopedPersistent.h
+++ b/third_party/WebKit/Source/platform/bindings/ScopedPersistent.h
@@ -50,7 +50,7 @@
   WTF_MAKE_NONCOPYABLE(ScopedPersistent);
 
  public:
-  ScopedPersistent() {}
+  ScopedPersistent() = default;
 
   ScopedPersistent(v8::Isolate* isolate, v8::Local<T> handle)
       : handle_(isolate, handle) {}
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappable.cpp b/third_party/WebKit/Source/platform/bindings/ScriptWrappable.cpp
index 1af85736..6975da7 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappable.cpp
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappable.cpp
@@ -11,7 +11,7 @@
 namespace blink {
 
 struct SameSizeAsScriptWrappable {
-  virtual ~SameSizeAsScriptWrappable() {}
+  virtual ~SameSizeAsScriptWrappable() = default;
   v8::Persistent<v8::Object> main_world_wrapper_;
 };
 
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp
index 0685084..64540e8 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp
@@ -23,7 +23,7 @@
 
 namespace blink {
 
-ScriptWrappableVisitor::~ScriptWrappableVisitor() {}
+ScriptWrappableVisitor::~ScriptWrappableVisitor() = default;
 
 void ScriptWrappableVisitor::TracePrologue() {
   // This CHECK ensures that wrapper tracing is not started from scopes
diff --git a/third_party/WebKit/Source/platform/bindings/V0CustomElementBinding.cpp b/third_party/WebKit/Source/platform/bindings/V0CustomElementBinding.cpp
index dbfa5d6..411f4b6 100644
--- a/third_party/WebKit/Source/platform/bindings/V0CustomElementBinding.cpp
+++ b/third_party/WebKit/Source/platform/bindings/V0CustomElementBinding.cpp
@@ -47,6 +47,6 @@
   DCHECK(!prototype_.IsEmpty());
 }
 
-V0CustomElementBinding::~V0CustomElementBinding() {}
+V0CustomElementBinding::~V0CustomElementBinding() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h b/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h
index fe28de55..b91c737e 100644
--- a/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h
+++ b/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h
@@ -45,7 +45,7 @@
   USING_FAST_MALLOC(V8DOMActivityLogger);
 
  public:
-  virtual ~V8DOMActivityLogger() {}
+  virtual ~V8DOMActivityLogger() = default;
 
   virtual void LogGetter(const String& api_name) {}
   virtual void LogSetter(const String& api_name,
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
index 3ccd3ee..8c62f1f 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
+++ b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
@@ -113,7 +113,7 @@
   g_main_thread_per_isolate_data = this;
 }
 
-V8PerIsolateData::~V8PerIsolateData() {}
+V8PerIsolateData::~V8PerIsolateData() = default;
 
 v8::Isolate* V8PerIsolateData::MainThreadIsolate() {
   DCHECK(g_main_thread_per_isolate_data);
diff --git a/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h b/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h
index 40bbcc6..289bd46 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h
+++ b/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h
@@ -211,7 +211,7 @@
   }
 
  private:
-  V8PrivateProperty() {}
+  V8PrivateProperty() = default;
 
   static v8::Local<v8::Private> CreateV8Private(v8::Isolate*,
                                                 const char* symbol);
diff --git a/third_party/WebKit/Source/platform/blob/BlobData.cpp b/third_party/WebKit/Source/platform/blob/BlobData.cpp
index 5b22560..3945fa3 100644
--- a/third_party/WebKit/Source/platform/blob/BlobData.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobData.cpp
@@ -110,7 +110,7 @@
 
 const long long BlobDataItem::kToEndOfFile = -1;
 
-RawData::RawData() {}
+RawData::RawData() = default;
 
 void BlobDataItem::DetachFromCurrentThread() {
   path = path.IsolatedCopy();
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp
index 972583e..366f5b9 100644
--- a/third_party/WebKit/Source/platform/exported/Platform.cpp
+++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -113,7 +113,7 @@
   WTF::Partitions::Initialize(MaxObservedSizeFunction);
 }
 
-Platform::~Platform() {}
+Platform::~Platform() = default;
 
 void Platform::Initialize(Platform* platform) {
   DCHECK(!g_platform);
diff --git a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp
index 6e4bf3f..de45a854 100644
--- a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.cpp
@@ -41,7 +41,7 @@
       new WebActiveGestureAnimation(std::move(curve), target, start_time));
 }
 
-WebActiveGestureAnimation::~WebActiveGestureAnimation() {}
+WebActiveGestureAnimation::~WebActiveGestureAnimation() = default;
 
 WebActiveGestureAnimation::WebActiveGestureAnimation(
     std::unique_ptr<WebGestureCurve> curve,
diff --git a/third_party/WebKit/Source/platform/exported/WebAudioDevice.cpp b/third_party/WebKit/Source/platform/exported/WebAudioDevice.cpp
index e14ed8d..7ab20e4d 100644
--- a/third_party/WebKit/Source/platform/exported/WebAudioDevice.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebAudioDevice.cpp
@@ -33,6 +33,6 @@
     double delay_timestamp,
     size_t prior_frames_skipped) {}
 
-WebAudioDevice::RenderCallback::~RenderCallback() {}
+WebAudioDevice::RenderCallback::~RenderCallback() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebBlobData.cpp b/third_party/WebKit/Source/platform/exported/WebBlobData.cpp
index 3a468adc..78469a3 100644
--- a/third_party/WebKit/Source/platform/exported/WebBlobData.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebBlobData.cpp
@@ -36,9 +36,9 @@
 
 namespace blink {
 
-WebBlobData::WebBlobData() {}
+WebBlobData::WebBlobData() = default;
 
-WebBlobData::~WebBlobData() {}
+WebBlobData::~WebBlobData() = default;
 
 size_t WebBlobData::ItemCount() const {
   DCHECK(!IsNull());
diff --git a/third_party/WebKit/Source/platform/exported/WebContentDecryptionModule.cpp b/third_party/WebKit/Source/platform/exported/WebContentDecryptionModule.cpp
index 01ad80d..8f9d195 100644
--- a/third_party/WebKit/Source/platform/exported/WebContentDecryptionModule.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebContentDecryptionModule.cpp
@@ -26,6 +26,6 @@
 
 namespace blink {
 
-WebContentDecryptionModule::~WebContentDecryptionModule() {}
+WebContentDecryptionModule::~WebContentDecryptionModule() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleAccess.cpp b/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleAccess.cpp
index 3b01fa0..c77c82e 100644
--- a/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleAccess.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleAccess.cpp
@@ -6,6 +6,6 @@
 
 namespace blink {
 
-WebContentDecryptionModuleAccess::~WebContentDecryptionModuleAccess() {}
+WebContentDecryptionModuleAccess::~WebContentDecryptionModuleAccess() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleSession.cpp b/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleSession.cpp
index 567d52c4..63b14c45 100644
--- a/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleSession.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebContentDecryptionModuleSession.cpp
@@ -28,8 +28,9 @@
 
 namespace blink {
 
-WebContentDecryptionModuleSession::~WebContentDecryptionModuleSession() {}
+WebContentDecryptionModuleSession::~WebContentDecryptionModuleSession() =
+    default;
 
-WebContentDecryptionModuleSession::Client::~Client() {}
+WebContentDecryptionModuleSession::Client::~Client() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebEncryptedMediaClient.cpp b/third_party/WebKit/Source/platform/exported/WebEncryptedMediaClient.cpp
index 9f78781..cd5a6dd9 100644
--- a/third_party/WebKit/Source/platform/exported/WebEncryptedMediaClient.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebEncryptedMediaClient.cpp
@@ -6,6 +6,6 @@
 
 namespace blink {
 
-WebEncryptedMediaClient::~WebEncryptedMediaClient() {}
+WebEncryptedMediaClient::~WebEncryptedMediaClient() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebEncryptedMediaKeyInformation.cpp b/third_party/WebKit/Source/platform/exported/WebEncryptedMediaKeyInformation.cpp
index 2010a122..889405c 100644
--- a/third_party/WebKit/Source/platform/exported/WebEncryptedMediaKeyInformation.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebEncryptedMediaKeyInformation.cpp
@@ -6,9 +6,9 @@
 
 namespace blink {
 
-WebEncryptedMediaKeyInformation::WebEncryptedMediaKeyInformation() {}
+WebEncryptedMediaKeyInformation::WebEncryptedMediaKeyInformation() = default;
 
-WebEncryptedMediaKeyInformation::~WebEncryptedMediaKeyInformation() {}
+WebEncryptedMediaKeyInformation::~WebEncryptedMediaKeyInformation() = default;
 
 WebData WebEncryptedMediaKeyInformation::Id() const {
   return id_;
diff --git a/third_party/WebKit/Source/platform/exported/WebFont.cpp b/third_party/WebKit/Source/platform/exported/WebFont.cpp
index fee8027c..850e741 100644
--- a/third_party/WebKit/Source/platform/exported/WebFont.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebFont.cpp
@@ -38,7 +38,7 @@
 WebFont::WebFont(const WebFontDescription& description)
     : private_(new Impl(description)) {}
 
-WebFont::~WebFont() {}
+WebFont::~WebFont() = default;
 
 WebFontDescription WebFont::GetFontDescription() const {
   return WebFontDescription(private_->GetFont().GetFontDescription());
diff --git a/third_party/WebKit/Source/platform/exported/WebHTTPHeaderMap.cpp b/third_party/WebKit/Source/platform/exported/WebHTTPHeaderMap.cpp
index e0b2d00..e32d665d 100644
--- a/third_party/WebKit/Source/platform/exported/WebHTTPHeaderMap.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebHTTPHeaderMap.cpp
@@ -50,7 +50,8 @@
   HTTPHeaderMap map_;
 };
 
-WebHTTPHeaderMap::~WebHTTPHeaderMap(){};
+WebHTTPHeaderMap::~WebHTTPHeaderMap() = default;
+;
 
 WebHTTPHeaderMap::WebHTTPHeaderMap(const HTTPHeaderMap& map) {
   implementation_ = std::make_unique<WebHTTPHeaderMapImpl>(map);
diff --git a/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp b/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp
index 84b6ccb..4aaf97cf 100644
--- a/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebMediaConstraints.cpp
@@ -155,7 +155,7 @@
 
 BaseConstraint::BaseConstraint(const char* name) : name_(name) {}
 
-BaseConstraint::~BaseConstraint() {}
+BaseConstraint::~BaseConstraint() = default;
 
 LongConstraint::LongConstraint(const char* name)
     : BaseConstraint(name),
diff --git a/third_party/WebKit/Source/platform/exported/WebMediaPlayerSource.cpp b/third_party/WebKit/Source/platform/exported/WebMediaPlayerSource.cpp
index c618dc47..3f6f437 100644
--- a/third_party/WebKit/Source/platform/exported/WebMediaPlayerSource.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebMediaPlayerSource.cpp
@@ -6,7 +6,7 @@
 
 namespace blink {
 
-WebMediaPlayerSource::WebMediaPlayerSource() {}
+WebMediaPlayerSource::WebMediaPlayerSource() = default;
 
 WebMediaPlayerSource::WebMediaPlayerSource(const WebURL& url) : url_(url) {}
 
diff --git a/third_party/WebKit/Source/platform/exported/WebPrerender.cpp b/third_party/WebKit/Source/platform/exported/WebPrerender.cpp
index a347532d..3daa49d 100644
--- a/third_party/WebKit/Source/platform/exported/WebPrerender.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebPrerender.cpp
@@ -46,7 +46,7 @@
     return base::AdoptRef(new PrerenderExtraDataContainer(extra_data));
   }
 
-  ~PrerenderExtraDataContainer() override {}
+  ~PrerenderExtraDataContainer() override = default;
 
   WebPrerender::ExtraData* GetExtraData() const { return extra_data_.get(); }
 
diff --git a/third_party/WebKit/Source/platform/exported/WebRTCPeerConnectionHandlerClient.cpp b/third_party/WebKit/Source/platform/exported/WebRTCPeerConnectionHandlerClient.cpp
index 2e2a5fce..f86bf524 100644
--- a/third_party/WebKit/Source/platform/exported/WebRTCPeerConnectionHandlerClient.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRTCPeerConnectionHandlerClient.cpp
@@ -6,7 +6,8 @@
 
 namespace blink {
 
-WebRTCPeerConnectionHandlerClient::~WebRTCPeerConnectionHandlerClient() {}
+WebRTCPeerConnectionHandlerClient::~WebRTCPeerConnectionHandlerClient() =
+    default;
 
 void WebRTCPeerConnectionHandlerClient::ClosePeerConnection() {}
 
diff --git a/third_party/WebKit/Source/platform/exported/WebRTCRtpContributingSource.cpp b/third_party/WebKit/Source/platform/exported/WebRTCRtpContributingSource.cpp
index e8480b0..e07d324 100644
--- a/third_party/WebKit/Source/platform/exported/WebRTCRtpContributingSource.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRTCRtpContributingSource.cpp
@@ -6,6 +6,6 @@
 
 namespace blink {
 
-WebRTCRtpContributingSource::~WebRTCRtpContributingSource() {}
+WebRTCRtpContributingSource::~WebRTCRtpContributingSource() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebRTCRtpReceiver.cpp b/third_party/WebKit/Source/platform/exported/WebRTCRtpReceiver.cpp
index 39658f6..6ecc260 100644
--- a/third_party/WebKit/Source/platform/exported/WebRTCRtpReceiver.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRTCRtpReceiver.cpp
@@ -6,6 +6,6 @@
 
 namespace blink {
 
-WebRTCRtpReceiver::~WebRTCRtpReceiver() {}
+WebRTCRtpReceiver::~WebRTCRtpReceiver() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp b/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp
index 54393666..7800cee 100644
--- a/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRTCRtpSender.cpp
@@ -6,6 +6,6 @@
 
 namespace blink {
 
-WebRTCRtpSender::~WebRTCRtpSender() {}
+WebRTCRtpSender::~WebRTCRtpSender() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebRTCStats.cpp b/third_party/WebKit/Source/platform/exported/WebRTCStats.cpp
index a354dee3..ec490a11 100644
--- a/third_party/WebKit/Source/platform/exported/WebRTCStats.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRTCStats.cpp
@@ -6,12 +6,12 @@
 
 namespace blink {
 
-WebRTCStatsReport::~WebRTCStatsReport() {}
+WebRTCStatsReport::~WebRTCStatsReport() = default;
 
-WebRTCStats::~WebRTCStats() {}
+WebRTCStats::~WebRTCStats() = default;
 
-WebRTCStatsMember::~WebRTCStatsMember() {}
+WebRTCStatsMember::~WebRTCStatsMember() = default;
 
-WebRTCStatsReportCallback::~WebRTCStatsReportCallback() {}
+WebRTCStatsReportCallback::~WebRTCStatsReportCallback() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebSpeechSynthesizerClientImpl.cpp b/third_party/WebKit/Source/platform/exported/WebSpeechSynthesizerClientImpl.cpp
index dd3a398..2b19c6c 100644
--- a/third_party/WebKit/Source/platform/exported/WebSpeechSynthesizerClientImpl.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebSpeechSynthesizerClientImpl.cpp
@@ -34,7 +34,7 @@
     PlatformSpeechSynthesizerClient* client)
     : synthesizer_(synthesizer), client_(client) {}
 
-WebSpeechSynthesizerClientImpl::~WebSpeechSynthesizerClientImpl() {}
+WebSpeechSynthesizerClientImpl::~WebSpeechSynthesizerClientImpl() = default;
 
 void WebSpeechSynthesizerClientImpl::SetVoiceList(
     const WebVector<WebSpeechSynthesisVoice>& voices) {
diff --git a/third_party/WebKit/Source/platform/exported/WebSurfaceLayerBridge.cpp b/third_party/WebKit/Source/platform/exported/WebSurfaceLayerBridge.cpp
index eb1c33f..1a854e9c 100644
--- a/third_party/WebKit/Source/platform/exported/WebSurfaceLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebSurfaceLayerBridge.cpp
@@ -15,6 +15,6 @@
   return std::make_unique<SurfaceLayerBridge>(layer_tree_view, observer);
 }
 
-WebSurfaceLayerBridge::~WebSurfaceLayerBridge() {}
+WebSurfaceLayerBridge::~WebSurfaceLayerBridge() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebThreadSafeData.cpp b/third_party/WebKit/Source/platform/exported/WebThreadSafeData.cpp
index 348893b..6b0b9dc 100644
--- a/third_party/WebKit/Source/platform/exported/WebThreadSafeData.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebThreadSafeData.cpp
@@ -70,10 +70,7 @@
 }
 
 WebThreadSafeData& WebThreadSafeData::operator=(
-    const WebThreadSafeData& other) {
-  private_ = other.private_;
-  return *this;
-}
+    const WebThreadSafeData& other) = default;
 
 WebThreadSafeData& WebThreadSafeData::operator=(scoped_refptr<RawData> data) {
   private_ = std::move(data);
diff --git a/third_party/WebKit/Source/platform/exported/WebURLLoaderTestDelegate.cpp b/third_party/WebKit/Source/platform/exported/WebURLLoaderTestDelegate.cpp
index 67b9c96..2bd97ae 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLLoaderTestDelegate.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLLoaderTestDelegate.cpp
@@ -11,9 +11,9 @@
 
 namespace blink {
 
-WebURLLoaderTestDelegate::WebURLLoaderTestDelegate() {}
+WebURLLoaderTestDelegate::WebURLLoaderTestDelegate() = default;
 
-WebURLLoaderTestDelegate::~WebURLLoaderTestDelegate() {}
+WebURLLoaderTestDelegate::~WebURLLoaderTestDelegate() = default;
 
 void WebURLLoaderTestDelegate::DidReceiveResponse(
     WebURLLoaderClient* original_client,
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
index c306452..55aa371 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
@@ -51,7 +51,7 @@
     return base::AdoptRef(new URLRequestExtraDataContainer(extra_data));
   }
 
-  ~URLRequestExtraDataContainer() override {}
+  ~URLRequestExtraDataContainer() override = default;
 
   WebURLRequest::ExtraData* GetExtraData() const { return extra_data_.get(); }
 
@@ -68,14 +68,14 @@
 // heap, which is otherwise disallowed by DISALLOW_NEW_EXCEPT_PLACEMENT_NEW
 // annotation on ResourceRequest.
 struct WebURLRequest::ResourceRequestContainer {
-  ResourceRequestContainer() {}
+  ResourceRequestContainer() = default;
   explicit ResourceRequestContainer(const ResourceRequest& r)
       : resource_request(r) {}
 
   ResourceRequest resource_request;
 };
 
-WebURLRequest::~WebURLRequest() {}
+WebURLRequest::~WebURLRequest() = default;
 
 WebURLRequest::WebURLRequest()
     : owned_resource_request_(new ResourceRequestContainer()),
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
index e706820f..4e3248a 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -54,7 +54,7 @@
     return base::AdoptRef(new URLResponseExtraDataContainer(extra_data));
   }
 
-  ~URLResponseExtraDataContainer() override {}
+  ~URLResponseExtraDataContainer() override = default;
 
   WebURLResponse::ExtraData* GetExtraData() const { return extra_data_.get(); }
 
@@ -71,7 +71,7 @@
 // heap, which is otherwise disallowed by the DISALLOW_NEW_EXCEPT_PLACEMENT_NEW
 // annotation on ResourceResponse.
 struct WebURLResponse::ResourceResponseContainer {
-  ResourceResponseContainer() {}
+  ResourceResponseContainer() = default;
 
   explicit ResourceResponseContainer(const ResourceResponse& r)
       : resource_response(r) {}
@@ -79,7 +79,7 @@
   ResourceResponse resource_response;
 };
 
-WebURLResponse::~WebURLResponse() {}
+WebURLResponse::~WebURLResponse() = default;
 
 WebURLResponse::WebURLResponse()
     : owned_resource_response_(new ResourceResponseContainer()),
diff --git a/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h b/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h
index 57d15f7..8d69f10 100644
--- a/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h
+++ b/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h
@@ -43,7 +43,7 @@
   WTF_MAKE_NONCOPYABLE(WrappedResourceRequest);
 
  public:
-  ~WrappedResourceRequest() {}
+  ~WrappedResourceRequest() = default;
 
   explicit WrappedResourceRequest(ResourceRequest& resource_request)
       : WebURLRequest(resource_request) {}
diff --git a/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h b/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
index 496229d..4fc9ad6 100644
--- a/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
+++ b/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
@@ -42,7 +42,7 @@
   WTF_MAKE_NONCOPYABLE(WrappedResourceResponse);
 
  public:
-  ~WrappedResourceResponse() {}
+  ~WrappedResourceResponse() = default;
 
   explicit WrappedResourceResponse(ResourceResponse& resource_response)
       : WebURLResponse(resource_response) {}
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp
index 10820f8..998e7dcf 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicyTest.cpp
@@ -57,10 +57,9 @@
 
 class FeaturePolicyTest : public ::testing::Test {
  protected:
-  FeaturePolicyTest() {}
+  FeaturePolicyTest() = default;
 
-  ~FeaturePolicyTest() {
-  }
+  ~FeaturePolicyTest() = default;
 
   scoped_refptr<const SecurityOrigin> origin_a_ =
       SecurityOrigin::CreateFromString(ORIGIN_A);
diff --git a/third_party/WebKit/Source/platform/fonts/CustomFontData.h b/third_party/WebKit/Source/platform/fonts/CustomFontData.h
index af22c60..a222074f 100644
--- a/third_party/WebKit/Source/platform/fonts/CustomFontData.h
+++ b/third_party/WebKit/Source/platform/fonts/CustomFontData.h
@@ -33,7 +33,7 @@
     return base::AdoptRef(new CustomFontData());
   }
 
-  virtual ~CustomFontData() {}
+  virtual ~CustomFontData() = default;
 
   virtual void BeginLoadIfNeeded() const {}
   virtual bool IsLoading() const { return false; }
@@ -42,7 +42,7 @@
   virtual void ClearFontFaceSource() {}
 
  protected:
-  CustomFontData() {}
+  CustomFontData() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h b/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h
index d09a7b37..e4d0618a 100644
--- a/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h
+++ b/third_party/WebKit/Source/platform/fonts/FallbackListCompositeKey.h
@@ -67,7 +67,6 @@
 
  private:
   static const unsigned kDeletedValueHash = 1;
-  FontDescription font_description_;
   Vector<FontCacheKey> font_cache_keys_;
   unsigned hash_;
 
diff --git a/third_party/WebKit/Source/platform/fonts/Font.h b/third_party/WebKit/Source/platform/fonts/Font.h
index c489c1b..8630376 100644
--- a/third_party/WebKit/Source/platform/fonts/Font.h
+++ b/third_party/WebKit/Source/platform/fonts/Font.h
@@ -222,7 +222,7 @@
   friend class CachingWordShaper;
 };
 
-inline Font::~Font() {}
+inline Font::~Font() = default;
 
 inline const SimpleFontData* Font::PrimaryFont() const {
   DCHECK(font_fallback_list_);
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.h b/third_party/WebKit/Source/platform/fonts/FontCache.h
index c75a78a..0ef5539 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.h
@@ -234,7 +234,7 @@
   void DumpFontPlatformDataCache(base::trace_event::ProcessMemoryDump*);
   void DumpShapeResultCache(base::trace_event::ProcessMemoryDump*);
 
-  ~FontCache() {}
+  ~FontCache() = default;
 
  private:
   scoped_refptr<SimpleFontData> PlatformFallbackFontForCharacter(
diff --git a/third_party/WebKit/Source/platform/fonts/FontCacheClient.h b/third_party/WebKit/Source/platform/fonts/FontCacheClient.h
index 4630de5..2d5c76f 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCacheClient.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCacheClient.h
@@ -39,7 +39,7 @@
 class PLATFORM_EXPORT FontCacheClient
     : public GarbageCollectedFinalized<FontCacheClient> {
  public:
-  virtual ~FontCacheClient() {}
+  virtual ~FontCacheClient() = default;
 
   virtual void FontCacheInvalidated() = 0;
   virtual void Trace(blink::Visitor* visitor) {}
diff --git a/third_party/WebKit/Source/platform/fonts/FontCacheMemoryDumpProvider.h b/third_party/WebKit/Source/platform/fonts/FontCacheMemoryDumpProvider.h
index d2a6edd..68c3a86 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCacheMemoryDumpProvider.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCacheMemoryDumpProvider.h
@@ -19,14 +19,14 @@
 
  public:
   static FontCacheMemoryDumpProvider* Instance();
-  ~FontCacheMemoryDumpProvider() override {}
+  ~FontCacheMemoryDumpProvider() override = default;
 
   // base::trace_event::MemoryDumpProvider implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs&,
                     base::trace_event::ProcessMemoryDump*) override;
 
  private:
-  FontCacheMemoryDumpProvider() {}
+  FontCacheMemoryDumpProvider() = default;
 
   WTF_MAKE_NONCOPYABLE(FontCacheMemoryDumpProvider);
 };
diff --git a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
index 2be843c..93577261 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
@@ -58,7 +58,7 @@
                                                size_t data_size)
     : base_typeface_(std::move(typeface)), data_size_(data_size) {}
 
-FontCustomPlatformData::~FontCustomPlatformData() {}
+FontCustomPlatformData::~FontCustomPlatformData() = default;
 
 FontPlatformData FontCustomPlatformData::GetFontPlatformData(
     float size,
diff --git a/third_party/WebKit/Source/platform/fonts/FontData.cpp b/third_party/WebKit/Source/platform/fonts/FontData.cpp
index 776c0306..5dc613a7 100644
--- a/third_party/WebKit/Source/platform/fonts/FontData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontData.cpp
@@ -27,6 +27,6 @@
 
 namespace blink {
 
-FontData::~FontData() {}
+FontData::~FontData() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontData.h b/third_party/WebKit/Source/platform/fonts/FontData.h
index 79f6b72..fc2ca9c 100644
--- a/third_party/WebKit/Source/platform/fonts/FontData.h
+++ b/third_party/WebKit/Source/platform/fonts/FontData.h
@@ -42,7 +42,7 @@
   WTF_MAKE_NONCOPYABLE(FontData);
 
  public:
-  FontData() {}
+  FontData() = default;
 
   virtual ~FontData();
 
diff --git a/third_party/WebKit/Source/platform/fonts/FontDataCache.h b/third_party/WebKit/Source/platform/fonts/FontDataCache.h
index 1c963eb..0df9acc8e 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDataCache.h
+++ b/third_party/WebKit/Source/platform/fonts/FontDataCache.h
@@ -72,7 +72,7 @@
   WTF_MAKE_NONCOPYABLE(FontDataCache);
 
  public:
-  FontDataCache() {}
+  FontDataCache() = default;
 
   scoped_refptr<SimpleFontData> Get(const FontPlatformData*,
                                     ShouldRetain = kRetain,
diff --git a/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h b/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
index 07c51424..230a7b6 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
+++ b/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
@@ -45,7 +45,8 @@
 
   FontDataForRangeSet(const FontDataForRangeSet& other);
 
-  virtual ~FontDataForRangeSet(){};
+  virtual ~FontDataForRangeSet() = default;
+  ;
 
   bool Contains(UChar32 test_char) const {
     return !range_set_ || range_set_->Contains(test_char);
diff --git a/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h b/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h
index 7f979f2..bad85b2 100644
--- a/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h
+++ b/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h
@@ -96,7 +96,7 @@
   friend class WTF::ThreadSpecific<FontGlobalContext>;
 
   FontGlobalContext();
-  ~FontGlobalContext() {}
+  ~FontGlobalContext() = default;
 
   FontCache font_cache_;
 
diff --git a/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp b/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp
index d86c56a3..58f7cd03 100644
--- a/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp
@@ -166,7 +166,7 @@
 #endif
 }
 
-FontPlatformData::~FontPlatformData() {}
+FontPlatformData::~FontPlatformData() = default;
 
 #if defined(OS_MACOSX)
 CTFontRef FontPlatformData::CtFont() const {
diff --git a/third_party/WebKit/Source/platform/fonts/FontSelector.h b/third_party/WebKit/Source/platform/fonts/FontSelector.h
index de71ec7..0f97320 100644
--- a/third_party/WebKit/Source/platform/fonts/FontSelector.h
+++ b/third_party/WebKit/Source/platform/fonts/FontSelector.h
@@ -44,7 +44,7 @@
 
 class PLATFORM_EXPORT FontSelector : public FontCacheClient {
  public:
-  virtual ~FontSelector() {}
+  virtual ~FontSelector() = default;
   virtual scoped_refptr<FontData> GetFontData(const FontDescription&,
                                        const AtomicString& family_name) = 0;
 
diff --git a/third_party/WebKit/Source/platform/fonts/FontSelectorClient.h b/third_party/WebKit/Source/platform/fonts/FontSelectorClient.h
index 678081b..1fed453d 100644
--- a/third_party/WebKit/Source/platform/fonts/FontSelectorClient.h
+++ b/third_party/WebKit/Source/platform/fonts/FontSelectorClient.h
@@ -13,7 +13,7 @@
 
 class FontSelectorClient : public GarbageCollectedMixin {
  public:
-  virtual ~FontSelectorClient() {}
+  virtual ~FontSelectorClient() = default;
 
   virtual void FontsNeedUpdate(FontSelector*) = 0;
 
diff --git a/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h b/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h
index 2d388e84..98fd3b6b 100644
--- a/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h
+++ b/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h
@@ -46,7 +46,7 @@
   DISALLOW_NEW();
 
  public:
-  GenericFontFamilySettings() {}
+  GenericFontFamilySettings() = default;
 
   explicit GenericFontFamilySettings(const GenericFontFamilySettings&);
 
diff --git a/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.cpp b/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.cpp
index 974afb5..df72973 100644
--- a/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.cpp
+++ b/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.cpp
@@ -14,7 +14,7 @@
 
 const int ScriptData::kMaxScriptCount = 20;
 
-ScriptData::~ScriptData() {}
+ScriptData::~ScriptData() = default;
 
 void ICUScriptData::GetScripts(UChar32 ch, Vector<UScriptCode>& dst) const {
   ICUError status;
diff --git a/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.h b/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.h
index 68bd067..0142ef8 100644
--- a/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/ScriptRunIterator.h
@@ -101,7 +101,7 @@
 
 class PLATFORM_EXPORT ICUScriptData : public ScriptData {
  public:
-  ~ICUScriptData() override {}
+  ~ICUScriptData() override = default;
 
   static const ICUScriptData* Instance();
 
diff --git a/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp b/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp
index b7b959e7..3368ef0 100644
--- a/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp
@@ -27,7 +27,7 @@
 
 class MockScriptData : public ScriptData {
  public:
-  ~MockScriptData() override {}
+  ~MockScriptData() override = default;
 
   static const MockScriptData* Instance() {
     DEFINE_THREAD_SAFE_STATIC_LOCAL(const MockScriptData, mock_script_data, ());
diff --git a/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h b/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h
index 251f787e..36bab5b 100644
--- a/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h
+++ b/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h
@@ -48,7 +48,7 @@
   bool ContainsCharacter(UChar32) const;
 
  private:
-  SegmentedFontData() {}
+  SegmentedFontData() = default;
 
   const SimpleFontData* FontDataForCharacter(UChar32) const override;
 
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.h b/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
index f9584d4..393770f9 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.h
@@ -180,7 +180,7 @@
     scoped_refptr<SimpleFontData> emphasis_mark;
 
    private:
-    DerivedFontData() {}
+    DerivedFontData() = default;
   };
 
   mutable std::unique_ptr<DerivedFontData> derived_font_data_;
diff --git a/third_party/WebKit/Source/platform/fonts/UnicodeRangeSet.h b/third_party/WebKit/Source/platform/fonts/UnicodeRangeSet.h
index 784edf23..e8aab46 100644
--- a/third_party/WebKit/Source/platform/fonts/UnicodeRangeSet.h
+++ b/third_party/WebKit/Source/platform/fonts/UnicodeRangeSet.h
@@ -59,7 +59,8 @@
 class PLATFORM_EXPORT UnicodeRangeSet : public RefCounted<UnicodeRangeSet> {
  public:
   explicit UnicodeRangeSet(const Vector<UnicodeRange>&);
-  UnicodeRangeSet(){};
+  UnicodeRangeSet() = default;
+  ;
   bool Contains(UChar32) const;
   bool IntersectsWith(const String&) const;
   bool IsEntireRange() const { return ranges_.IsEmpty(); }
diff --git a/third_party/WebKit/Source/platform/fonts/WebFontDecoder.h b/third_party/WebKit/Source/platform/fonts/WebFontDecoder.h
index bdcc3d8..a2f61767 100644
--- a/third_party/WebKit/Source/platform/fonts/WebFontDecoder.h
+++ b/third_party/WebKit/Source/platform/fonts/WebFontDecoder.h
@@ -44,7 +44,7 @@
   STACK_ALLOCATED();
 
  public:
-  WebFontDecoder() {}
+  WebFontDecoder() = default;
 
   sk_sp<SkTypeface> Decode(SharedBuffer*);
   size_t DecodedSize() const { return decoded_size_; }
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
index 719575a..6ef5fda 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.h
@@ -47,7 +47,7 @@
 
  public:
   explicit CachingWordShaper(const Font& font) : font_(font) {}
-  ~CachingWordShaper() {}
+  ~CachingWordShaper() = default;
 
   float Width(const TextRun&,
               HashSet<const SimpleFontData*>* fallback_fonts,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
index 8709e68..a843b682 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
@@ -68,7 +68,7 @@
   const UChar* GetText() const { return text_; }
   unsigned TextLength() const { return text_length_; }
 
-  ~HarfBuzzShaper() {}
+  ~HarfBuzzShaper() = default;
 
  private:
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
index 2151e90..f0b5017 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -227,7 +227,7 @@
     runs_.push_back(std::make_unique<RunInfo>(*run));
 }
 
-ShapeResult::~ShapeResult() {}
+ShapeResult::~ShapeResult() = default;
 
 size_t ShapeResult::ByteSize() const {
   size_t self_byte_size = sizeof(this);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h
index d17ebfd..c0202eb 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h
@@ -41,7 +41,7 @@
                      const LazyLineBreakIterator*,
                      ShapeResultSpacing<String>* = nullptr,
                      const Hyphenation* = nullptr);
-  ~ShapingLineBreaker() {}
+  ~ShapingLineBreaker() = default;
 
   // Represents details of the result of |ShapeLine()|.
   struct Result {
diff --git a/third_party/WebKit/Source/platform/geometry/DoubleRect.h b/third_party/WebKit/Source/platform/geometry/DoubleRect.h
index 7b6574d5..d5e7704 100644
--- a/third_party/WebKit/Source/platform/geometry/DoubleRect.h
+++ b/third_party/WebKit/Source/platform/geometry/DoubleRect.h
@@ -20,7 +20,7 @@
   STACK_ALLOCATED();
 
  public:
-  DoubleRect() {}
+  DoubleRect() = default;
   DoubleRect(const DoublePoint& location, const DoubleSize& size)
       : location_(location), size_(size) {}
   DoubleRect(double x, double y, double width, double height)
diff --git a/third_party/WebKit/Source/platform/geometry/FloatPolygon.h b/third_party/WebKit/Source/platform/geometry/FloatPolygon.h
index 6385bc05..d76b2dc 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatPolygon.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatPolygon.h
@@ -92,7 +92,7 @@
 
 class PLATFORM_EXPORT VertexPair {
  public:
-  virtual ~VertexPair() {}
+  virtual ~VertexPair() = default;
 
   virtual const FloatPoint& Vertex1() const = 0;
   virtual const FloatPoint& Vertex2() const = 0;
diff --git a/third_party/WebKit/Source/platform/geometry/FloatQuad.h b/third_party/WebKit/Source/platform/geometry/FloatQuad.h
index 17b951e..564dca9 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatQuad.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatQuad.h
@@ -47,7 +47,7 @@
   USING_FAST_MALLOC(FloatQuad);
 
  public:
-  FloatQuad() {}
+  FloatQuad() = default;
 
   FloatQuad(const FloatPoint& p1,
             const FloatPoint& p2,
diff --git a/third_party/WebKit/Source/platform/geometry/FloatRect.h b/third_party/WebKit/Source/platform/geometry/FloatRect.h
index 1bf5932..f404923 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatRect.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatRect.h
@@ -61,7 +61,7 @@
  public:
   enum ContainsMode { kInsideOrOnStroke, kInsideButNotOnStroke };
 
-  FloatRect() {}
+  FloatRect() = default;
   FloatRect(const FloatPoint& location, const FloatSize& size)
       : location_(location), size_(size) {}
   FloatRect(float x, float y, float width, float height)
diff --git a/third_party/WebKit/Source/platform/geometry/FloatRoundedRect.h b/third_party/WebKit/Source/platform/geometry/FloatRoundedRect.h
index 47dfbbc..cb967950 100644
--- a/third_party/WebKit/Source/platform/geometry/FloatRoundedRect.h
+++ b/third_party/WebKit/Source/platform/geometry/FloatRoundedRect.h
@@ -48,7 +48,7 @@
     DISALLOW_NEW();
 
    public:
-    Radii() {}
+    Radii() = default;
     Radii(const FloatSize& top_left,
           const FloatSize& top_right,
           const FloatSize& bottom_left,
@@ -106,7 +106,7 @@
     FloatSize bottom_right_;
   };
 
-  FloatRoundedRect() {}
+  FloatRoundedRect() = default;
   explicit FloatRoundedRect(const FloatRect&, const Radii& = Radii());
   FloatRoundedRect(float x, float y, float width, float height);
   FloatRoundedRect(const FloatRect&,
diff --git a/third_party/WebKit/Source/platform/geometry/IntRect.h b/third_party/WebKit/Source/platform/geometry/IntRect.h
index eb6671e..70b2f34 100644
--- a/third_party/WebKit/Source/platform/geometry/IntRect.h
+++ b/third_party/WebKit/Source/platform/geometry/IntRect.h
@@ -57,7 +57,7 @@
   USING_FAST_MALLOC(IntRect);
 
  public:
-  IntRect() {}
+  IntRect() = default;
   IntRect(const IntPoint& location, const IntSize& size)
       : location_(location), size_(size) {}
   IntRect(int x, int y, int width, int height)
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutPoint.h b/third_party/WebKit/Source/platform/geometry/LayoutPoint.h
index cddb6744..f492067 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutPoint.h
+++ b/third_party/WebKit/Source/platform/geometry/LayoutPoint.h
@@ -44,7 +44,7 @@
   DISALLOW_NEW();
 
  public:
-  LayoutPoint() {}
+  LayoutPoint() = default;
   LayoutPoint(LayoutUnit x, LayoutUnit y) : x_(x), y_(y) {}
   LayoutPoint(int x, int y) : x_(LayoutUnit(x)), y_(LayoutUnit(y)) {}
   LayoutPoint(const IntPoint& point) : x_(point.X()), y_(point.Y()) {}
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRect.h b/third_party/WebKit/Source/platform/geometry/LayoutRect.h
index 0290b55..83c7d040 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutRect.h
+++ b/third_party/WebKit/Source/platform/geometry/LayoutRect.h
@@ -48,7 +48,7 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  LayoutRect() {}
+  LayoutRect() = default;
   LayoutRect(const LayoutPoint& location, const LayoutSize& size)
       : location_(location), size_(size) {}
   LayoutRect(LayoutUnit x, LayoutUnit y, LayoutUnit width, LayoutUnit height)
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h
index 0407f03..aedafc5 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h
+++ b/third_party/WebKit/Source/platform/geometry/LayoutRectOutsets.h
@@ -49,7 +49,7 @@
   DISALLOW_NEW();
 
  public:
-  LayoutRectOutsets() {}
+  LayoutRectOutsets() = default;
   LayoutRectOutsets(LayoutUnit top,
                     LayoutUnit right,
                     LayoutUnit bottom,
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutSize.h b/third_party/WebKit/Source/platform/geometry/LayoutSize.h
index 9061bc28..01cba32e 100644
--- a/third_party/WebKit/Source/platform/geometry/LayoutSize.h
+++ b/third_party/WebKit/Source/platform/geometry/LayoutSize.h
@@ -48,7 +48,7 @@
   DISALLOW_NEW();
 
  public:
-  LayoutSize() {}
+  LayoutSize() = default;
   explicit LayoutSize(const IntSize& size)
       : width_(size.Width()), height_(size.Height()) {}
   LayoutSize(LayoutUnit width, LayoutUnit height)
diff --git a/third_party/WebKit/Source/platform/geometry/Region.cpp b/third_party/WebKit/Source/platform/geometry/Region.cpp
index bfaede7..a35404e 100644
--- a/third_party/WebKit/Source/platform/geometry/Region.cpp
+++ b/third_party/WebKit/Source/platform/geometry/Region.cpp
@@ -35,7 +35,7 @@
 
 namespace blink {
 
-Region::Region() {}
+Region::Region() = default;
 
 Region::Region(const IntRect& rect) : bounds_(rect), shape_(rect) {}
 
@@ -222,7 +222,7 @@
   }
 };
 
-Region::Shape::Shape() {}
+Region::Shape::Shape() = default;
 
 Region::Shape::Shape(const IntRect& rect) {
   AppendSpan(rect.Y());
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index ada3c6199..405880b 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -152,7 +152,7 @@
    public:
     virtual void ReportHibernationEvent(HibernationEvent);
     virtual void DidStartHibernating() {}
-    virtual ~Logger() {}
+    virtual ~Logger() = default;
   };
 
   void SetLoggerForTesting(std::unique_ptr<Logger>);
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index 44161b8a..c5e4b783 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -75,7 +75,7 @@
 
 class Canvas2DLayerBridgePtr {
  public:
-  Canvas2DLayerBridgePtr() {}
+  Canvas2DLayerBridgePtr() = default;
   Canvas2DLayerBridgePtr(std::unique_ptr<Canvas2DLayerBridge> layer_bridge)
       : layer_bridge_(std::move(layer_bridge)) {}
 
@@ -414,7 +414,7 @@
   MOCK_METHOD1(ReportHibernationEvent,
                void(Canvas2DLayerBridge::HibernationEvent));
   MOCK_METHOD0(DidStartHibernating, void());
-  virtual ~MockLogger() {}
+  virtual ~MockLogger() = default;
 };
 
 class MockImageBuffer : public ImageBuffer {
@@ -425,7 +425,7 @@
 
   MOCK_CONST_METHOD1(ResetCanvas, void(PaintCanvas*));
 
-  virtual ~MockImageBuffer() {}
+  virtual ~MockImageBuffer() = default;
 };
 
 class MockCanvasResourceHost : public CanvasResourceHost {
diff --git a/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h b/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h
index 911e45dd5..ca7393a 100644
--- a/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h
+++ b/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h
@@ -12,7 +12,7 @@
 
 class PLATFORM_EXPORT CanvasResourceHost {
  public:
-  virtual ~CanvasResourceHost() {}
+  virtual ~CanvasResourceHost() = default;
   virtual void NotifySurfaceInvalid() = 0;
   virtual void SetNeedsCompositingUpdate() = 0;
   virtual void RestoreCanvasMatrixClipStack(PaintCanvas*) const = 0;
diff --git a/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp b/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp
index 023235fd..35168ca 100644
--- a/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp
@@ -40,7 +40,7 @@
                                std::move(context_provider_wrapper)),
         msaa_sample_count_(msaa_sample_count) {}
 
-  virtual ~CanvasResourceProvider_Texture() {}
+  virtual ~CanvasResourceProvider_Texture() = default;
 
   bool IsValid() const final { return GetSkSurface() && !IsGpuContextLost(); }
   bool IsAccelerated() const final { return true; }
@@ -117,7 +117,7 @@
                                        color_params,
                                        std::move(context_provider_wrapper)) {}
 
-  virtual ~CanvasResourceProvider_Texture_GpuMemoryBuffer() {}
+  virtual ~CanvasResourceProvider_Texture_GpuMemoryBuffer() = default;
 
  protected:
   scoped_refptr<CanvasResource> CreateResource() final {
@@ -169,7 +169,7 @@
                                color_params,
                                nullptr /*context_provider_wrapper*/) {}
 
-  ~CanvasResourceProvider_Bitmap() {}
+  ~CanvasResourceProvider_Bitmap() = default;
 
   bool IsValid() const final { return GetSkSurface(); }
   bool IsAccelerated() const final { return false; }
@@ -293,7 +293,7 @@
       size_(size),
       color_params_(color_params) {}
 
-CanvasResourceProvider::~CanvasResourceProvider() {}
+CanvasResourceProvider::~CanvasResourceProvider() = default;
 
 SkSurface* CanvasResourceProvider::GetSkSurface() const {
   if (!surface_) {
diff --git a/third_party/WebKit/Source/platform/graphics/CompositorMutator.h b/third_party/WebKit/Source/platform/graphics/CompositorMutator.h
index 30e853e..c0ed4705 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositorMutator.h
+++ b/third_party/WebKit/Source/platform/graphics/CompositorMutator.h
@@ -14,7 +14,7 @@
 class PLATFORM_EXPORT CompositorMutator
     : public GarbageCollectedFinalized<CompositorMutator> {
  public:
-  virtual ~CompositorMutator() {}
+  virtual ~CompositorMutator() = default;
 
   virtual void Trace(blink::Visitor* visitor) {}
 
diff --git a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
index c933275..385aed9b 100644
--- a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
@@ -71,7 +71,7 @@
   Swap(source);
 }
 
-ContiguousContainerBase::~ContiguousContainerBase() {}
+ContiguousContainerBase::~ContiguousContainerBase() = default;
 
 ContiguousContainerBase& ContiguousContainerBase::operator=(
     ContiguousContainerBase&& source) {
diff --git a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.h b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.h
index 3836f5b..7203185 100644
--- a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.h
+++ b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.h
@@ -95,7 +95,7 @@
     DISALLOW_NEW();
 
    public:
-    IteratorWrapper() {}
+    IteratorWrapper() = default;
     bool operator==(const IteratorWrapper& other) const {
       return it_ == other.it_;
     }
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
index f9820dd..3556b83c 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
@@ -96,7 +96,7 @@
       can_yuv_decode_(false),
       complete_frame_content_id_(complete_frame_content_id) {}
 
-DecodingImageGenerator::~DecodingImageGenerator() {}
+DecodingImageGenerator::~DecodingImageGenerator() = default;
 
 sk_sp<SkData> DecodingImageGenerator::GetEncodedData() const {
   TRACE_EVENT0("blink", "DecodingImageGenerator::refEncodedData");
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
index 280b2e8..20c02d85 100644
--- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
@@ -86,7 +86,7 @@
       has_hot_spot_(false),
       complete_frame_content_id_(PaintImage::GetNextContentId()) {}
 
-DeferredImageDecoder::~DeferredImageDecoder() {}
+DeferredImageDecoder::~DeferredImageDecoder() = default;
 
 String DeferredImageDecoder::FilenameExtension() const {
   return metadata_decoder_ ? metadata_decoder_->FilenameExtension()
diff --git a/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp b/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp
index bbc33b1..76c98e8 100644
--- a/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp
@@ -44,9 +44,9 @@
 
 namespace blink {
 
-DrawLooperBuilder::DrawLooperBuilder() {}
+DrawLooperBuilder::DrawLooperBuilder() = default;
 
-DrawLooperBuilder::~DrawLooperBuilder() {}
+DrawLooperBuilder::~DrawLooperBuilder() = default;
 
 sk_sp<SkDrawLooper> DrawLooperBuilder::DetachDrawLooper() {
   return sk_draw_looper_builder_.detach();
diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.cpp b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
index 6322898..8aad93e 100644
--- a/third_party/WebKit/Source/platform/graphics/Gradient.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
@@ -48,7 +48,7 @@
       color_interpolation_(interpolation),
       stops_sorted_(true) {}
 
-Gradient::~Gradient() {}
+Gradient::~Gradient() = default;
 
 static inline bool CompareStops(const Gradient::ColorStop& a,
                                 const Gradient::ColorStop& b) {
diff --git a/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h b/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h
index 18e92fc..1e1e9eb 100644
--- a/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h
+++ b/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h
@@ -41,7 +41,7 @@
         new GradientGeneratedImage(std::move(generator), size));
   }
 
-  ~GradientGeneratedImage() override {}
+  ~GradientGeneratedImage() override = default;
 
   bool ApplyShader(PaintFlags&, const SkMatrix&) override;
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h b/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h
index ebbd5a3..fd18a2e 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContextState.h
@@ -116,7 +116,7 @@
  private:
   GraphicsContextState();
   explicit GraphicsContextState(const GraphicsContextState&);
-  GraphicsContextState& operator=(const GraphicsContextState&);
+  GraphicsContextState& operator=(const GraphicsContextState&) = delete;
 
   // This is mutable to enable dash path effect updates when the paint is
   // fetched for use.
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h
index d3477de..36a8f73 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerClient.h
@@ -72,7 +72,7 @@
 
 class PLATFORM_EXPORT GraphicsLayerClient {
  public:
-  virtual ~GraphicsLayerClient() {}
+  virtual ~GraphicsLayerClient() = default;
 
   virtual void InvalidateTargetElementForTesting() {}
 
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
index be55c45..ab54cc60 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
@@ -30,7 +30,7 @@
       owner_node_id_(0),
       main_thread_scrolling_reasons_(0) {}
 
-GraphicsLayerDebugInfo::~GraphicsLayerDebugInfo() {}
+GraphicsLayerDebugInfo::~GraphicsLayerDebugInfo() = default;
 
 std::unique_ptr<base::trace_event::TracedValue>
 GraphicsLayerDebugInfo::AsTracedValue() const {
diff --git a/third_party/WebKit/Source/platform/graphics/Image.cpp b/third_party/WebKit/Source/platform/graphics/Image.cpp
index 7546fbc..72bb1e4 100644
--- a/third_party/WebKit/Source/platform/graphics/Image.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Image.cpp
@@ -83,7 +83,7 @@
       high_contrast_classification_(
           HighContrastClassification::kNotClassified) {}
 
-Image::~Image() {}
+Image::~Image() = default;
 
 Image* Image::NullImage() {
   DCHECK(IsMainThread());
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp
index 41b6cd7..121e4d6 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.cpp
@@ -42,7 +42,7 @@
     : size_(size), color_params_(color_params) {
 }
 
-ImageBufferSurface::~ImageBufferSurface() {}
+ImageBufferSurface::~ImageBufferSurface() = default;
 
 void ImageBufferSurface::Clear() {
   // Clear the background transparent or opaque, as required. It would be nice
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
index bb4dfa4b..fd4e5b2 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
@@ -52,8 +52,8 @@
   WTF_MAKE_NONCOPYABLE(ImageDecoderFactory);
 
  public:
-  ImageDecoderFactory() {}
-  virtual ~ImageDecoderFactory() {}
+  ImageDecoderFactory() = default;
+  virtual ~ImageDecoderFactory() = default;
   virtual std::unique_ptr<ImageDecoder> Create() = 0;
 };
 
diff --git a/third_party/WebKit/Source/platform/graphics/ImageObserver.cpp b/third_party/WebKit/Source/platform/graphics/ImageObserver.cpp
index 0230629..65037a36 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageObserver.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageObserver.cpp
@@ -31,6 +31,6 @@
 
 namespace blink {
 
-ImageObserver::~ImageObserver() {}
+ImageObserver::~ImageObserver() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/LinkHighlight.h b/third_party/WebKit/Source/platform/graphics/LinkHighlight.h
index 77231d9..d9b6f61f 100644
--- a/third_party/WebKit/Source/platform/graphics/LinkHighlight.h
+++ b/third_party/WebKit/Source/platform/graphics/LinkHighlight.h
@@ -18,7 +18,7 @@
   virtual WebLayer* Layer() = 0;
 
  protected:
-  virtual ~LinkHighlight() {}
+  virtual ~LinkHighlight() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h b/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h
index 671bce97..fc71ef5 100644
--- a/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h
+++ b/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h
@@ -120,9 +120,9 @@
 };
 
 #ifndef NDEBUG
-std::unique_ptr<JSONArray> RecordAsJSON(const PaintRecord&);
-String RecordAsDebugString(const PaintRecord&);
-void ShowPaintRecord(const PaintRecord&);
+PLATFORM_EXPORT std::unique_ptr<JSONArray> RecordAsJSON(const PaintRecord&);
+PLATFORM_EXPORT String RecordAsDebugString(const PaintRecord&);
+PLATFORM_EXPORT void ShowPaintRecord(const PaintRecord&);
 #endif
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcher.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcher.h
index a612781..d308716 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcher.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcher.h
@@ -22,7 +22,7 @@
 
 class PLATFORM_EXPORT OffscreenCanvasFrameDispatcher {
  public:
-  virtual ~OffscreenCanvasFrameDispatcher() {}
+  virtual ~OffscreenCanvasFrameDispatcher() = default;
   virtual void DispatchFrame(scoped_refptr<StaticBitmapImage>,
                              double commit_start_time,
                              const SkIRect& damage_rect) = 0;
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index b542af4..d8dc12d 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -64,8 +64,8 @@
       std::make_unique<OffscreenCanvasResourceProvider>(width, height);
 }
 
-OffscreenCanvasFrameDispatcherImpl::~OffscreenCanvasFrameDispatcherImpl() {
-}
+OffscreenCanvasFrameDispatcherImpl::~OffscreenCanvasFrameDispatcherImpl() =
+    default;
 
 namespace {
 
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.cpp
index aec9057..62fc5ce 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.cpp
@@ -25,7 +25,7 @@
                                                                  int height)
     : width_(width), height_(height), next_resource_id_(0u) {}
 
-OffscreenCanvasResourceProvider::~OffscreenCanvasResourceProvider() {}
+OffscreenCanvasResourceProvider::~OffscreenCanvasResourceProvider() = default;
 
 std::unique_ptr<OffscreenCanvasResourceProvider::FrameResource>
 OffscreenCanvasResourceProvider::CreateOrRecycleFrameResource() {
@@ -105,7 +105,7 @@
   resources_.insert(next_resource_id_, std::move(frame_resource));
 }
 
-OffscreenCanvasResourceProvider::FrameResource::~FrameResource() {}
+OffscreenCanvasResourceProvider::FrameResource::~FrameResource() = default;
 
 void OffscreenCanvasResourceProvider::ReclaimResources(
     const WTF::Vector<viz::ReturnedResource>& resources) {
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.h
index 814f804..f756cc1 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasResourceProvider.h
@@ -47,7 +47,7 @@
     bool spare_lock_ = true;
     gpu::Mailbox mailbox_;
 
-    FrameResource() {}
+    FrameResource() = default;
     ~FrameResource();
   };
 
diff --git a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h
index c4ac09d5..71f8d73 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h
+++ b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h
@@ -18,7 +18,7 @@
                                                    const FloatSize& size) {
     return base::AdoptRef(new PaintGeneratedImage(std::move(record), size));
   }
-  ~PaintGeneratedImage() override {}
+  ~PaintGeneratedImage() override = default;
 
  protected:
   void Draw(PaintCanvas*,
diff --git a/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp b/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp
index a8d4d97..7c9d933c 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp
@@ -31,7 +31,7 @@
   // FIXME: we don't have a good way to account for DL memory utilization.
 }
 
-PaintRecordPattern::~PaintRecordPattern() {}
+PaintRecordPattern::~PaintRecordPattern() = default;
 
 sk_sp<PaintShader> PaintRecordPattern::CreateShader(
     const SkMatrix& local_matrix) {
diff --git a/third_party/WebKit/Source/platform/graphics/Path.cpp b/third_party/WebKit/Source/platform/graphics/Path.cpp
index 1366313..ebc0ca1 100644
--- a/third_party/WebKit/Source/platform/graphics/Path.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Path.cpp
@@ -50,7 +50,7 @@
   path_ = other;
 }
 
-Path::~Path() {}
+Path::~Path() = default;
 
 Path& Path::operator=(const Path& other) {
   path_ = SkPath(other.path_);
diff --git a/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp b/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp
index 52b921c..ffc54bbf 100644
--- a/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PathTraversalState.cpp
@@ -38,7 +38,7 @@
 
 struct QuadraticBezier {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-  QuadraticBezier() {}
+  QuadraticBezier() = default;
   QuadraticBezier(const FloatPoint& s, const FloatPoint& c, const FloatPoint& e)
       : start(s), control(c), end(e), split_depth(0) {}
 
@@ -75,7 +75,7 @@
 
 struct CubicBezier {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-  CubicBezier() {}
+  CubicBezier() = default;
   CubicBezier(const FloatPoint& s,
               const FloatPoint& c1,
               const FloatPoint& c2,
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.cpp b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
index 8f08322d..978aaa6 100644
--- a/third_party/WebKit/Source/platform/graphics/Pattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
@@ -53,8 +53,7 @@
 
 Pattern::Pattern(RepeatMode repeat_mode) : repeat_mode_(repeat_mode) {}
 
-Pattern::~Pattern() {
-}
+Pattern::~Pattern() = default;
 
 void Pattern::ApplyToFlags(PaintFlags& flags, const SkMatrix& local_matrix) {
   if (!cached_shader_ || IsLocalMatrixChanged(local_matrix))
diff --git a/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp b/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp
index 5b653a64a..8018a13dc 100644
--- a/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp
@@ -24,7 +24,7 @@
 PlaceholderImage::PlaceholderImage(ImageObserver* observer, const IntSize& size)
     : Image(observer), size_(size) {}
 
-PlaceholderImage::~PlaceholderImage() {}
+PlaceholderImage::~PlaceholderImage() = default;
 
 PaintImage PlaceholderImage::PaintImageForCurrentFrame() {
   auto builder = CreatePaintImageBuilder().set_completion_state(
diff --git a/third_party/WebKit/Source/platform/graphics/TextureHolder.h b/third_party/WebKit/Source/platform/graphics/TextureHolder.h
index 2c59031..19be985 100644
--- a/third_party/WebKit/Source/platform/graphics/TextureHolder.h
+++ b/third_party/WebKit/Source/platform/graphics/TextureHolder.h
@@ -20,7 +20,7 @@
 
 class PLATFORM_EXPORT TextureHolder {
  public:
-  virtual ~TextureHolder() {}
+  virtual ~TextureHolder() = default;
 
   // Methods overridden by all sub-classes
   virtual bool IsSkiaTextureHolder() = 0;
diff --git a/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp
index cd7558e..8015dca 100644
--- a/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/UnacceleratedImageBufferSurface.cpp
@@ -61,7 +61,7 @@
     Clear();
 }
 
-UnacceleratedImageBufferSurface::~UnacceleratedImageBufferSurface() {}
+UnacceleratedImageBufferSurface::~UnacceleratedImageBufferSurface() = default;
 
 PaintCanvas* UnacceleratedImageBufferSurface::Canvas() {
   return canvas_.get();
diff --git a/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp
index 23819b1..8dbe0127 100644
--- a/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp
@@ -36,7 +36,7 @@
   DCHECK(paint_image_);
 }
 
-UnacceleratedStaticBitmapImage::~UnacceleratedStaticBitmapImage() {}
+UnacceleratedStaticBitmapImage::~UnacceleratedStaticBitmapImage() = default;
 
 IntSize UnacceleratedStaticBitmapImage::Size() const {
   return IntSize(paint_image_.width(), paint_image_.height());
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp
index 6016c329..c597f499 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitter.cpp
@@ -28,7 +28,7 @@
   DETACH_FROM_THREAD(media_thread_checker_);
 }
 
-VideoFrameSubmitter::~VideoFrameSubmitter() {}
+VideoFrameSubmitter::~VideoFrameSubmitter() = default;
 
 void VideoFrameSubmitter::StopUsingProvider() {
   DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp
index 6da889d..977545e 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp
@@ -34,8 +34,8 @@
 
 class MockVideoFrameProvider : public cc::VideoFrameProvider {
  public:
-  MockVideoFrameProvider() {}
-  ~MockVideoFrameProvider() {}
+  MockVideoFrameProvider() = default;
+  ~MockVideoFrameProvider() = default;
 
   MOCK_METHOD1(SetVideoFrameProviderClient, void(Client*));
   MOCK_METHOD2(UpdateCurrentFrame, bool(base::TimeTicks, base::TimeTicks));
@@ -52,7 +52,7 @@
   MockCompositorFrameSink(
       viz::mojom::blink::CompositorFrameSinkRequest* request)
       : binding_(this, std::move(*request)) {}
-  ~MockCompositorFrameSink() {}
+  ~MockCompositorFrameSink() = default;
 
   MOCK_METHOD1(SetNeedsBeginFrame, void(bool));
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.h b/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.h
index 163ee25..2d6987b 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.h
+++ b/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.h
@@ -31,7 +31,7 @@
         raster_invalidator_([this](const IntRect& rect) {
           cc_picture_layer_->SetNeedsDisplayRect(rect);
         }) {}
-  ~ContentLayerClientImpl() override {}
+  ~ContentLayerClientImpl() override = default;
 
   // cc::ContentLayerClient
   gfx::Rect PaintableRegion() override {
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FEBoxReflect.cpp b/third_party/WebKit/Source/platform/graphics/filters/FEBoxReflect.cpp
index e5bce9e9..c3aed17 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FEBoxReflect.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/FEBoxReflect.cpp
@@ -13,7 +13,7 @@
 FEBoxReflect::FEBoxReflect(Filter* filter, const BoxReflection& reflection)
     : FilterEffect(filter), reflection_(reflection) {}
 
-FEBoxReflect::~FEBoxReflect() {}
+FEBoxReflect::~FEBoxReflect() = default;
 
 FloatRect FEBoxReflect::MapEffect(const FloatRect& rect) const {
   return reflection_.MapRect(rect);
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp b/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp
index 7124069..4dbb360 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/FEDiffuseLighting.cpp
@@ -51,7 +51,7 @@
                                diffuse_constant, std::move(light_source));
 }
 
-FEDiffuseLighting::~FEDiffuseLighting() {}
+FEDiffuseLighting::~FEDiffuseLighting() = default;
 
 Color FEDiffuseLighting::LightingColor() const {
   return lighting_color_;
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp b/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp
index 2ae2a1ef..d453cad 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/FESpecularLighting.cpp
@@ -56,7 +56,7 @@
                                 std::move(light_source));
 }
 
-FESpecularLighting::~FESpecularLighting() {}
+FESpecularLighting::~FESpecularLighting() = default;
 
 Color FESpecularLighting::LightingColor() const {
   return lighting_color_;
diff --git a/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp b/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
index b166efd..42f4365 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/FilterEffect.cpp
@@ -37,7 +37,7 @@
   DCHECK(filter_);
 }
 
-FilterEffect::~FilterEffect() {}
+FilterEffect::~FilterEffect() = default;
 
 void FilterEffect::Trace(blink::Visitor* visitor) {
   visitor->Trace(input_effects_);
diff --git a/third_party/WebKit/Source/platform/graphics/filters/LightSource.cpp b/third_party/WebKit/Source/platform/graphics/filters/LightSource.cpp
index ac8a308..c0a40240 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/LightSource.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/LightSource.cpp
@@ -31,6 +31,6 @@
 
 namespace blink {
 
-LightSource::~LightSource() {}
+LightSource::~LightSource() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/filters/PaintFilterEffect.cpp b/third_party/WebKit/Source/platform/graphics/filters/PaintFilterEffect.cpp
index f31ee01..c57e2ef8 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/PaintFilterEffect.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/PaintFilterEffect.cpp
@@ -15,7 +15,7 @@
   SetOperatingInterpolationSpace(kInterpolationSpaceSRGB);
 }
 
-PaintFilterEffect::~PaintFilterEffect() {}
+PaintFilterEffect::~PaintFilterEffect() = default;
 
 PaintFilterEffect* PaintFilterEffect::Create(Filter* filter,
                                              const PaintFlags& flags) {
diff --git a/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp b/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp
index 4e62406f..0c056ad0 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/SourceGraphic.cpp
@@ -29,7 +29,7 @@
   SetOperatingInterpolationSpace(kInterpolationSpaceSRGB);
 }
 
-SourceGraphic::~SourceGraphic() {}
+SourceGraphic::~SourceGraphic() = default;
 
 SourceGraphic* SourceGraphic::Create(Filter* filter) {
   return new SourceGraphic(filter);
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h
index e01fbc6..2ef005f 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/AcceleratedImageBufferSurface.h
@@ -52,7 +52,7 @@
  public:
   AcceleratedImageBufferSurface(const IntSize&,
                                 const CanvasColorParams& = CanvasColorParams());
-  ~AcceleratedImageBufferSurface() override {}
+  ~AcceleratedImageBufferSurface() override = default;
 
   PaintCanvas* Canvas() override { return canvas_.get(); }
   bool IsValid() const override;
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp b/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp
index 54ba072..314c23f 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/Extensions3DUtil.cpp
@@ -34,7 +34,7 @@
 Extensions3DUtil::Extensions3DUtil(gpu::gles2::GLES2Interface* gl)
     : gl_(gl), is_valid_(true) {}
 
-Extensions3DUtil::~Extensions3DUtil() {}
+Extensions3DUtil::~Extensions3DUtil() = default;
 
 void Extensions3DUtil::InitializeExtensions() {
   if (gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/CullRect.h b/third_party/WebKit/Source/platform/graphics/paint/CullRect.h
index 2a17155..1e16046 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/CullRect.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/CullRect.h
@@ -22,7 +22,7 @@
   DISALLOW_NEW();
 
  public:
-  CullRect() {}
+  CullRect() = default;
   explicit CullRect(const IntRect& rect) : rect_(rect) {}
   CullRect(const CullRect&, const IntPoint& offset);
   CullRect(const CullRect&, const IntSize& offset);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
index c227249..5e01b4308 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
@@ -7,7 +7,7 @@
 namespace blink {
 
 struct SameSizeAsDisplayItem {
-  virtual ~SameSizeAsDisplayItem() {}  // Allocate vtable pointer.
+  virtual ~SameSizeAsDisplayItem() = default;  // Allocate vtable pointer.
   void* pointer;
   LayoutRect rect;
   LayoutUnit outset;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
index 739607e..13fe365 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -201,7 +201,7 @@
     SECURITY_DCHECK(derived_size >= sizeof(*this));
   }
 
-  virtual ~DisplayItem() {}
+  virtual ~DisplayItem() = default;
 
   // Ids are for matching new DisplayItems with existing DisplayItems.
   struct Id {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ForeignLayerDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ForeignLayerDisplayItem.cpp
index f7bd2b31..b1765588 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ForeignLayerDisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ForeignLayerDisplayItem.cpp
@@ -28,7 +28,7 @@
   DCHECK(layer_);
 }
 
-ForeignLayerDisplayItem::~ForeignLayerDisplayItem() {}
+ForeignLayerDisplayItem::~ForeignLayerDisplayItem() = default;
 
 void ForeignLayerDisplayItem::Replay(GraphicsContext&) const {
   NOTREACHED();
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
index 2e94a164..7ea52116 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
@@ -60,7 +60,7 @@
     : display_item_list_(std::move(source.display_item_list_)),
       paint_chunks_(std::move(source.paint_chunks_)) {}
 
-PaintArtifact::~PaintArtifact() {}
+PaintArtifact::~PaintArtifact() = default;
 
 PaintArtifact& PaintArtifact::operator=(PaintArtifact&& source) {
   display_item_list_ = std::move(source.display_item_list_);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp
index 599386e..da01bb7 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp
@@ -10,7 +10,7 @@
 
 PaintChunker::PaintChunker() : force_new_chunk_(false) {}
 
-PaintChunker::~PaintChunker() {}
+PaintChunker::~PaintChunker() = default;
 
 void PaintChunker::UpdateCurrentPaintChunkProperties(
     const Optional<PaintChunk::Id>& chunk_id,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollHitTestDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollHitTestDisplayItem.cpp
index fc22287..8b04433 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollHitTestDisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollHitTestDisplayItem.cpp
@@ -22,7 +22,7 @@
   DCHECK(scroll_offset_node_->ScrollNode());
 }
 
-ScrollHitTestDisplayItem::~ScrollHitTestDisplayItem() {}
+ScrollHitTestDisplayItem::~ScrollHitTestDisplayItem() = default;
 
 void ScrollHitTestDisplayItem::Replay(GraphicsContext&) const {
   NOTREACHED();
diff --git a/third_party/WebKit/Source/platform/graphics/test/StubImage.h b/third_party/WebKit/Source/platform/graphics/test/StubImage.h
index b16421f7..62536b0 100644
--- a/third_party/WebKit/Source/platform/graphics/test/StubImage.h
+++ b/third_party/WebKit/Source/platform/graphics/test/StubImage.h
@@ -11,7 +11,7 @@
 
 class StubImage : public Image {
  public:
-  StubImage() {}
+  StubImage() = default;
 
   bool CurrentFrameKnownToBeOpaque(MetadataMode) override { return false; }
   IntSize Size() const override { return IntSize(10, 10); }
diff --git a/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp b/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp
index d4077870..a10c77fe 100644
--- a/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp
+++ b/third_party/WebKit/Source/platform/heap/BlinkGCMemoryDumpProvider.cpp
@@ -50,7 +50,7 @@
   return &instance;
 }
 
-BlinkGCMemoryDumpProvider::~BlinkGCMemoryDumpProvider() {}
+BlinkGCMemoryDumpProvider::~BlinkGCMemoryDumpProvider() = default;
 
 bool BlinkGCMemoryDumpProvider::OnMemoryDump(
     const base::trace_event::MemoryDumpArgs& args,
diff --git a/third_party/WebKit/Source/platform/heap/CallbackStack.h b/third_party/WebKit/Source/platform/heap/CallbackStack.h
index e857595..94c0eab 100644
--- a/third_party/WebKit/Source/platform/heap/CallbackStack.h
+++ b/third_party/WebKit/Source/platform/heap/CallbackStack.h
@@ -27,7 +27,7 @@
     DISALLOW_NEW();
 
    public:
-    Item() {}
+    Item() = default;
     Item(void* object, VisitorCallback callback)
         : object_(object), callback_(callback) {}
     void* Object() { return object_; }
diff --git a/third_party/WebKit/Source/platform/heap/HeapCompact.cpp b/third_party/WebKit/Source/platform/heap/HeapCompact.cpp
index 936a528c..3104c5f 100644
--- a/third_party/WebKit/Source/platform/heap/HeapCompact.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapCompact.cpp
@@ -29,7 +29,7 @@
     return WTF::WrapUnique(new MovableObjectFixups);
   }
 
-  ~MovableObjectFixups() {}
+  ~MovableObjectFixups() = default;
 
   // For the arenas being compacted, record all pages belonging to them.
   // This is needed to handle 'interior slots', pointers that themselves
@@ -225,7 +225,7 @@
 #endif
 
  private:
-  MovableObjectFixups() {}
+  MovableObjectFixups() = default;
 
   // Tracking movable and updatable references. For now, we keep a
   // map which for each movable object, recording the slot that
@@ -275,7 +275,7 @@
       "unexpected ArenaIndices ordering");
 }
 
-HeapCompact::~HeapCompact() {}
+HeapCompact::~HeapCompact() = default;
 
 HeapCompact::MovableObjectFixups& HeapCompact::Fixups() {
   if (!fixups_)
diff --git a/third_party/WebKit/Source/platform/heap/HeapCompactTest.cpp b/third_party/WebKit/Source/platform/heap/HeapCompactTest.cpp
index e9d7649..108df986 100644
--- a/third_party/WebKit/Source/platform/heap/HeapCompactTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapCompactTest.cpp
@@ -29,7 +29,7 @@
     return new IntWrapper(x, verify);
   }
 
-  virtual ~IntWrapper() {}
+  virtual ~IntWrapper() = default;
 
   void Trace(blink::Visitor* visitor) {
     // Verify if compaction is indeed activated.
@@ -61,7 +61,7 @@
   IntWrapper(int x, VerifyArenaCompaction verify) : x_(x), verify_(verify) {}
 
  private:
-  IntWrapper();
+  IntWrapper() = delete;
 
   int x_;
   VerifyArenaCompaction verify_;
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h
index 8256d80c..952d1664 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.h
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -372,7 +372,7 @@
 
  public:
   BasePage(PageMemory*, BaseArena*);
-  virtual ~BasePage() {}
+  virtual ~BasePage() = default;
 
   void Link(BasePage** previous_next) {
     next_ = *previous_next;
diff --git a/third_party/WebKit/Source/platform/heap/HeapTerminatedArray.h b/third_party/WebKit/Source/platform/heap/HeapTerminatedArray.h
index 03b4e17b..93ca458 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTerminatedArray.h
+++ b/third_party/WebKit/Source/platform/heap/HeapTerminatedArray.h
@@ -54,7 +54,7 @@
 
   // Prohibit construction. Allocator makes HeapTerminatedArray instances for
   // HeapTerminatedArrayBuilder by pointer casting.
-  HeapTerminatedArray();
+  HeapTerminatedArray() = delete;
 
   template <typename U, template <typename> class>
   friend class WTF::TerminatedArrayBuilder;
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index 9b870d5..b5eb1218 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -76,7 +76,7 @@
   IntWrapper(int x) : x_(x) {}
 
  private:
-  IntWrapper();
+  IntWrapper() = delete;
   int x_;
 };
 static_assert(WTF::IsTraceable<IntWrapper>::value,
@@ -364,7 +364,7 @@
   virtual void VirtualMethod() {}
 
  protected:
-  SimpleObject() {}
+  SimpleObject() = default;
   char payload[64];
 };
 
@@ -379,7 +379,7 @@
   void Trace(blink::Visitor* visitor) {}
 
  protected:
-  HeapTestSuperClass() {}
+  HeapTestSuperClass() = default;
 };
 
 int HeapTestSuperClass::destructor_calls_ = 0;
@@ -450,7 +450,7 @@
   OffHeapInt(int x) : x_(x) {}
 
  private:
-  OffHeapInt();
+  OffHeapInt() = delete;
   int x_;
 };
 
@@ -483,7 +483,7 @@
 
   ThreadedTesterBase() : gc_count_(0), threads_to_finish_(kNumberOfThreads) {}
 
-  virtual ~ThreadedTesterBase() {}
+  virtual ~ThreadedTesterBase() = default;
 
   inline bool Done() const {
     return gc_count_ >= kNumberOfThreads * kGcPerThread;
@@ -631,7 +631,7 @@
  protected:
   class Local final : public GarbageCollected<Local> {
    public:
-    Local() {}
+    Local() = default;
 
     void Trace(blink::Visitor* visitor) {}
   };
@@ -748,7 +748,7 @@
   void Trace(blink::Visitor* visitor) {}
 
  private:
-  SimpleFinalizedObject() {}
+  SimpleFinalizedObject() = default;
 };
 
 int SimpleFinalizedObject::destructor_calls_ = 0;
@@ -1449,7 +1449,7 @@
   void Trace(blink::Visitor* visitor) {}
 
  private:
-  DynamicallySizedObject() {}
+  DynamicallySizedObject() = default;
 };
 
 class FinalizationAllocator
@@ -1960,13 +1960,13 @@
 class SimpleFinalizedEagerObjectBase
     : public GarbageCollectedFinalized<SimpleFinalizedEagerObjectBase> {
  public:
-  virtual ~SimpleFinalizedEagerObjectBase() {}
+  virtual ~SimpleFinalizedEagerObjectBase() = default;
   void Trace(blink::Visitor* visitor) {}
 
   EAGERLY_FINALIZE();
 
  protected:
-  SimpleFinalizedEagerObjectBase() {}
+  SimpleFinalizedEagerObjectBase() = default;
 };
 
 class SimpleFinalizedEagerObject : public SimpleFinalizedEagerObjectBase {
@@ -1980,7 +1980,7 @@
   static int destructor_calls_;
 
  private:
-  SimpleFinalizedEagerObject() {}
+  SimpleFinalizedEagerObject() = default;
 };
 
 template <typename T>
@@ -2003,7 +2003,7 @@
   static int destructor_calls_;
 
  private:
-  SimpleFinalizedObjectInstanceOfTemplate() {}
+  SimpleFinalizedObjectInstanceOfTemplate() = default;
 };
 
 int SimpleFinalizedEagerObject::destructor_calls_ = 0;
@@ -3075,7 +3075,7 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  NonTrivialObject() {}
+  NonTrivialObject() = default;
   explicit NonTrivialObject(int num) {
     deque_.push_back(IntWrapper::Create(num));
     vector_.push_back(IntWrapper::Create(num));
@@ -4290,7 +4290,7 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  InlinedVectorObject() {}
+  InlinedVectorObject() = default;
   ~InlinedVectorObject() { destructor_calls_++; }
   void Trace(blink::Visitor* visitor) {}
 
@@ -4303,7 +4303,7 @@
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
  public:
-  InlinedVectorObjectWithVtable() {}
+  InlinedVectorObjectWithVtable() = default;
   virtual ~InlinedVectorObjectWithVtable() { destructor_calls_++; }
   virtual void VirtualMethod() {}
   void Trace(blink::Visitor* visitor) {}
@@ -4611,7 +4611,7 @@
 
 class SimpleClassWithDestructor {
  public:
-  SimpleClassWithDestructor() {}
+  SimpleClassWithDestructor() = default;
   ~SimpleClassWithDestructor() { was_destructed_ = true; }
   static bool was_destructed_;
 };
@@ -4620,7 +4620,7 @@
 
 class RefCountedWithDestructor : public RefCounted<RefCountedWithDestructor> {
  public:
-  RefCountedWithDestructor() {}
+  RefCountedWithDestructor() = default;
   ~RefCountedWithDestructor() { was_destructed_ = true; }
   static bool was_destructed_;
 };
@@ -4790,7 +4790,7 @@
   USING_GARBAGE_COLLECTED_MIXIN(MixinInstanceWithoutTrace);
 
  public:
-  MixinInstanceWithoutTrace() {}
+  MixinInstanceWithoutTrace() = default;
 };
 
 TEST(HeapTest, MixinInstanceWithoutTrace) {
@@ -5761,7 +5761,7 @@
   void Trace(blink::Visitor* visitor) {}
 
  private:
-  DestructorLockingObject() {}
+  DestructorLockingObject() = default;
 };
 
 int DestructorLockingObject::destructor_calls_ = 0;
@@ -5780,10 +5780,10 @@
     TraceIfNeeded<T>::Trace(visitor, obj_);
   }
   T& Obj() { return obj_; }
-  ~TraceIfNeededTester() {}
+  ~TraceIfNeededTester() = default;
 
  private:
-  TraceIfNeededTester() {}
+  TraceIfNeededTester() = default;
   explicit TraceIfNeededTester(const T& obj) : obj_(obj) {}
   T obj_;
 };
@@ -5921,7 +5921,7 @@
     : public GarbageCollectedFinalized<AllocInSuperConstructorArgumentSuper> {
  public:
   AllocInSuperConstructorArgumentSuper(bool value) : value_(value) {}
-  virtual ~AllocInSuperConstructorArgumentSuper() {}
+  virtual ~AllocInSuperConstructorArgumentSuper() = default;
   virtual void Trace(blink::Visitor* visitor) {}
   bool Value() { return value_; }
 
@@ -6658,7 +6658,7 @@
 class EmptyMixin : public GarbageCollectedMixin {};
 class UseMixinFromLeftmostInherited : public UseMixin, public EmptyMixin {
  public:
-  ~UseMixinFromLeftmostInherited() {}
+  ~UseMixinFromLeftmostInherited() = default;
 };
 
 TEST(HeapTest, IsGarbageCollected) {
@@ -6734,7 +6734,7 @@
     : public GarbageCollectedFinalized<DoublyLinkedListNodeImpl>,
       public DoublyLinkedListNode<DoublyLinkedListNodeImpl> {
  public:
-  DoublyLinkedListNodeImpl() {}
+  DoublyLinkedListNodeImpl() = default;
   static DoublyLinkedListNodeImpl* Create() {
     return new DoublyLinkedListNodeImpl();
   }
@@ -6762,7 +6762,7 @@
   static HeapDoublyLinkedListContainer<T>* Create() {
     return new HeapDoublyLinkedListContainer<T>();
   }
-  HeapDoublyLinkedListContainer<T>() {}
+  HeapDoublyLinkedListContainer<T>() = default;
   HeapDoublyLinkedList<T> list_;
   void Trace(Visitor* visitor) { visitor->Trace(list_); }
 };
diff --git a/third_party/WebKit/Source/platform/heap/Persistent.h b/third_party/WebKit/Source/platform/heap/Persistent.h
index 18eb93dc..cf582e9a 100644
--- a/third_party/WebKit/Source/platform/heap/Persistent.h
+++ b/third_party/WebKit/Source/platform/heap/Persistent.h
@@ -704,7 +704,7 @@
 class PersistentHeapDeque
     : public PersistentHeapCollectionBase<HeapDeque<T, inlineCapacity>> {
  public:
-  PersistentHeapDeque() {}
+  PersistentHeapDeque() = default;
 
   template <size_t otherCapacity>
   PersistentHeapDeque(const HeapDeque<T, otherCapacity>& other)
diff --git a/third_party/WebKit/Source/platform/heap/SelfKeepAlive.h b/third_party/WebKit/Source/platform/heap/SelfKeepAlive.h
index d2bee35..cc32ace3 100644
--- a/third_party/WebKit/Source/platform/heap/SelfKeepAlive.h
+++ b/third_party/WebKit/Source/platform/heap/SelfKeepAlive.h
@@ -46,7 +46,7 @@
   DISALLOW_NEW();
 
  public:
-  SelfKeepAlive() {}
+  SelfKeepAlive() = default;
 
   explicit SelfKeepAlive(Self* self) { Assign(self); }
 
diff --git a/third_party/WebKit/Source/platform/heap/SparseHeapBitmap.h b/third_party/WebKit/Source/platform/heap/SparseHeapBitmap.h
index 37d87d0..599b0b9b 100644
--- a/third_party/WebKit/Source/platform/heap/SparseHeapBitmap.h
+++ b/third_party/WebKit/Source/platform/heap/SparseHeapBitmap.h
@@ -44,7 +44,7 @@
     return WTF::WrapUnique(new SparseHeapBitmap(base));
   }
 
-  ~SparseHeapBitmap() {}
+  ~SparseHeapBitmap() = default;
 
   // Return the sparse bitmap subtree that at least covers the
   // [address, address + size) range, or nullptr if none.
diff --git a/third_party/WebKit/Source/platform/heap/Visitor.cpp b/third_party/WebKit/Source/platform/heap/Visitor.cpp
index 61462f64..ce2f9cf 100644
--- a/third_party/WebKit/Source/platform/heap/Visitor.cpp
+++ b/third_party/WebKit/Source/platform/heap/Visitor.cpp
@@ -26,7 +26,7 @@
 #endif
 }
 
-Visitor::~Visitor() {}
+Visitor::~Visitor() = default;
 
 void Visitor::MarkNoTracingCallback(Visitor* visitor, void* object) {
   visitor->MarkNoTracing(object);
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
index 48489eab0..af49698 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
@@ -86,7 +86,7 @@
 
   enum AlphaOption { kAlphaPremultiplied, kAlphaNotPremultiplied };
 
-  virtual ~ImageDecoder() {}
+  virtual ~ImageDecoder() = default;
 
   // Returns a caller-owned decoder of the appropriate type.  Returns nullptr if
   // we can't sniff a supported type from the provided data (possibly
diff --git a/third_party/WebKit/Source/platform/image-decoders/SegmentReader.h b/third_party/WebKit/Source/platform/image-decoders/SegmentReader.h
index 2acf71e..1f03ac7 100644
--- a/third_party/WebKit/Source/platform/image-decoders/SegmentReader.h
+++ b/third_party/WebKit/Source/platform/image-decoders/SegmentReader.h
@@ -41,8 +41,8 @@
   static scoped_refptr<SegmentReader> CreateFromSkData(sk_sp<SkData>);
   static scoped_refptr<SegmentReader> CreateFromSkROBuffer(sk_sp<SkROBuffer>);
 
-  SegmentReader() {}
-  virtual ~SegmentReader() {}
+  SegmentReader() = default;
+  virtual ~SegmentReader() = default;
   virtual size_t size() const = 0;
   virtual size_t GetSomeData(const char*& data, size_t position) const = 0;
   virtual sk_sp<SkData> GetAsSkData() const = 0;
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
index 90193853..2a2e2fe65 100644
--- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -38,7 +38,7 @@
     : ImageDecoder(alpha_option, color_behavior, max_decoded_bytes),
       repetition_count_(kAnimationLoopOnce) {}
 
-GIFImageDecoder::~GIFImageDecoder() {}
+GIFImageDecoder::~GIFImageDecoder() = default;
 
 void GIFImageDecoder::OnSetData(SegmentReader* data) {
   if (reader_)
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h
index 4f1cf3d..036bc4c9 100644
--- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h
+++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageReader.h
@@ -199,7 +199,7 @@
         is_header_defined_(false),
         is_data_size_defined_(false) {}
 
-  ~GIFFrameContext() {}
+  ~GIFFrameContext() = default;
 
   void AddLzwBlock(size_t position, size_t size) {
     lzw_blocks_.push_back(GIFLZWBlock(position, size));
@@ -300,7 +300,7 @@
         loop_count_(kCLoopCountNotSeen),
         parse_completed_(false) {}
 
-  ~GIFImageReader() {}
+  ~GIFImageReader() = default;
 
   void SetData(scoped_refptr<blink::SegmentReader> data) {
     data_ = std::move(data);
diff --git a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
index ed2581374..2a3ceb8 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
@@ -51,7 +51,7 @@
       dir_entries_count_(0),
       color_behavior_(color_behavior) {}
 
-ICOImageDecoder::~ICOImageDecoder() {}
+ICOImageDecoder::~ICOImageDecoder() = default;
 
 void ICOImageDecoder::OnSetData(SegmentReader* data) {
   fast_reader_.SetData(data);
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index 6bade405..f2dbd24 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -753,7 +753,7 @@
                                    size_t max_decoded_bytes)
     : ImageDecoder(alpha_option, color_behavior, max_decoded_bytes) {}
 
-JPEGImageDecoder::~JPEGImageDecoder() {}
+JPEGImageDecoder::~JPEGImageDecoder() = default;
 
 bool JPEGImageDecoder::SetSize(unsigned width, unsigned height) {
   if (!ImageDecoder::SetSize(width, height))
diff --git a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
index 4e3d1df2..e57705e 100644
--- a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
@@ -56,7 +56,7 @@
       has_alpha_channel_(false),
       current_buffer_saw_alpha_(false) {}
 
-PNGImageDecoder::~PNGImageDecoder() {}
+PNGImageDecoder::~PNGImageDecoder() = default;
 
 bool PNGImageDecoder::SetFailed() {
   reader_.reset();
diff --git a/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/RendererResourceCoordinator.cpp b/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/RendererResourceCoordinator.cpp
index 3c0dc7f..bdf6ef36 100644
--- a/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/RendererResourceCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/RendererResourceCoordinator.cpp
@@ -44,7 +44,7 @@
   connector->BindInterface(service_name, &service_);
 }
 
-RendererResourceCoordinator::RendererResourceCoordinator() {}
+RendererResourceCoordinator::RendererResourceCoordinator() = default;
 
 RendererResourceCoordinator::~RendererResourceCoordinator() = default;
 
diff --git a/third_party/WebKit/Source/platform/instrumentation/tracing/MemoryCacheDumpProvider.cpp b/third_party/WebKit/Source/platform/instrumentation/tracing/MemoryCacheDumpProvider.cpp
index d75ea71..6665391 100644
--- a/third_party/WebKit/Source/platform/instrumentation/tracing/MemoryCacheDumpProvider.cpp
+++ b/third_party/WebKit/Source/platform/instrumentation/tracing/MemoryCacheDumpProvider.cpp
@@ -40,8 +40,8 @@
   return client_->OnMemoryDump(level, &dump);
 }
 
-MemoryCacheDumpProvider::MemoryCacheDumpProvider() {}
+MemoryCacheDumpProvider::MemoryCacheDumpProvider() = default;
 
-MemoryCacheDumpProvider::~MemoryCacheDumpProvider() {}
+MemoryCacheDumpProvider::~MemoryCacheDumpProvider() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/instrumentation/tracing/TracedValue.cpp b/third_party/WebKit/Source/platform/instrumentation/tracing/TracedValue.cpp
index 9476b12..6e912be 100644
--- a/third_party/WebKit/Source/platform/instrumentation/tracing/TracedValue.cpp
+++ b/third_party/WebKit/Source/platform/instrumentation/tracing/TracedValue.cpp
@@ -13,9 +13,9 @@
   return WTF::WrapUnique(new TracedValue());
 }
 
-TracedValue::TracedValue() {}
+TracedValue::TracedValue() = default;
 
-TracedValue::~TracedValue() {}
+TracedValue::~TracedValue() = default;
 
 void TracedValue::SetInteger(const char* name, int value) {
   traced_value_.SetInteger(name, value);
diff --git a/third_party/WebKit/Source/platform/instrumentation/tracing/web_memory_allocator_dump.cc b/third_party/WebKit/Source/platform/instrumentation/tracing/web_memory_allocator_dump.cc
index b1cdf169..809d4c2 100644
--- a/third_party/WebKit/Source/platform/instrumentation/tracing/web_memory_allocator_dump.cc
+++ b/third_party/WebKit/Source/platform/instrumentation/tracing/web_memory_allocator_dump.cc
@@ -14,7 +14,7 @@
     : memory_allocator_dump_(memory_allocator_dump),
       guid_(memory_allocator_dump->guid().ToUint64()) {}
 
-WebMemoryAllocatorDump::~WebMemoryAllocatorDump() {}
+WebMemoryAllocatorDump::~WebMemoryAllocatorDump() = default;
 
 void WebMemoryAllocatorDump::AddScalar(const char* name,
                                        const char* units,
diff --git a/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump.cc b/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump.cc
index 6049d65c..99adcde5 100644
--- a/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump.cc
+++ b/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump.cc
@@ -32,7 +32,7 @@
     : process_memory_dump_(process_memory_dump),
       level_of_detail_(level_of_detail) {}
 
-WebProcessMemoryDump::~WebProcessMemoryDump() {}
+WebProcessMemoryDump::~WebProcessMemoryDump() = default;
 
 blink::WebMemoryAllocatorDump* WebProcessMemoryDump::CreateMemoryAllocatorDump(
     const String& absolute_name) {
diff --git a/third_party/WebKit/Source/platform/json/JSONValues.cpp b/third_party/WebKit/Source/platform/json/JSONValues.cpp
index 96bc59d..37e3b97 100644
--- a/third_party/WebKit/Source/platform/json/JSONValues.cpp
+++ b/third_party/WebKit/Source/platform/json/JSONValues.cpp
@@ -240,7 +240,7 @@
   return JSONString::Create(string_value_);
 }
 
-JSONObject::~JSONObject() {}
+JSONObject::~JSONObject() = default;
 
 void JSONObject::SetBoolean(const String& name, bool value) {
   SetValue(name, JSONBasicValue::Create(value));
@@ -395,7 +395,7 @@
 
 JSONObject::JSONObject() : JSONValue(kTypeObject), data_(), order_() {}
 
-JSONArray::~JSONArray() {}
+JSONArray::~JSONArray() = default;
 
 void JSONArray::WriteJSON(StringBuilder* output) const {
   output->Append('[');
diff --git a/third_party/WebKit/Source/platform/json/JSONValues.h b/third_party/WebKit/Source/platform/json/JSONValues.h
index 9998ab2..509ab0d 100644
--- a/third_party/WebKit/Source/platform/json/JSONValues.h
+++ b/third_party/WebKit/Source/platform/json/JSONValues.h
@@ -62,7 +62,7 @@
  public:
   static const int kMaxDepth = 1000;
 
-  virtual ~JSONValue() {}
+  virtual ~JSONValue() = default;
 
   static std::unique_ptr<JSONValue> Null() {
     return WTF::WrapUnique(new JSONValue());
diff --git a/third_party/WebKit/Source/platform/loader/fetch/CachedMetadata.h b/third_party/WebKit/Source/platform/loader/fetch/CachedMetadata.h
index 5027915..3125f30 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/CachedMetadata.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/CachedMetadata.h
@@ -61,7 +61,7 @@
     return base::AdoptRef(new CachedMetadata(data, size));
   }
 
-  ~CachedMetadata() {}
+  ~CachedMetadata() = default;
 
   const Vector<char>& SerializedData() const { return serialized_data_; }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/CachedMetadataHandler.h b/third_party/WebKit/Source/platform/loader/fetch/CachedMetadataHandler.h
index f1162c4..7a343eed 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/CachedMetadataHandler.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/CachedMetadataHandler.h
@@ -21,7 +21,7 @@
     kSendToPlatform,  // send cache data to blink::Platform::cacheMetadata
     kCacheLocally     // cache only in Resource's member variables
   };
-  virtual ~CachedMetadataHandler() {}
+  virtual ~CachedMetadataHandler() = default;
   virtual void Trace(blink::Visitor* visitor) {}
   // Caches the given metadata in association with this resource and suggests
   // that the platform persist it. The dataTypeID is a pseudo-randomly chosen
@@ -42,7 +42,7 @@
   virtual bool IsServedFromCacheStorage() const = 0;
 
  protected:
-  CachedMetadataHandler() {}
+  CachedMetadataHandler() = default;
 };
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h
index 71a6638..d2100f2 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ClientHintsPreferences.h
@@ -27,7 +27,7 @@
     virtual void CountPersistentClientHintHeaders() = 0;
 
    protected:
-    virtual ~Context() {}
+    virtual ~Context() = default;
   };
 
   ClientHintsPreferences();
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
index a1b748d1..28c0ea3 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/FetchContext.h
@@ -88,7 +88,7 @@
 
   static FetchContext& NullInstance();
 
-  virtual ~FetchContext() {}
+  virtual ~FetchContext() = default;
 
   virtual void Trace(blink::Visitor*);
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
index 5ec729e4..db5b03a 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
@@ -66,7 +66,7 @@
       origin_restriction_(kUseDefaultOriginRestrictionForType),
       placeholder_image_request_type_(kDisallowPlaceholder) {}
 
-FetchParameters::~FetchParameters() {}
+FetchParameters::~FetchParameters() = default;
 
 void FetchParameters::SetCrossOriginAccessControl(
     const SecurityOrigin* origin,
diff --git a/third_party/WebKit/Source/platform/loader/fetch/IntegrityMetadata.h b/third_party/WebKit/Source/platform/loader/fetch/IntegrityMetadata.h
index 51e832bf..811cb63 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/IntegrityMetadata.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/IntegrityMetadata.h
@@ -21,7 +21,7 @@
 
 class PLATFORM_EXPORT IntegrityMetadata {
  public:
-  IntegrityMetadata() {}
+  IntegrityMetadata() = default;
   IntegrityMetadata(String digest, IntegrityAlgorithm);
   IntegrityMetadata(IntegrityMetadataPair);
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
index bea8f48..be4d5f2 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
@@ -370,7 +370,7 @@
 RawResourceClientStateChecker::RawResourceClientStateChecker()
     : state_(kNotAddedAsClient) {}
 
-RawResourceClientStateChecker::~RawResourceClientStateChecker() {}
+RawResourceClientStateChecker::~RawResourceClientStateChecker() = default;
 
 NEVER_INLINE void RawResourceClientStateChecker::WillAddClient() {
   SECURITY_CHECK(state_ == kNotAddedAsClient);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResourceTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/RawResourceTest.cpp
index 2b7eb65..156a3c06 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResourceTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResourceTest.cpp
@@ -48,8 +48,8 @@
 
 class RawResourceTest : public ::testing::Test {
  public:
-  RawResourceTest() {}
-  ~RawResourceTest() override {}
+  RawResourceTest() = default;
+  ~RawResourceTest() override = default;
 
  protected:
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
@@ -78,7 +78,7 @@
 
  public:
   DummyClient() : called_(false), number_of_redirects_received_(0) {}
-  ~DummyClient() override {}
+  ~DummyClient() override = default;
 
   // ResourceClient implementation.
   void NotifyFinished(Resource* resource) override { called_ = true; }
@@ -119,7 +119,7 @@
   AddingClient(DummyClient* client, Resource* resource)
       : dummy_client_(client), resource_(resource) {}
 
-  ~AddingClient() override {}
+  ~AddingClient() override = default;
 
   // ResourceClient implementation.
   void NotifyFinished(Resource* resource) override {
@@ -176,7 +176,7 @@
  public:
   explicit RemovingClient(DummyClient* client) : dummy_client_(client) {}
 
-  ~RemovingClient() override {}
+  ~RemovingClient() override = default;
 
   // ResourceClient implementation.
   void NotifyFinished(Resource* resource) override {
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
index 226d35d..91217d3 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -118,7 +118,7 @@
   static Resource::CachedMetadataHandlerImpl* Create(Resource* resource) {
     return new CachedMetadataHandlerImpl(resource);
   }
-  ~CachedMetadataHandlerImpl() override {}
+  ~CachedMetadataHandlerImpl() override = default;
   void Trace(blink::Visitor*) override;
   void SetCachedMetadata(uint32_t, const char*, size_t, CacheType) override;
   void ClearCachedMetadata(CacheType) override;
@@ -217,7 +217,7 @@
     return new ServiceWorkerResponseCachedMetadataHandler(resource,
                                                           security_origin);
   }
-  ~ServiceWorkerResponseCachedMetadataHandler() override {}
+  ~ServiceWorkerResponseCachedMetadataHandler() override = default;
   void Trace(blink::Visitor*) override;
 
  protected:
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
index 99c063d..2b2168d5 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
@@ -44,7 +44,7 @@
     kRawResourceType
   };
 
-  virtual ~ResourceClient() {}
+  virtual ~ResourceClient() = default;
 
   // DataReceived() is called each time a chunk of data is received.
   // For cache hits, the data is replayed before NotifyFinished() is called.
@@ -72,7 +72,7 @@
   void Trace(blink::Visitor* visitor) override { visitor->Trace(resource_); }
 
  protected:
-  ResourceClient() {}
+  ResourceClient() = default;
 
   void ClearResource() { SetResource(nullptr, nullptr); }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
index a9440ce..321427e 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -289,7 +289,7 @@
       allow_stale_resources_(false),
       image_fetched_(false) {}
 
-ResourceFetcher::~ResourceFetcher() {}
+ResourceFetcher::~ResourceFetcher() = default;
 
 Resource* ResourceFetcher::CachedResource(const KURL& resource_url) const {
   KURL url = MemoryCache::RemoveFragmentIdentifierIfNeeded(resource_url);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
index 36fcdc0..37f1a8c 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
@@ -244,6 +244,13 @@
   // Currently we only care about stats from frames.
   if (!IsMainThread())
     return;
+
+  // Blink has several cases to create DocumentLoader not for an actual page
+  // load use. I.e., per a XMLHttpRequest in "document" type response.
+  // We just ignore such uninteresting cases in following metrics.
+  if (!total_throttled_request_count_ && !total_not_throttled_request_count_)
+    return;
+
   if (report_all_is_called_)
     return;
   report_all_is_called_ = true;
@@ -346,6 +353,10 @@
 
   if (!RuntimeEnabledFeatures::ResourceLoadSchedulerEnabled() &&
       !Platform::Current()->IsRendererSideResourceSchedulerEnabled()) {
+    // Initialize TrafficMonitor's state to be |kNotThrottled| so that it
+    // reports metrics in a reasonable state group.
+    traffic_monitor_->OnThrottlingStateChanged(
+        WebFrameScheduler::ThrottlingState::kNotThrottled);
     return;
   }
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadSchedulerTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadSchedulerTest.cpp
index 29df517..2cce8df 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadSchedulerTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadSchedulerTest.cpp
@@ -17,7 +17,7 @@
   USING_GARBAGE_COLLECTED_MIXIN(MockClient);
 
  public:
-  ~MockClient() {}
+  ~MockClient() = default;
 
   void Run() override {
     EXPECT_FALSE(was_run_);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
index 154f787..85c2930c 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
@@ -92,7 +92,7 @@
   resource_->SetLoader(this);
 }
 
-ResourceLoader::~ResourceLoader() {}
+ResourceLoader::~ResourceLoader() = default;
 
 void ResourceLoader::Trace(blink::Visitor* visitor) {
   visitor->Trace(fetcher_);
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
index ae0dd4c..6165e002 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
@@ -85,7 +85,7 @@
 
   class ExtraData : public RefCounted<ExtraData> {
    public:
-    virtual ~ExtraData() {}
+    virtual ~ExtraData() = default;
   };
 
   ResourceRequest();
@@ -428,7 +428,7 @@
   USING_FAST_MALLOC(CrossThreadResourceRequestData);
 
  public:
-  CrossThreadResourceRequestData() {}
+  CrossThreadResourceRequestData() = default;
   KURL url_;
 
   mojom::FetchCacheMode cache_mode_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h
index aa2b881..5c18a1c0 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceResponse.h
@@ -139,7 +139,7 @@
 
   class ExtraData : public RefCounted<ExtraData> {
    public:
-    virtual ~ExtraData() {}
+    virtual ~ExtraData() = default;
   };
 
   explicit ResourceResponse(CrossThreadResourceResponseData*);
@@ -568,7 +568,7 @@
   USING_FAST_MALLOC(CrossThreadResourceResponseData);
 
  public:
-  CrossThreadResourceResponseData() {}
+  CrossThreadResourceResponseData() = default;
   KURL url_;
   String mime_type_;
   long long expected_content_length_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceTest.cpp
index a678b21..6c1150d 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceTest.cpp
@@ -24,8 +24,8 @@
 
 class MockPlatform final : public TestingPlatformSupportWithMockScheduler {
  public:
-  MockPlatform() {}
-  ~MockPlatform() override {}
+  MockPlatform() = default;
+  ~MockPlatform() override = default;
 
   // From blink::Platform:
   void CacheMetadata(const WebURL& url, Time, const char*, size_t) override {
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceTimingInfo.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceTimingInfo.h
index 3a692a4..72fcdfde 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceTimingInfo.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceTimingInfo.h
@@ -139,7 +139,7 @@
   USING_FAST_MALLOC(CrossThreadResourceTimingInfoData);
 
  public:
-  CrossThreadResourceTimingInfoData() {}
+  CrossThreadResourceTimingInfoData() = default;
 
   String type_;
   String original_timing_allow_origin_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/SubstituteData.h b/third_party/WebKit/Source/platform/loader/fetch/SubstituteData.h
index 29a331ff..75279f9 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/SubstituteData.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/SubstituteData.h
@@ -37,7 +37,7 @@
   DISALLOW_NEW();
 
  public:
-  SubstituteData() {}
+  SubstituteData() = default;
 
   SubstituteData(scoped_refptr<SharedBuffer> content)
       : SubstituteData(content, "text/html", "UTF-8", KURL()) {}
diff --git a/third_party/WebKit/Source/platform/loader/testing/CryptoTestingPlatformSupport.h b/third_party/WebKit/Source/platform/loader/testing/CryptoTestingPlatformSupport.h
index 574a272c..6c1b6d8b 100644
--- a/third_party/WebKit/Source/platform/loader/testing/CryptoTestingPlatformSupport.h
+++ b/third_party/WebKit/Source/platform/loader/testing/CryptoTestingPlatformSupport.h
@@ -14,8 +14,8 @@
 
 class CryptoTestingPlatformSupport : public FetchTestingPlatformSupport {
  public:
-  CryptoTestingPlatformSupport() {}
-  ~CryptoTestingPlatformSupport() override {}
+  CryptoTestingPlatformSupport() = default;
+  ~CryptoTestingPlatformSupport() override = default;
 
   // Platform:
   WebCrypto* Crypto() override { return mock_web_crypto_.get(); }
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
index a9b6b05d..96fea59 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
@@ -36,7 +36,7 @@
     return new MockFetchContext(load_policy);
   }
 
-  ~MockFetchContext() override {}
+  ~MockFetchContext() override = default;
 
   void SetLoadComplete(bool complete) { complete_ = complete; }
   long long GetTransferSize() const { return transfer_size_; }
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockResourceClient.h b/third_party/WebKit/Source/platform/loader/testing/MockResourceClient.h
index 4f616e3..d6b6ebd 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockResourceClient.h
+++ b/third_party/WebKit/Source/platform/loader/testing/MockResourceClient.h
@@ -41,8 +41,8 @@
   USING_GARBAGE_COLLECTED_MIXIN(MockResourceClient);
 
  public:
-  MockResourceClient() {}
-  ~MockResourceClient() override {}
+  MockResourceClient() = default;
+  ~MockResourceClient() override = default;
 
   void NotifyFinished(Resource*) override {
     CHECK(!notify_finished_called_);
diff --git a/third_party/WebKit/Source/platform/loader/testing/WebURLLoaderFactoryWithMock.cpp b/third_party/WebKit/Source/platform/loader/testing/WebURLLoaderFactoryWithMock.cpp
index 6a0e587..55c6418c 100644
--- a/third_party/WebKit/Source/platform/loader/testing/WebURLLoaderFactoryWithMock.cpp
+++ b/third_party/WebKit/Source/platform/loader/testing/WebURLLoaderFactoryWithMock.cpp
@@ -13,7 +13,7 @@
     WebURLLoaderMockFactory* mock_factory)
     : mock_factory_(mock_factory) {}
 
-WebURLLoaderFactoryWithMock::~WebURLLoaderFactoryWithMock() {}
+WebURLLoaderFactoryWithMock::~WebURLLoaderFactoryWithMock() = default;
 
 std::unique_ptr<WebURLLoader> WebURLLoaderFactoryWithMock::CreateURLLoader(
     const WebURLRequest& request,
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp
index 17c00b4..be49b4a 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamCenter.cpp
@@ -55,7 +55,7 @@
 MediaStreamCenter::MediaStreamCenter()
     : private_(Platform::Current()->CreateMediaStreamCenter(this)) {}
 
-MediaStreamCenter::~MediaStreamCenter() {}
+MediaStreamCenter::~MediaStreamCenter() = default;
 
 void MediaStreamCenter::DidSetMediaStreamTrackEnabled(
     MediaStreamComponent* component) {
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
index b8cf2a8..ac5a5df 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
@@ -64,7 +64,7 @@
 
    public:
     virtual void GetSettings(WebMediaStreamTrack::Settings&) = 0;
-    virtual ~TrackData() {}
+    virtual ~TrackData() = default;
   };
 
   static MediaStreamComponent* Create(MediaStreamSource*);
@@ -125,7 +125,7 @@
    public:
     AudioSourceProviderImpl() : web_audio_source_provider_(nullptr) {}
 
-    ~AudioSourceProviderImpl() override {}
+    ~AudioSourceProviderImpl() override = default;
 
     // Wraps the given blink::WebAudioSourceProvider to
     // blink::AudioSourceProvider.
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamDescriptor.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamDescriptor.h
index da22ec3..dd39192 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamDescriptor.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamDescriptor.h
@@ -46,7 +46,7 @@
 class PLATFORM_EXPORT MediaStreamDescriptorClient
     : public GarbageCollectedMixin {
  public:
-  virtual ~MediaStreamDescriptorClient() {}
+  virtual ~MediaStreamDescriptorClient() = default;
 
   virtual void StreamEnded() = 0;
   virtual void AddTrackByComponent(MediaStreamComponent*) = 0;
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
index 379b4ac1..8b76d03 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
@@ -52,7 +52,7 @@
  public:
   class PLATFORM_EXPORT Observer : public GarbageCollectedMixin {
    public:
-    virtual ~Observer() {}
+    virtual ~Observer() = default;
     virtual void SourceChangedState() = 0;
   };
 
@@ -60,7 +60,7 @@
     USING_FAST_MALLOC(ExtraData);
 
    public:
-    virtual ~ExtraData() {}
+    virtual ~ExtraData() = default;
   };
 
   enum StreamType { kTypeAudio, kTypeVideo };
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamWebAudioSource.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamWebAudioSource.cpp
index 5bd7346..1d24fcc 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamWebAudioSource.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamWebAudioSource.cpp
@@ -39,7 +39,7 @@
     std::unique_ptr<WebAudioSourceProvider> provider)
     : web_audio_source_provider_(std::move(provider)) {}
 
-MediaStreamWebAudioSource::~MediaStreamWebAudioSource() {}
+MediaStreamWebAudioSource::~MediaStreamWebAudioSource() = default;
 
 void MediaStreamWebAudioSource::ProvideInput(AudioBus* bus,
                                              size_t frames_to_process) {
diff --git a/third_party/WebKit/Source/platform/mhtml/ArchiveResource.cpp b/third_party/WebKit/Source/platform/mhtml/ArchiveResource.cpp
index 378b3cc..afeec448 100644
--- a/third_party/WebKit/Source/platform/mhtml/ArchiveResource.cpp
+++ b/third_party/WebKit/Source/platform/mhtml/ArchiveResource.cpp
@@ -43,7 +43,7 @@
   DCHECK(data_);
 }
 
-ArchiveResource::~ArchiveResource() {}
+ArchiveResource::~ArchiveResource() = default;
 
 ArchiveResource* ArchiveResource::Create(scoped_refptr<SharedBuffer> data,
                                          const KURL& url,
diff --git a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
index 35583ed..f485212 100644
--- a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
+++ b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
@@ -75,7 +75,7 @@
   return "=?utf-8?Q?" + String(encoded_text.data(), encoded_text.size()) + "?=";
 }
 
-MHTMLArchive::MHTMLArchive() {}
+MHTMLArchive::MHTMLArchive() = default;
 
 MHTMLArchive* MHTMLArchive::Create(const KURL& url,
                                    scoped_refptr<const SharedBuffer> data) {
diff --git a/third_party/WebKit/Source/platform/mojo/Geometry.typemap b/third_party/WebKit/Source/platform/mojo/Geometry.typemap
index 4153c37..1763ca5 100644
--- a/third_party/WebKit/Source/platform/mojo/Geometry.typemap
+++ b/third_party/WebKit/Source/platform/mojo/Geometry.typemap
@@ -6,6 +6,7 @@
 public_headers = [
   "//third_party/WebKit/public/platform/WebFloatRect.h",
   "//third_party/WebKit/public/platform/WebFloatPoint.h",
+  "//third_party/WebKit/public/platform/WebPoint.h",
   "//third_party/WebKit/public/platform/WebRect.h",
   "//third_party/WebKit/public/platform/WebSize.h",
 ]
@@ -23,6 +24,7 @@
 # TODO(zqzhang): ideally, gfx.mojom.Size should be mapped into ::blink::IntSize.
 # However that introduces an link issue on Windows. See https://crbug.com/653323
 type_mappings = [
+  "gfx.mojom.Point=::blink::WebPoint",
   "gfx.mojom.PointF=::blink::WebFloatPoint",
   "gfx.mojom.RectF=::blink::WebFloatRect",
   "gfx.mojom.Rect=::blink::WebRect",
diff --git a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp
index 66ace43..93d7c6c1 100644
--- a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp
+++ b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp
@@ -33,6 +33,15 @@
 }
 
 // static
+bool StructTraits<gfx::mojom::PointDataView, ::blink::WebPoint>::Read(
+    gfx::mojom::PointDataView data,
+    ::blink::WebPoint* out) {
+  out->x = data.x();
+  out->y = data.y();
+  return true;
+}
+
+// static
 bool StructTraits<gfx::mojom::PointFDataView, ::blink::WebFloatPoint>::Read(
     gfx::mojom::PointFDataView data,
     ::blink::WebFloatPoint* out) {
diff --git a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h
index 07e5f4f..bd35a27 100644
--- a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h
+++ b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h
@@ -7,6 +7,7 @@
 
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebFloatRect.h"
+#include "third_party/WebKit/public/platform/WebPoint.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "ui/gfx/geometry/mojo/geometry.mojom-shared.h"
@@ -14,6 +15,13 @@
 namespace mojo {
 
 template <>
+struct StructTraits<gfx::mojom::PointDataView, ::blink::WebPoint> {
+  static int x(const ::blink::WebPoint& point) { return point.x; }
+  static int y(const ::blink::WebPoint& point) { return point.y; }
+  static bool Read(gfx::mojom::PointDataView, ::blink::WebPoint* out);
+};
+
+template <>
 struct StructTraits<gfx::mojom::PointFDataView, ::blink::WebFloatPoint> {
   static float x(const ::blink::WebFloatPoint& point) { return point.x; }
   static float y(const ::blink::WebFloatPoint& point) { return point.y; }
diff --git a/third_party/WebKit/Source/platform/mojo/GeometryStructTraitsTest.cpp b/third_party/WebKit/Source/platform/mojo/GeometryStructTraitsTest.cpp
index 73a76dc..78c083d 100644
--- a/third_party/WebKit/Source/platform/mojo/GeometryStructTraitsTest.cpp
+++ b/third_party/WebKit/Source/platform/mojo/GeometryStructTraitsTest.cpp
@@ -28,9 +28,8 @@
 
  private:
   // GeometryTraitsTestService:
-  void EchoPoint(gfx::mojom::blink::PointPtr, EchoPointCallback) override {
-    // The type map is not specified.
-    NOTREACHED();
+  void EchoPoint(const WebPoint& p, EchoPointCallback callback) override {
+    std::move(callback).Run(p);
   }
 
   void EchoPointF(const WebFloatPoint& p,
@@ -98,6 +97,16 @@
   EXPECT_EQ(input, output);
 }
 
+TEST_F(GeometryStructTraitsTest, Point) {
+  const float kX = 1234;
+  const float kY = 5678;
+  WebPoint input(kX, kY);
+  gfx::mojom::blink::GeometryTraitsTestServicePtr proxy = GetTraitsTestProxy();
+  WebPoint output;
+  proxy->EchoPoint(input, &output);
+  EXPECT_EQ(input, output);
+}
+
 TEST_F(GeometryStructTraitsTest, PointF) {
   const float kX = 1.234;
   const float kY = 5.678;
diff --git a/third_party/WebKit/Source/platform/network/ContentSecurityPolicyResponseHeaders.h b/third_party/WebKit/Source/platform/network/ContentSecurityPolicyResponseHeaders.h
index feafff6..a0f04ac 100644
--- a/third_party/WebKit/Source/platform/network/ContentSecurityPolicyResponseHeaders.h
+++ b/third_party/WebKit/Source/platform/network/ContentSecurityPolicyResponseHeaders.h
@@ -38,7 +38,7 @@
 
 class PLATFORM_EXPORT ContentSecurityPolicyResponseHeaders final {
  public:
-  ContentSecurityPolicyResponseHeaders() {}
+  ContentSecurityPolicyResponseHeaders() = default;
   explicit ContentSecurityPolicyResponseHeaders(const ResourceResponse&);
   explicit ContentSecurityPolicyResponseHeaders(
       const HTTPHeaderMap&,
diff --git a/third_party/WebKit/Source/platform/network/EncodedFormData.cpp b/third_party/WebKit/Source/platform/network/EncodedFormData.cpp
index 0b6e3eb8..663d3360 100644
--- a/third_party/WebKit/Source/platform/network/EncodedFormData.cpp
+++ b/third_party/WebKit/Source/platform/network/EncodedFormData.cpp
@@ -42,7 +42,7 @@
       identifier_(data.identifier_),
       contains_password_data_(data.contains_password_data_) {}
 
-EncodedFormData::~EncodedFormData() {}
+EncodedFormData::~EncodedFormData() = default;
 
 scoped_refptr<EncodedFormData> EncodedFormData::Create() {
   return base::AdoptRef(new EncodedFormData);
diff --git a/third_party/WebKit/Source/platform/network/HTTPHeaderMap.cpp b/third_party/WebKit/Source/platform/network/HTTPHeaderMap.cpp
index e90ae2b..8ee2ba7 100644
--- a/third_party/WebKit/Source/platform/network/HTTPHeaderMap.cpp
+++ b/third_party/WebKit/Source/platform/network/HTTPHeaderMap.cpp
@@ -34,9 +34,9 @@
 
 namespace blink {
 
-HTTPHeaderMap::HTTPHeaderMap() {}
+HTTPHeaderMap::HTTPHeaderMap() = default;
 
-HTTPHeaderMap::~HTTPHeaderMap() {}
+HTTPHeaderMap::~HTTPHeaderMap() = default;
 
 std::unique_ptr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::CopyData() const {
   std::unique_ptr<CrossThreadHTTPHeaderMapData> data =
diff --git a/third_party/WebKit/Source/platform/network/WebSocketHandshakeRequest.cpp b/third_party/WebKit/Source/platform/network/WebSocketHandshakeRequest.cpp
index e22242c..00fc4b9 100644
--- a/third_party/WebKit/Source/platform/network/WebSocketHandshakeRequest.cpp
+++ b/third_party/WebKit/Source/platform/network/WebSocketHandshakeRequest.cpp
@@ -35,7 +35,7 @@
 WebSocketHandshakeRequest::WebSocketHandshakeRequest(const KURL& url)
     : url_(url) {}
 
-WebSocketHandshakeRequest::WebSocketHandshakeRequest() {}
+WebSocketHandshakeRequest::WebSocketHandshakeRequest() = default;
 
 WebSocketHandshakeRequest::WebSocketHandshakeRequest(
     const WebSocketHandshakeRequest& request)
@@ -43,7 +43,7 @@
       header_fields_(request.header_fields_),
       headers_text_(request.headers_text_) {}
 
-WebSocketHandshakeRequest::~WebSocketHandshakeRequest() {}
+WebSocketHandshakeRequest::~WebSocketHandshakeRequest() = default;
 
 void WebSocketHandshakeRequest::AddAndMergeHeader(HTTPHeaderMap* map,
                                                   const AtomicString& name,
diff --git a/third_party/WebKit/Source/platform/network/WebSocketHandshakeResponse.cpp b/third_party/WebKit/Source/platform/network/WebSocketHandshakeResponse.cpp
index 341ac579..6af248e 100644
--- a/third_party/WebKit/Source/platform/network/WebSocketHandshakeResponse.cpp
+++ b/third_party/WebKit/Source/platform/network/WebSocketHandshakeResponse.cpp
@@ -36,9 +36,9 @@
 
 namespace blink {
 
-WebSocketHandshakeResponse::WebSocketHandshakeResponse() {}
+WebSocketHandshakeResponse::WebSocketHandshakeResponse() = default;
 
-WebSocketHandshakeResponse::~WebSocketHandshakeResponse() {}
+WebSocketHandshakeResponse::~WebSocketHandshakeResponse() = default;
 
 int WebSocketHandshakeResponse::StatusCode() const {
   return status_code_;
diff --git a/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp b/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp
index 14a2f7b0..6005e6f 100644
--- a/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp
+++ b/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp
@@ -27,7 +27,7 @@
     Platform::Current()->GetInterfaceProvider()->GetInterface(
         mojo::MakeRequest(&mime_registry));
   }
-  ~MimeRegistryPtrHolder() {}
+  ~MimeRegistryPtrHolder() = default;
 
   mojom::blink::MimeRegistryPtr mime_registry;
 };
diff --git a/third_party/WebKit/Source/platform/peerconnection/RTCSessionDescriptionRequest.h b/third_party/WebKit/Source/platform/peerconnection/RTCSessionDescriptionRequest.h
index 43f2b7e..d684bc1ff8 100644
--- a/third_party/WebKit/Source/platform/peerconnection/RTCSessionDescriptionRequest.h
+++ b/third_party/WebKit/Source/platform/peerconnection/RTCSessionDescriptionRequest.h
@@ -40,7 +40,7 @@
 class RTCSessionDescriptionRequest
     : public GarbageCollectedFinalized<RTCSessionDescriptionRequest> {
  public:
-  virtual ~RTCSessionDescriptionRequest() {}
+  virtual ~RTCSessionDescriptionRequest() = default;
 
   virtual void RequestSucceeded(const WebRTCSessionDescription&) = 0;
   virtual void RequestFailed(const String& error) = 0;
@@ -48,7 +48,7 @@
   virtual void Trace(blink::Visitor* visitor) {}
 
  protected:
-  RTCSessionDescriptionRequest() {}
+  RTCSessionDescriptionRequest() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/peerconnection/RTCStatsRequest.h b/third_party/WebKit/Source/platform/peerconnection/RTCStatsRequest.h
index c61aec42..4759290 100644
--- a/third_party/WebKit/Source/platform/peerconnection/RTCStatsRequest.h
+++ b/third_party/WebKit/Source/platform/peerconnection/RTCStatsRequest.h
@@ -42,7 +42,7 @@
 
 class RTCStatsRequest : public GarbageCollectedFinalized<RTCStatsRequest> {
  public:
-  virtual ~RTCStatsRequest() {}
+  virtual ~RTCStatsRequest() = default;
 
   virtual RTCStatsResponseBase* CreateResponse() = 0;
   virtual bool HasSelector() = 0;
@@ -52,7 +52,7 @@
   virtual void Trace(blink::Visitor* visitor) {}
 
  protected:
-  RTCStatsRequest() {}
+  RTCStatsRequest() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/peerconnection/RTCStatsResponseBase.h b/third_party/WebKit/Source/platform/peerconnection/RTCStatsResponseBase.h
index 752f703..c11fc9b9 100644
--- a/third_party/WebKit/Source/platform/peerconnection/RTCStatsResponseBase.h
+++ b/third_party/WebKit/Source/platform/peerconnection/RTCStatsResponseBase.h
@@ -33,7 +33,7 @@
 
 class RTCStatsResponseBase : public ScriptWrappable {
  public:
-  virtual ~RTCStatsResponseBase() {}
+  virtual ~RTCStatsResponseBase() = default;
 
   virtual void AddStats(const WebRTCLegacyStats&) = 0;
 };
diff --git a/third_party/WebKit/Source/platform/peerconnection/RTCVoidRequest.h b/third_party/WebKit/Source/platform/peerconnection/RTCVoidRequest.h
index f76dbe9..9467f676 100644
--- a/third_party/WebKit/Source/platform/peerconnection/RTCVoidRequest.h
+++ b/third_party/WebKit/Source/platform/peerconnection/RTCVoidRequest.h
@@ -38,7 +38,7 @@
 
 class RTCVoidRequest : public GarbageCollectedFinalized<RTCVoidRequest> {
  public:
-  virtual ~RTCVoidRequest() {}
+  virtual ~RTCVoidRequest() = default;
 
   virtual void RequestSucceeded() = 0;
   virtual void RequestFailed(const String& error) = 0;
@@ -46,7 +46,7 @@
   virtual void Trace(blink::Visitor* visitor) {}
 
  protected:
-  RTCVoidRequest() {}
+  RTCVoidRequest() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/plugins/PluginData.h b/third_party/WebKit/Source/platform/plugins/PluginData.h
index 22f08da9..bdd586b 100644
--- a/third_party/WebKit/Source/platform/plugins/PluginData.h
+++ b/third_party/WebKit/Source/platform/plugins/PluginData.h
@@ -106,7 +106,7 @@
   static void RefreshBrowserSidePluginCache();
 
  private:
-  PluginData() {}
+  PluginData() = default;
 
   HeapVector<Member<PluginInfo>> plugins_;
   HeapVector<Member<MimeClassInfo>> mimes_;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc b/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc
index f2570877..6bb86306 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc
@@ -13,7 +13,7 @@
 EnqueueOrderGenerator::EnqueueOrderGenerator()
     : enqueue_order_(static_cast<EnqueueOrder>(EnqueueOrderValues::kFirst)) {}
 
-EnqueueOrderGenerator::~EnqueueOrderGenerator() {}
+EnqueueOrderGenerator::~EnqueueOrderGenerator() = default;
 
 EnqueueOrder EnqueueOrderGenerator::GenerateNext() {
   base::AutoLock lock(lock_);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc b/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc
index df4d89e..2d7f233c 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/graceful_queue_shutdown_helper.cc
@@ -11,7 +11,7 @@
 GracefulQueueShutdownHelper::GracefulQueueShutdownHelper()
     : task_queue_manager_deleted_(false) {}
 
-GracefulQueueShutdownHelper::~GracefulQueueShutdownHelper() {}
+GracefulQueueShutdownHelper::~GracefulQueueShutdownHelper() = default;
 
 void GracefulQueueShutdownHelper::GracefullyShutdownTaskQueue(
     std::unique_ptr<internal::TaskQueueImpl> task_queue) {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
index 702d88a..be4e285 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
@@ -13,7 +13,7 @@
 
 RealTimeDomain::RealTimeDomain() : task_queue_manager_(nullptr) {}
 
-RealTimeDomain::~RealTimeDomain() {}
+RealTimeDomain::~RealTimeDomain() = default;
 
 void RealTimeDomain::OnRegisterWithTaskQueueManager(
     TaskQueueManager* task_queue_manager) {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue.h
index 9af508e..a0f2e88 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue.h
@@ -40,7 +40,7 @@
  public:
   class PLATFORM_EXPORT Observer {
    public:
-    virtual ~Observer() {}
+    virtual ~Observer() = default;
 
     // Notify observer that the time at which this queue wants to run
     // the next task has changed. |next_wakeup| can be in the past
@@ -153,8 +153,8 @@
   // TaskQueue should be enabled.
   class QueueEnabledVoter {
    public:
-    QueueEnabledVoter() {}
-    virtual ~QueueEnabledVoter() {}
+    QueueEnabledVoter() = default;
+    virtual ~QueueEnabledVoter() = default;
 
     // Votes to enable or disable the associated TaskQueue. The TaskQueue will
     // only be enabled if all the voters agree it should be enabled, or if there
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
index 82bc41cf..b3939fc 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -91,7 +91,7 @@
                                     TimeDomain* time_domain)
     : task_queue_manager(task_queue_manager), time_domain(time_domain) {}
 
-TaskQueueImpl::AnyThread::~AnyThread() {}
+TaskQueueImpl::AnyThread::~AnyThread() = default;
 
 TaskQueueImpl::MainThreadOnly::MainThreadOnly(
     TaskQueueManager* task_queue_manager,
@@ -111,7 +111,7 @@
       current_fence(0),
       is_enabled_for_test(true) {}
 
-TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {}
+TaskQueueImpl::MainThreadOnly::~MainThreadOnly() = default;
 
 void TaskQueueImpl::UnregisterTaskQueue() {
   TaskDeque immediate_incoming_queue;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
index 2f228b7..d341cce 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
@@ -33,7 +33,7 @@
 class PerfTestTimeDomain : public VirtualTimeDomain {
  public:
   PerfTestTimeDomain() : VirtualTimeDomain(base::TimeTicks::Now()) {}
-  ~PerfTestTimeDomain() override {}
+  ~PerfTestTimeDomain() override = default;
 
   base::Optional<base::TimeDelta> DelayTillNextTask(
       LazyNow* lazy_now) override {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index d03dd7ac..b24d2d6 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -69,7 +69,7 @@
                              std::move(task_runner),
                              time_source) {}
 
-  ~ThreadControllerForTest() override {}
+  ~ThreadControllerForTest() override = default;
 
   void AddNestingObserver(base::RunLoop::NestingObserver* observer) override {
     if (!message_loop_)
@@ -86,7 +86,7 @@
 
 class TaskQueueManagerTest : public ::testing::Test {
  public:
-  TaskQueueManagerTest() {}
+  TaskQueueManagerTest() = default;
   void DeleteTaskQueueManager() { manager_.reset(); }
 
  protected:
@@ -1866,7 +1866,7 @@
 
 class MockTaskQueueObserver : public TaskQueue::Observer {
  public:
-  ~MockTaskQueueObserver() override {}
+  ~MockTaskQueueObserver() override = default;
 
   MOCK_METHOD2(OnQueueNextWakeUpChanged, void(TaskQueue*, base::TimeTicks));
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc
index 62882dd..1cf39cb8 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc
@@ -22,7 +22,7 @@
       num_blocked_queues_to_report_(0),
       task_queue_selector_observer_(nullptr) {}
 
-TaskQueueSelector::~TaskQueueSelector() {}
+TaskQueueSelector::~TaskQueueSelector() = default;
 
 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h
index 7c53b48..985ec2ac 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h
@@ -60,7 +60,7 @@
 
   class PLATFORM_EXPORT Observer {
    public:
-    virtual ~Observer() {}
+    virtual ~Observer() = default;
 
     // Called when |queue| transitions from disabled to enabled.
     virtual void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) = 0;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
index 44f376d3..5b44a245 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
@@ -29,8 +29,8 @@
 
 class MockObserver : public TaskQueueSelector::Observer {
  public:
-  MockObserver() {}
-  virtual ~MockObserver() {}
+  MockObserver() = default;
+  virtual ~MockObserver() = default;
 
   MOCK_METHOD1(OnTaskQueueEnabled, void(internal::TaskQueueImpl*));
   MOCK_METHOD1(OnTriedToSelectBlockedWorkQueue, void(internal::WorkQueue*));
@@ -50,7 +50,7 @@
  public:
   TaskQueueSelectorTest()
       : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {}
-  ~TaskQueueSelectorTest() override {}
+  ~TaskQueueSelectorTest() override = default;
 
   TaskQueueSelectorForTest::PrioritizingSelector* enabled_selector() {
     return selector_.enabled_selector_for_test();
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h b/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h
index 38124e5..8e8f19db 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_time_observer.h
@@ -14,8 +14,8 @@
 // TaskTimeObserver provides an API for observing completion of renderer tasks.
 class PLATFORM_EXPORT TaskTimeObserver {
  public:
-  TaskTimeObserver() {}
-  virtual ~TaskTimeObserver() {}
+  TaskTimeObserver() = default;
+  virtual ~TaskTimeObserver() = default;
 
   // Callback to be called when task is about to start.
   // |start_time| - time in seconds when task started to run,
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc b/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc
index 28f82a8..e61164e7 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc
@@ -10,7 +10,7 @@
 
 TestCountUsesTimeSource::TestCountUsesTimeSource() : now_calls_count_(0) {}
 
-TestCountUsesTimeSource::~TestCountUsesTimeSource() {}
+TestCountUsesTimeSource::~TestCountUsesTimeSource() = default;
 
 base::TimeTicks TestCountUsesTimeSource::NowTicks() {
   now_calls_count_++;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h b/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h
index 56a22d8..e1d65ed 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h
@@ -24,7 +24,7 @@
 // Interface for TaskQueueManager to schedule work to be run.
 class PLATFORM_EXPORT ThreadController {
  public:
-  virtual ~ThreadController() {}
+  virtual ~ThreadController() = default;
 
   // Notify the controller that its associated sequence has immediate work
   // to run. Shortly after this is called, the thread associated with this
diff --git a/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc
index 62d0fa2..8fea7efe 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc
@@ -33,7 +33,7 @@
                                                  Sequence::WorkType::kDelayed);
 }
 
-ThreadControllerImpl::~ThreadControllerImpl() {}
+ThreadControllerImpl::~ThreadControllerImpl() = default;
 
 std::unique_ptr<ThreadControllerImpl> ThreadControllerImpl::Create(
     base::MessageLoop* message_loop,
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
index d0b64b7..d621846 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
@@ -12,7 +12,7 @@
 namespace blink {
 namespace scheduler {
 
-TimeDomain::TimeDomain() {}
+TimeDomain::TimeDomain() = default;
 
 TimeDomain::~TimeDomain() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
index b35203d..274bc56 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
@@ -26,7 +26,7 @@
   MockTimeDomain()
       : now_(base::TimeTicks() + base::TimeDelta::FromSeconds(1)) {}
 
-  ~MockTimeDomain() override {}
+  ~MockTimeDomain() override = default;
 
   using TimeDomain::CancelDelayedWork;
   using TimeDomain::NextScheduledRunTime;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
index 930195b6..e425035 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
@@ -14,7 +14,7 @@
 VirtualTimeDomain::VirtualTimeDomain(base::TimeTicks initial_time)
     : now_(initial_time), task_queue_manager_(nullptr) {}
 
-VirtualTimeDomain::~VirtualTimeDomain() {}
+VirtualTimeDomain::~VirtualTimeDomain() = default;
 
 void VirtualTimeDomain::OnRegisterWithTaskQueueManager(
     TaskQueueManager* task_queue_manager) {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc
index d2ff24c..f9e564b 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc
@@ -13,7 +13,7 @@
 WorkQueueSets::WorkQueueSets(size_t num_sets, const char* name)
     : work_queue_heaps_(num_sets), name_(name) {}
 
-WorkQueueSets::~WorkQueueSets() {}
+WorkQueueSets::~WorkQueueSets() = default;
 
 void WorkQueueSets::AddQueue(WorkQueue* work_queue, size_t set_index) {
   DCHECK(!work_queue->work_queue_sets());
diff --git a/third_party/WebKit/Source/platform/scheduler/child/cancelable_closure_holder.cc b/third_party/WebKit/Source/platform/scheduler/child/cancelable_closure_holder.cc
index 930cfa0..f08c003 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/cancelable_closure_holder.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/cancelable_closure_holder.cc
@@ -7,9 +7,9 @@
 namespace blink {
 namespace scheduler {
 
-CancelableClosureHolder::CancelableClosureHolder() {}
+CancelableClosureHolder::CancelableClosureHolder() = default;
 
-CancelableClosureHolder::~CancelableClosureHolder() {}
+CancelableClosureHolder::~CancelableClosureHolder() = default;
 
 void CancelableClosureHolder::Reset(const base::Closure& callback) {
   callback_ = callback;
diff --git a/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc
index 31462825..c4eb5c02 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc
@@ -27,7 +27,7 @@
       compositor_thread_task_duration_reporter_(
           "RendererScheduler.TaskDurationPerThreadType") {}
 
-CompositorWorkerScheduler::~CompositorWorkerScheduler() {}
+CompositorWorkerScheduler::~CompositorWorkerScheduler() = default;
 
 scoped_refptr<WorkerTaskQueue> CompositorWorkerScheduler::DefaultTaskQueue() {
   return helper_->DefaultWorkerTaskQueue();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
index 6209b36..138246a9 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
@@ -52,7 +52,7 @@
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
-  ~IdleCanceledDelayedTaskSweeperTest() override {}
+  ~IdleCanceledDelayedTaskSweeperTest() override = default;
 
   void TearDown() override {
     // Check that all tests stop posting tasks.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
index fa84667..d095066 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
@@ -58,9 +58,9 @@
   idle_queue_->ShutdownTaskQueue();
 }
 
-IdleHelper::Delegate::Delegate() {}
+IdleHelper::Delegate::Delegate() = default;
 
-IdleHelper::Delegate::~Delegate() {}
+IdleHelper::Delegate::~Delegate() = default;
 
 scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() {
   helper_->CheckOnValidThread();
@@ -351,7 +351,7 @@
       running_idle_task_for_tracing_(false),
       idle_period_tracing_name_(idle_period_tracing_name) {}
 
-IdleHelper::State::~State() {}
+IdleHelper::State::~State() = default;
 
 IdleHelper::IdlePeriodState IdleHelper::State::idle_period_state() const {
   helper_->CheckOnValidThread();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
index 5b639caa..da38ea6 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
@@ -174,7 +174,7 @@
                    required_quiescence_duration_before_long_idle_period,
                    idle_task_runner) {}
 
-  ~IdleHelperForTest() override {}
+  ~IdleHelperForTest() override = default;
 
   // IdleHelper::Delegate implementation:
   MOCK_METHOD2(CanEnterLongIdlePeriod,
@@ -211,7 +211,7 @@
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
-  ~BaseIdleHelperTest() override {}
+  ~BaseIdleHelperTest() override = default;
 
   void SetUp() override {
     EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
@@ -314,7 +314,7 @@
  public:
   IdleHelperTest() : BaseIdleHelperTest(nullptr, base::TimeDelta()) {}
 
-  ~IdleHelperTest() override {}
+  ~IdleHelperTest() override = default;
 
   TaskQueueManager* task_queue_manager() const {
     return scheduler_helper_->GetTaskQueueManagerForTesting();
@@ -421,7 +421,7 @@
   IdleHelperTestWithIdlePeriodObserver()
       : BaseIdleHelperTest(nullptr, base::TimeDelta()) {}
 
-  ~IdleHelperTestWithIdlePeriodObserver() override {}
+  ~IdleHelperTestWithIdlePeriodObserver() override = default;
 
   void SetUp() override {
     // Don't set expectations on IdleHelper::Delegate.
@@ -475,7 +475,7 @@
  public:
   IdleHelperWithMessageLoopTest()
       : BaseIdleHelperTest(new base::MessageLoop(), base::TimeDelta()) {}
-  ~IdleHelperWithMessageLoopTest() override {}
+  ~IdleHelperWithMessageLoopTest() override = default;
 
   void PostFromNestedRunloop(
       std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>*
@@ -871,7 +871,7 @@
             nullptr,
             base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs)) {}
 
-  ~IdleHelperWithQuiescencePeriodTest() override {}
+  ~IdleHelperWithQuiescencePeriodTest() override = default;
 
   void SetUp() override {
     EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
@@ -898,7 +898,8 @@
   IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver()
       : IdleHelperWithQuiescencePeriodTest() {}
 
-  ~IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() override {}
+  ~IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() override =
+      default;
 
   void SetUp() override {
     // Don't set expectations on IdleHelper::Delegate.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/pollable_thread_safe_flag.cc b/third_party/WebKit/Source/platform/scheduler/child/pollable_thread_safe_flag.cc
index efda3253..318015c 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/pollable_thread_safe_flag.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/pollable_thread_safe_flag.cc
@@ -7,7 +7,7 @@
 PollableThreadSafeFlag::PollableThreadSafeFlag(base::Lock* write_lock_)
     : flag_(false), write_lock_(write_lock_) {}
 
-PollableThreadSafeFlag::~PollableThreadSafeFlag() {}
+PollableThreadSafeFlag::~PollableThreadSafeFlag() = default;
 
 void PollableThreadSafeFlag::SetWhileLocked(bool value) {
   write_lock_->AssertAcquired();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h
index 84e478f..6b1fff8 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h
@@ -62,7 +62,7 @@
 
   class PLATFORM_EXPORT Observer {
    public:
-    virtual ~Observer() {}
+    virtual ~Observer() = default;
 
     // Called when the scheduler tried to execute a task from a disabled
     // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
index 496d972..94e2852 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
@@ -61,7 +61,7 @@
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
-  ~SchedulerHelperTest() override {}
+  ~SchedulerHelperTest() override = default;
 
   void TearDown() override {
     // Check that all tests stop posting tasks.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc
index f9b56ac..36f117e 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc
@@ -24,11 +24,11 @@
   weak_scheduler_ptr_ = weak_factory_.GetWeakPtr();
 }
 
-SingleThreadIdleTaskRunner::~SingleThreadIdleTaskRunner() {}
+SingleThreadIdleTaskRunner::~SingleThreadIdleTaskRunner() = default;
 
-SingleThreadIdleTaskRunner::Delegate::Delegate() {}
+SingleThreadIdleTaskRunner::Delegate::Delegate() = default;
 
-SingleThreadIdleTaskRunner::Delegate::~Delegate() {}
+SingleThreadIdleTaskRunner::Delegate::~Delegate() = default;
 
 bool SingleThreadIdleTaskRunner::RunsTasksInCurrentSequence() const {
   return idle_priority_task_runner_->RunsTasksInCurrentSequence();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler.h b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler.h
index 7bc99cf..5c97b36 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler.h
@@ -24,7 +24,7 @@
  public:
   class PLATFORM_EXPORT InterventionReporter {
    public:
-    virtual ~InterventionReporter() {}
+    virtual ~InterventionReporter() = default;
 
     // The scheduler has performed an intervention, described by |message|,
     // which should be reported to the developer.
@@ -33,7 +33,7 @@
 
   using RendererPauseHandle = scheduler::RendererScheduler::RendererPauseHandle;
 
-  virtual ~WebScheduler() {}
+  virtual ~WebScheduler() = default;
 
   // Called to prevent any more pending tasks from running. Must be called on
   // the associated WebThread.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
index 730edec2..ca790e7f 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
@@ -30,7 +30,7 @@
       v8_web_task_runner_(
           WebTaskRunnerImpl::Create(v8_task_runner, base::nullopt)) {}
 
-WebSchedulerImpl::~WebSchedulerImpl() {}
+WebSchedulerImpl::~WebSchedulerImpl() = default;
 
 void WebSchedulerImpl::Shutdown() {
   child_scheduler_->Shutdown();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
index 7d39e93..c29fed3 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
@@ -35,7 +35,7 @@
                                      base::Optional<TaskType> task_type)
     : task_queue_(std::move(task_queue)), task_type_(task_type) {}
 
-WebTaskRunnerImpl::~WebTaskRunnerImpl() {}
+WebTaskRunnerImpl::~WebTaskRunnerImpl() = default;
 
 base::TimeTicks WebTaskRunnerImpl::Now() const {
   TimeDomain* time_domain = task_queue_->GetTimeDomain();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc
index 188abee..5c149bb 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc
@@ -40,7 +40,7 @@
   WebThread::TaskObserver* observer_;
 };
 
-WebThreadBase::WebThreadBase() {}
+WebThreadBase::WebThreadBase() = default;
 
 WebThreadBase::~WebThreadBase() {
   for (auto& observer_entry : task_observer_map_) {
@@ -117,7 +117,7 @@
       : WebThreadImplForWorkerScheduler("Compositor", options) {
     Init();
   }
-  ~WebThreadForCompositor() override {}
+  ~WebThreadForCompositor() override = default;
 
  private:
   // WebThreadImplForWorkerScheduler:
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
index 2f28e5d..77cd435 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
@@ -37,7 +37,7 @@
  public:
   explicit TestObserver(std::string* calls) : calls_(calls) {}
 
-  ~TestObserver() override {}
+  ~TestObserver() override = default;
 
   void WillProcessTask() override { calls_->append(" willProcessTask"); }
 
@@ -69,9 +69,9 @@
 
 class WebThreadImplForWorkerSchedulerTest : public ::testing::Test {
  public:
-  WebThreadImplForWorkerSchedulerTest() {}
+  WebThreadImplForWorkerSchedulerTest() = default;
 
-  ~WebThreadImplForWorkerSchedulerTest() override {}
+  ~WebThreadImplForWorkerSchedulerTest() override = default;
 
   void SetUp() override {
     thread_.reset(new WebThreadImplForWorkerScheduler("test thread"));
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc
index 8d820b4..5997a3c 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_global_scope_scheduler_unittest.cc
@@ -38,7 +38,7 @@
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
-  ~WorkerGlobalScopeSchedulerTest() override {}
+  ~WorkerGlobalScopeSchedulerTest() override = default;
 
   void SetUp() override {
     scheduler_->Init();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc
index 4dba547..2178caf9 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc
@@ -16,7 +16,7 @@
 WorkerScheduler::WorkerScheduler(std::unique_ptr<WorkerSchedulerHelper> helper)
     : helper_(std::move(helper)) {}
 
-WorkerScheduler::~WorkerScheduler() {}
+WorkerScheduler::~WorkerScheduler() = default;
 
 // static
 std::unique_ptr<WorkerScheduler> WorkerScheduler::Create() {
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
index 3742b45..7099ad3 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
@@ -100,7 +100,7 @@
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
-  ~WorkerSchedulerImplTest() override {}
+  ~WorkerSchedulerImplTest() override = default;
 
   void TearDown() override {
     // Check that all tests stop posting tasks.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc
index 69ebbcb5..b518220 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc
@@ -21,7 +21,7 @@
   }
 }
 
-WorkerTaskQueue::~WorkerTaskQueue() {}
+WorkerTaskQueue::~WorkerTaskQueue() = default;
 
 void WorkerTaskQueue::OnTaskCompleted(const TaskQueue::Task& task,
                                       base::TimeTicks start,
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
index 44fb0bdf..acee7c8a 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
@@ -91,9 +91,9 @@
   }
 }
 
-AutoAdvancingVirtualTimeDomain::Observer::Observer() {}
+AutoAdvancingVirtualTimeDomain::Observer::Observer() = default;
 
-AutoAdvancingVirtualTimeDomain::Observer::~Observer() {}
+AutoAdvancingVirtualTimeDomain::Observer::~Observer() = default;
 
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
index bc8d0ef..ef68520 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
@@ -22,8 +22,8 @@
 
 class AutoAdvancingVirtualTimeDomainTest : public ::testing::Test {
  public:
-  AutoAdvancingVirtualTimeDomainTest() {}
-  ~AutoAdvancingVirtualTimeDomainTest() override {}
+  AutoAdvancingVirtualTimeDomainTest() = default;
+  ~AutoAdvancingVirtualTimeDomainTest() override = default;
 
   void SetUp() override {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc
index 6224516..cee532f 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc
@@ -19,7 +19,7 @@
       budget_pool_controller_(budget_pool_controller),
       is_enabled_(true) {}
 
-BudgetPool::~BudgetPool() {}
+BudgetPool::~BudgetPool() = default;
 
 const char* BudgetPool::Name() const {
   return name_;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
index dcc5d88..30c7f430 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
@@ -26,8 +26,8 @@
 
 class BudgetPoolTest : public ::testing::Test {
  public:
-  BudgetPoolTest() {}
-  ~BudgetPoolTest() override {}
+  BudgetPoolTest() = default;
+  ~BudgetPoolTest() override = default;
 
   void SetUp() override {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
index 76c2988c..b3c9393 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
@@ -26,7 +26,7 @@
       last_checkpoint_(now),
       cpu_percentage_(1) {}
 
-CPUTimeBudgetPool::~CPUTimeBudgetPool() {}
+CPUTimeBudgetPool::~CPUTimeBudgetPool() = default;
 
 QueueBlockType CPUTimeBudgetPool::GetBlockType() const {
   return QueueBlockType::kAllTasks;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
index cba5c22..c1f8443 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
@@ -17,7 +17,7 @@
       base::Bind(&DeadlineTaskRunner::RunInternal, base::Unretained(this)));
 }
 
-DeadlineTaskRunner::~DeadlineTaskRunner() {}
+DeadlineTaskRunner::~DeadlineTaskRunner() = default;
 
 void DeadlineTaskRunner::SetDeadline(const base::Location& from_here,
                                      base::TimeDelta delay,
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
index e29085c..1b9f6bd 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
@@ -16,8 +16,8 @@
 
 class DeadlineTaskRunnerTest : public ::testing::Test {
  public:
-  DeadlineTaskRunnerTest() {}
-  ~DeadlineTaskRunnerTest() override {}
+  DeadlineTaskRunnerTest() = default;
+  ~DeadlineTaskRunnerTest() override = default;
 
   void SetUp() override {
     clock_.reset(new base::SimpleTestTickClock());
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc
index 520f29ed..f3a2fba 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc
@@ -37,7 +37,7 @@
   IdleTimeEstimatorTest()
       : frame_length_(base::TimeDelta::FromMilliseconds(16)) {}
 
-  ~IdleTimeEstimatorTest() override {}
+  ~IdleTimeEstimatorTest() override = default;
 
   void SetUp() override {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
index 812cd541..7616a48 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
@@ -15,39 +15,39 @@
     MainThreadTaskQueue::QueueType queue_type) {
   switch (queue_type) {
     case MainThreadTaskQueue::QueueType::kControl:
-      return "ControlTQ";
+      return "control_tq";
     case MainThreadTaskQueue::QueueType::kDefault:
-      return "DefaultTQ";
+      return "default_tq";
     case MainThreadTaskQueue::QueueType::kDefaultLoading:
-      return "DefaultLoadingTQ";
+      return "default_loading_tq";
     case MainThreadTaskQueue::QueueType::kDefaultTimer:
-      return "DefaultTimerTQ";
+      return "default_timer_tq";
     case MainThreadTaskQueue::QueueType::kUnthrottled:
-      return "UnthrottledTQ";
+      return "unthrottled_tq";
     case MainThreadTaskQueue::QueueType::kFrameLoading:
-      return "FrameLoadingTQ";
+      return "frame_loading_tq";
     case MainThreadTaskQueue::QueueType::kFrameThrottleable:
-      return "FrameThrottleableTQ";
+      return "frame_throttleable_tq";
     case MainThreadTaskQueue::QueueType::kFrameDeferrable:
-      return "FrameDeferrableTQ";
+      return "frame_deferrable_tq";
     case MainThreadTaskQueue::QueueType::kFramePausable:
-      return "FramePausableTQ";
+      return "frame_pausable_tq";
     case MainThreadTaskQueue::QueueType::kFrameUnpausable:
-      return "FrameUnpausableTQ";
+      return "frame_unpausable_tq";
     case MainThreadTaskQueue::QueueType::kCompositor:
-      return "CompositorTQ";
+      return "compositor_tq";
     case MainThreadTaskQueue::QueueType::kIdle:
-      return "IdleTQ";
+      return "idle_tq";
     case MainThreadTaskQueue::QueueType::kTest:
-      return "TestTQ";
+      return "test_tq";
     case MainThreadTaskQueue::QueueType::kFrameLoading_kControl:
-      return "FrameLoadingControlTQ";
+      return "frame_loading_control_tq";
     case MainThreadTaskQueue::QueueType::kV8:
-      return "V8TQ";
+      return "v8_tq";
     case MainThreadTaskQueue::QueueType::kIPC:
-      return "IPCTQ";
+      return "ipc_tq";
     case MainThreadTaskQueue::QueueType::kOther:
-      return "OtherTQ";
+      return "other_tq";
     case MainThreadTaskQueue::QueueType::kCount:
       NOTREACHED();
       return nullptr;
@@ -112,7 +112,7 @@
   }
 }
 
-MainThreadTaskQueue::~MainThreadTaskQueue() {}
+MainThreadTaskQueue::~MainThreadTaskQueue() = default;
 
 void MainThreadTaskQueue::OnTaskStarted(const TaskQueue::Task& task,
                                         base::TimeTicks start) {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.cc b/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.cc
index fa7c0f4f..7d79cada 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.cc
@@ -363,8 +363,8 @@
 
   base::TimeDelta queueing_time() { return queueing_time_; }
 
-  RecordQueueingTimeClient() {}
-  ~RecordQueueingTimeClient() override {}
+  RecordQueueingTimeClient() = default;
+  ~RecordQueueingTimeClient() override = default;
 
  private:
   base::TimeDelta queueing_time_;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.h b/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.h
index 18d0fb9..dfb2cca 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/queueing_time_estimator.h
@@ -28,8 +28,8 @@
     virtual void OnReportFineGrainedExpectedQueueingTime(
         const char* split_description,
         base::TimeDelta queueing_time) = 0;
-    Client() {}
-    virtual ~Client() {}
+    Client() = default;
+    virtual ~Client() = default;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(Client);
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h
index 9ee1c9f19..e1c8a75 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h
@@ -20,7 +20,7 @@
  public:
   class PLATFORM_EXPORT Observer {
    public:
-    virtual ~Observer() {}
+    virtual ~Observer() = default;
 
     // If |hidden| is true then all render widgets managed by this renderer
     // process have been hidden.
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cc
index 8a3f164..db04860 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cc
@@ -20,8 +20,8 @@
 
 class MockObserver : public RenderWidgetSignals::Observer {
  public:
-  MockObserver() {}
-  virtual ~MockObserver() {}
+  MockObserver() = default;
+  virtual ~MockObserver() = default;
 
   MOCK_METHOD1(SetAllRenderWidgetsHidden, void(bool hidden));
   MOCK_METHOD1(SetHasVisibleRenderWidgetWithTouchHandler,
@@ -33,8 +33,8 @@
 
 class RenderWidgetSignalsTest : public ::testing::Test {
  public:
-  RenderWidgetSignalsTest() {}
-  ~RenderWidgetSignalsTest() override {}
+  RenderWidgetSignalsTest() = default;
+  ~RenderWidgetSignalsTest() override = default;
 
   void SetUp() override {
     mock_observer_.reset(new MockObserver());
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
index 288ffe99..d076a4f 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
@@ -109,7 +109,7 @@
   }
 }
 
-RendererMetricsHelper::~RendererMetricsHelper() {}
+RendererMetricsHelper::~RendererMetricsHelper() = default;
 
 void RendererMetricsHelper::OnRendererForegrounded(base::TimeTicks now) {
   foreground_main_thread_load_tracker.Resume(now);
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
index 5d206dfe..b4bfeb1 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
@@ -27,8 +27,8 @@
 
 class RendererMetricsHelperTest : public ::testing::Test {
  public:
-  RendererMetricsHelperTest() {}
-  ~RendererMetricsHelperTest() {}
+  RendererMetricsHelperTest() = default;
+  ~RendererMetricsHelperTest() = default;
 
   void SetUp() {
     histogram_tester_.reset(new base::HistogramTester());
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc
index d436887b..db9d06ef 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc
@@ -16,9 +16,9 @@
 namespace blink {
 namespace scheduler {
 
-RendererScheduler::RendererScheduler() {}
+RendererScheduler::RendererScheduler() = default;
 
-RendererScheduler::~RendererScheduler() {}
+RendererScheduler::~RendererScheduler() = default;
 
 RendererScheduler::RAILModeObserver::~RAILModeObserver() = default;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index c7fe1d2..701808c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -454,7 +454,7 @@
       virtual_time_stopped(false),
       nested_runloop(false) {}
 
-RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {}
+RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default;
 
 RendererSchedulerImpl::AnyThread::AnyThread()
     : awaiting_touch_start_response(false),
@@ -466,13 +466,13 @@
       waiting_for_meaningful_paint(false),
       have_seen_input_since_navigation(false) {}
 
-RendererSchedulerImpl::AnyThread::~AnyThread() {}
+RendererSchedulerImpl::AnyThread::~AnyThread() = default;
 
 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
     : last_input_type(blink::WebInputEvent::kUndefined),
       main_thread_seems_unresponsive(false) {}
 
-RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {}
+RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() = default;
 
 RendererSchedulerImpl::RendererPauseHandleImpl::RendererPauseHandleImpl(
     RendererSchedulerImpl* scheduler)
@@ -549,7 +549,7 @@
   return default_timer_task_queue_;
 }
 
-scoped_refptr<MainThreadTaskQueue> RendererSchedulerImpl::kV8TaskQueue() {
+scoped_refptr<MainThreadTaskQueue> RendererSchedulerImpl::V8TaskQueue() {
   helper_.CheckOnValidThread();
   return v8_task_queue_;
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
index 2949feb..088216c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -185,7 +185,7 @@
   scoped_refptr<MainThreadTaskQueue> CompositorTaskQueue();
   scoped_refptr<MainThreadTaskQueue> LoadingTaskQueue();
   scoped_refptr<MainThreadTaskQueue> TimerTaskQueue();
-  scoped_refptr<MainThreadTaskQueue> kV8TaskQueue();
+  scoped_refptr<MainThreadTaskQueue> V8TaskQueue();
 
   // Returns a new task queue created with given params.
   scoped_refptr<MainThreadTaskQueue> NewTaskQueue(
@@ -369,7 +369,7 @@
     Policy()
         : rail_mode_(v8::PERFORMANCE_ANIMATION),
           should_disable_throttling_(false) {}
-    ~Policy() {}
+    ~Policy() = default;
 
     TaskQueuePolicy& compositor_queue_policy() {
       return policies_[static_cast<size_t>(
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index ef5bead..61770c9 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -272,7 +272,7 @@
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
-  ~RendererSchedulerImplTest() override {}
+  ~RendererSchedulerImplTest() override = default;
 
   void SetUp() override {
     if (!message_loop_) {
@@ -295,7 +295,7 @@
         MainThreadTaskQueue::QueueType::kFrameLoading_kControl);
     idle_task_runner_ = scheduler_->IdleTaskRunner();
     timer_task_runner_ = scheduler_->TimerTaskQueue();
-    v8_task_runner_ = scheduler_->kV8TaskQueue();
+    v8_task_runner_ = scheduler_->V8TaskQueue();
     fake_queue_ = scheduler_->NewLoadingTaskQueue(
         MainThreadTaskQueue::QueueType::kFrameLoading);
   }
@@ -2084,7 +2084,7 @@
  public:
   RendererSchedulerImplWithMessageLoopTest()
       : RendererSchedulerImplTest(new base::MessageLoop()) {}
-  ~RendererSchedulerImplWithMessageLoopTest() override {}
+  ~RendererSchedulerImplWithMessageLoopTest() override = default;
 
   void PostFromNestedRunloop(
       std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>*
@@ -3133,7 +3133,7 @@
  public:
   WebViewSchedulerImplForTest(RendererSchedulerImpl* scheduler)
       : WebViewSchedulerImpl(nullptr, nullptr, scheduler, false) {}
-  ~WebViewSchedulerImplForTest() override {}
+  ~WebViewSchedulerImplForTest() override = default;
 
   void ReportIntervention(const std::string& message) override {
     interventions_.push_back(message);
@@ -3778,7 +3778,7 @@
             scheduler_->GetVirtualTimeDomain());
   EXPECT_EQ(scheduler_->VirtualTimeControlTaskQueue()->GetTimeDomain(),
             scheduler_->GetVirtualTimeDomain());
-  EXPECT_EQ(scheduler_->kV8TaskQueue()->GetTimeDomain(),
+  EXPECT_EQ(scheduler_->V8TaskQueue()->GetTimeDomain(),
             scheduler_->GetVirtualTimeDomain());
 
   // The main control task queue remains in the real time domain.
@@ -3856,7 +3856,7 @@
             scheduler_->real_time_domain());
   EXPECT_EQ(scheduler_->ControlTaskQueue()->GetTimeDomain(),
             scheduler_->real_time_domain());
-  EXPECT_EQ(scheduler_->kV8TaskQueue()->GetTimeDomain(),
+  EXPECT_EQ(scheduler_->V8TaskQueue()->GetTimeDomain(),
             scheduler_->real_time_domain());
   EXPECT_FALSE(scheduler_->VirtualTimeControlTaskQueue());
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
index faaa7856..8cf84a5 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
@@ -21,13 +21,13 @@
                        renderer_scheduler->IdleTaskRunner(),
                        renderer_scheduler->LoadingTaskQueue(),
                        renderer_scheduler->TimerTaskQueue(),
-                       renderer_scheduler->kV8TaskQueue()),
+                       renderer_scheduler->V8TaskQueue()),
       renderer_scheduler_(renderer_scheduler),
       compositor_task_runner_(
           WebTaskRunnerImpl::Create(renderer_scheduler_->CompositorTaskQueue(),
                                     base::nullopt)) {}
 
-RendererWebSchedulerImpl::~RendererWebSchedulerImpl() {}
+RendererWebSchedulerImpl::~RendererWebSchedulerImpl() = default;
 
 WebTaskRunner* RendererWebSchedulerImpl::CompositorTaskRunner() {
   return compositor_task_runner_.get();
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc
index 1494839..df69a1f 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc
@@ -17,7 +17,7 @@
       outstanding_task_count_(0),
       estimation_percentile_(estimation_percentile) {}
 
-TaskCostEstimator::~TaskCostEstimator() {}
+TaskCostEstimator::~TaskCostEstimator() = default;
 
 void TaskCostEstimator::WillProcessTask(const base::PendingTask& pending_task) {
   // Avoid measuring the duration in nested run loops.
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc
index c3a6d3fe..5747c3e 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc
@@ -15,8 +15,8 @@
 
 class TaskCostEstimatorTest : public ::testing::Test {
  public:
-  TaskCostEstimatorTest() {}
-  ~TaskCostEstimatorTest() override {}
+  TaskCostEstimatorTest() = default;
+  ~TaskCostEstimatorTest() override = default;
 
   base::SimpleTestTickClock clock_;
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h
index 9d7cc850..006adf80 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h
@@ -47,7 +47,7 @@
 // Interface for BudgetPool to interact with TaskQueueThrottler.
 class PLATFORM_EXPORT BudgetPoolController {
  public:
-  virtual ~BudgetPoolController() {}
+  virtual ~BudgetPoolController() = default;
 
   // To be used by BudgetPool only, use BudgetPool::{Add,Remove}Queue
   // methods instead.
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
index 032b4eb..ffadea1 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
@@ -55,7 +55,7 @@
  public:
   AutoAdvancingTestClock(base::TimeDelta interval)
       : advancing_interval_(interval) {}
-  ~AutoAdvancingTestClock() override {}
+  ~AutoAdvancingTestClock() override = default;
 
   base::TimeTicks NowTicks() override {
     Advance(advancing_interval_);
@@ -72,8 +72,8 @@
 
 class TaskQueueThrottlerTest : public ::testing::Test {
  public:
-  TaskQueueThrottlerTest() {}
-  ~TaskQueueThrottlerTest() override {}
+  TaskQueueThrottlerTest() = default;
+  ~TaskQueueThrottlerTest() override = default;
 
   void SetUp() override {
     clock_ = CreateClock();
@@ -147,7 +147,7 @@
       : auto_advance_time_interval_(GetParam()
                                         ? base::TimeDelta::FromMicroseconds(1)
                                         : base::TimeDelta()) {}
-  ~TaskQueueThrottlerWithAutoAdvancingTimeTest() override {}
+  ~TaskQueueThrottlerWithAutoAdvancingTimeTest() override = default;
 
  protected:
   std::unique_ptr<AutoAdvancingTestClock> CreateClock() override {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
index 7c0aa57..b847534c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
@@ -9,7 +9,7 @@
 
 ThrottledTimeDomain::ThrottledTimeDomain() : RealTimeDomain() {}
 
-ThrottledTimeDomain::~ThrottledTimeDomain() {}
+ThrottledTimeDomain::~ThrottledTimeDomain() = default;
 
 const char* ThrottledTimeDomain::GetName() const {
   return "ThrottledTimeDomain";
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc b/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc
index 8868026..7d3a592 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc
@@ -11,7 +11,7 @@
     : pending_input_event_count_(0),
       is_gesture_active_(false),
       is_gesture_expected_(false) {}
-UserModel::~UserModel() {}
+UserModel::~UserModel() = default;
 
 void UserModel::DidStartProcessingInputEvent(blink::WebInputEvent::Type type,
                                              const base::TimeTicks now) {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc
index bfa2e34..49edc3f 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc
@@ -13,8 +13,8 @@
 
 class UserModelTest : public ::testing::Test {
  public:
-  UserModelTest() {}
-  ~UserModelTest() override {}
+  UserModelTest() = default;
+  ~UserModelTest() override = default;
 
   void SetUp() override {
     clock_.reset(new base::SimpleTestTickClock());
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/wake_up_budget_pool.cc b/third_party/WebKit/Source/platform/scheduler/renderer/wake_up_budget_pool.cc
index 0778f2a..2f4e8fef 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/wake_up_budget_pool.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/wake_up_budget_pool.cc
@@ -18,7 +18,7 @@
     : BudgetPool(name, budget_pool_controller),
       wake_up_interval_(base::TimeDelta::FromSecondsD(1.0)) {}
 
-WakeUpBudgetPool::~WakeUpBudgetPool() {}
+WakeUpBudgetPool::~WakeUpBudgetPool() = default;
 
 QueueBlockType WakeUpBudgetPool::GetBlockType() const {
   return QueueBlockType::kNewTasksOnly;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
index 03b5b68..aef0792 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
@@ -25,8 +25,8 @@
 
 class WebFrameSchedulerImplTest : public ::testing::Test {
  public:
-  WebFrameSchedulerImplTest() {}
-  ~WebFrameSchedulerImplTest() override {}
+  WebFrameSchedulerImplTest() = default;
+  ~WebFrameSchedulerImplTest() override = default;
 
   void SetUp() override {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h
index 6519f78..3ad498f 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h
@@ -18,13 +18,13 @@
  public:
   class PLATFORM_EXPORT WebViewSchedulerDelegate {
    public:
-    virtual ~WebViewSchedulerDelegate() {}
+    virtual ~WebViewSchedulerDelegate() = default;
 
     virtual void RequestBeginMainFrameNotExpected(bool new_state) = 0;
     virtual void SetPageStopped(bool) = 0;
   };
 
-  virtual ~WebViewScheduler() {}
+  virtual ~WebViewScheduler() = default;
 
   // The scheduler may throttle tasks associated with background pages.
   virtual void SetPageVisible(bool) = 0;
@@ -86,7 +86,7 @@
 
   class PLATFORM_EXPORT VirtualTimeObserver {
    public:
-    virtual ~VirtualTimeObserver() {}
+    virtual ~VirtualTimeObserver() = default;
 
     // Called when virtual time advances. |virtual_time_offset| is the offset
     // between the current virtual time and the initial virtual time when
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index 715bb09..46b7604 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -32,8 +32,8 @@
 
 class WebViewSchedulerImplTest : public ::testing::Test {
  public:
-  WebViewSchedulerImplTest() {}
-  ~WebViewSchedulerImplTest() override {}
+  WebViewSchedulerImplTest() = default;
+  ~WebViewSchedulerImplTest() override = default;
 
   void SetUp() override {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
@@ -390,8 +390,9 @@
 class WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling
     : public WebViewSchedulerImplTest {
  public:
-  WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() {}
-  ~WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() override {}
+  WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() = default;
+  ~WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() override =
+      default;
 
   bool DisableBackgroundTimerThrottling() const override { return true; }
 };
@@ -656,7 +657,7 @@
 namespace {
 class MockObserver : public WebViewScheduler::VirtualTimeObserver {
  public:
-  ~MockObserver() override {}
+  ~MockObserver() override = default;
 
   void OnVirtualTimeAdvanced(base::TimeDelta virtual_time_offset) override {
     virtual_time_log_.push_back(base::StringPrintf(
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
index 629b857..f6759c7e 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
@@ -23,7 +23,8 @@
       web_task_runner_(WebTaskRunnerImpl::Create(scheduler->DefaultTaskQueue(),
                                                  base::nullopt)) {}
 
-WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() {}
+WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() =
+    default;
 
 blink::PlatformThreadId WebThreadImplForRendererScheduler::ThreadId() const {
   return thread_id_;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
index 1683e13..14da1bbe 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
@@ -39,7 +39,7 @@
 
 class WebThreadImplForRendererSchedulerTest : public ::testing::Test {
  public:
-  WebThreadImplForRendererSchedulerTest() {}
+  WebThreadImplForRendererSchedulerTest() = default;
 
   void SetUp() override {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
@@ -50,7 +50,7 @@
     thread_ = scheduler_->CreateMainThread();
   }
 
-  ~WebThreadImplForRendererSchedulerTest() override {}
+  ~WebThreadImplForRendererSchedulerTest() override = default;
 
   void SetWorkBatchSizeForTesting(size_t work_batch_size) {
     scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(
diff --git a/third_party/WebKit/Source/platform/scheduler/test/create_task_queue_manager_for_test.cc b/third_party/WebKit/Source/platform/scheduler/test/create_task_queue_manager_for_test.cc
index 717dbaa1..ddc2dd4 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/create_task_queue_manager_for_test.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/create_task_queue_manager_for_test.cc
@@ -42,7 +42,7 @@
     ThreadControllerImpl::RemoveNestingObserver(observer);
   }
 
-  ~ThreadControllerForTest() override {}
+  ~ThreadControllerForTest() override = default;
 };
 
 }  // namespace
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
index 15db601..0c84bd30 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
@@ -12,9 +12,9 @@
 namespace blink {
 namespace scheduler {
 
-FakeRendererScheduler::FakeRendererScheduler() {}
+FakeRendererScheduler::FakeRendererScheduler() = default;
 
-FakeRendererScheduler::~FakeRendererScheduler() {}
+FakeRendererScheduler::~FakeRendererScheduler() = default;
 
 std::unique_ptr<blink::WebThread> FakeRendererScheduler::CreateMainThread() {
   return nullptr;
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h b/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h
index ed1e2f4..d0118da 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h
@@ -22,7 +22,7 @@
                                 MainThreadTaskQueue::QueueType::kTest)),
                             QueueCreationParams(queue_type),
                             nullptr) {}
-  ~MainThreadTaskQueueForTest() {}
+  ~MainThreadTaskQueueForTest() = default;
 };
 
 // A dummy WebFrameScheduler for tests.
@@ -49,11 +49,11 @@
         is_exempt_from_throttling_(is_exempt_from_throttling) {
     DCHECK(frame_type_ != FrameType::kMainFrame || !is_cross_origin);
   }
-  ~FakeWebFrameScheduler() override {}
+  ~FakeWebFrameScheduler() override = default;
 
   class Builder {
    public:
-    Builder() {}
+    Builder() = default;
 
     std::unique_ptr<FakeWebFrameScheduler> Build() {
       return std::make_unique<FakeWebFrameScheduler>(
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc
index 18e16dc9..1a5ca8b 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc
@@ -18,7 +18,7 @@
 
 class FakeWebTaskRunner::Data : public WTF::ThreadSafeRefCounted<Data> {
  public:
-  Data() {}
+  Data() = default;
 
   void PostDelayedTask(base::OnceClosure task, base::TimeDelta delay) {
     task_queue_.emplace_back(std::move(task), time_ + delay);
@@ -37,7 +37,7 @@
   base::TimeTicks time_;
 
  private:
-  ~Data() {}
+  ~Data() = default;
 
   friend ThreadSafeRefCounted<Data>;
   DISALLOW_COPY_AND_ASSIGN(Data);
@@ -48,8 +48,7 @@
 FakeWebTaskRunner::FakeWebTaskRunner(scoped_refptr<Data> data)
     : data_(std::move(data)) {}
 
-FakeWebTaskRunner::~FakeWebTaskRunner() {
-}
+FakeWebTaskRunner::~FakeWebTaskRunner() = default;
 
 void FakeWebTaskRunner::SetTime(base::TimeTicks new_time) {
   data_->time_ = new_time;
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_web_view_scheduler.h b/third_party/WebKit/Source/platform/scheduler/test/fake_web_view_scheduler.h
index 8e5e28c..91c2024 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_web_view_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_web_view_scheduler.h
@@ -18,7 +18,7 @@
 
   class Builder {
    public:
-    Builder() {}
+    Builder() = default;
 
     Builder& SetIsPlayingAudio(bool is_playing_audio) {
       is_playing_audio_ = is_playing_audio;
diff --git a/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc b/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc
index 1785d3e4..e83032ad 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc
@@ -20,7 +20,7 @@
     task_runner_ = message_loop_->task_runner();
 }
 
-LazyThreadControllerForTest::~LazyThreadControllerForTest() {}
+LazyThreadControllerForTest::~LazyThreadControllerForTest() = default;
 
 void LazyThreadControllerForTest::EnsureMessageLoop() {
   if (message_loop_)
diff --git a/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc
index 51c5ec5..b531f80 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/test_task_queue.cc
@@ -14,7 +14,7 @@
     : TaskQueue(std::move(impl), spec),
       weak_factory_(this) {}
 
-TestTaskQueue::~TestTaskQueue() {}
+TestTaskQueue::~TestTaskQueue() = default;
 
 base::WeakPtr<TestTaskQueue> TestTaskQueue::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
diff --git a/third_party/WebKit/Source/platform/scheduler/util/task_duration_metric_reporter.h b/third_party/WebKit/Source/platform/scheduler/util/task_duration_metric_reporter.h
index 87b3bca..1fa8f59 100644
--- a/third_party/WebKit/Source/platform/scheduler/util/task_duration_metric_reporter.h
+++ b/third_party/WebKit/Source/platform/scheduler/util/task_duration_metric_reporter.h
@@ -36,7 +36,7 @@
             static_cast<int>(TaskClass::kCount) + 1,
             base::HistogramBase::kUmaTargetedHistogramFlag)) {}
 
-  ~TaskDurationMetricReporter() {}
+  ~TaskDurationMetricReporter() = default;
 
   void RecordTask(TaskClass task_class, base::TimeDelta duration) {
     DCHECK_LT(static_cast<int>(task_class),
diff --git a/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.cc b/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.cc
index d0a9e84..d3baa7a 100644
--- a/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.cc
+++ b/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.cc
@@ -20,7 +20,7 @@
   next_reporting_time_ = now + reporting_interval_;
 }
 
-ThreadLoadTracker::~ThreadLoadTracker() {}
+ThreadLoadTracker::~ThreadLoadTracker() = default;
 
 void ThreadLoadTracker::Pause(base::TimeTicks now) {
   Advance(now, TaskState::kIdle);
diff --git a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
index 177f420c..0b6454e3 100644
--- a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
+++ b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
@@ -13,7 +13,7 @@
     : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       thread_id_(base::PlatformThread::CurrentId()) {}
 
-WebThreadImplForUtilityThread::~WebThreadImplForUtilityThread() {}
+WebThreadImplForUtilityThread::~WebThreadImplForUtilityThread() = default;
 
 blink::WebScheduler* WebThreadImplForUtilityThread::Scheduler() const {
   NOTIMPLEMENTED();
diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp
index c03ccb7..eb84d39 100644
--- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp
@@ -21,7 +21,7 @@
     ScrollableArea* scrollable_area)
     : scrollable_area_(scrollable_area), start_time_(0.0) {}
 
-ProgrammaticScrollAnimator::~ProgrammaticScrollAnimator() {}
+ProgrammaticScrollAnimator::~ProgrammaticScrollAnimator() = default;
 
 void ProgrammaticScrollAnimator::ResetAnimationState() {
   ScrollAnimatorCompositorCoordinator::ResetAnimationState();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
index d34a365c..0382090 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
@@ -66,7 +66,7 @@
       time_function_(time_function),
       last_granularity_(kScrollByPixel) {}
 
-ScrollAnimator::~ScrollAnimator() {}
+ScrollAnimator::~ScrollAnimator() = default;
 
 ScrollOffset ScrollAnimator::DesiredTargetOffset() const {
   if (run_state_ == RunState::kWaitingToCancelOnCompositor)
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp
index 84b99cf3..b67d962e 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp
@@ -38,7 +38,7 @@
 ScrollAnimatorBase::ScrollAnimatorBase(ScrollableArea* scrollable_area)
     : scrollable_area_(scrollable_area) {}
 
-ScrollAnimatorBase::~ScrollAnimatorBase() {}
+ScrollAnimatorBase::~ScrollAnimatorBase() = default;
 
 ScrollOffset ScrollAnimatorBase::ComputeDeltaToConsume(
     const ScrollOffset& delta) const {
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
index e9896166..bc1fc2cb 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
@@ -30,7 +30,8 @@
   compositor_player_->SetAnimationDelegate(this);
 }
 
-ScrollAnimatorCompositorCoordinator::~ScrollAnimatorCompositorCoordinator() {}
+ScrollAnimatorCompositorCoordinator::~ScrollAnimatorCompositorCoordinator() =
+    default;
 
 void ScrollAnimatorCompositorCoordinator::Dispose() {
   compositor_player_->SetAnimationDelegate(nullptr);
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp
index 80d3281..48b30e22 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp
@@ -150,7 +150,7 @@
   TestScrollAnimator(ScrollableArea* scrollable_area,
                      WTF::TimeFunction timing_function)
       : ScrollAnimator(scrollable_area, timing_function) {}
-  ~TestScrollAnimator() override {}
+  ~TestScrollAnimator() override = default;
 
   void SetShouldSendToCompositor(bool send) {
     should_send_to_compositor_ = send;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
index 1d6e9b0..c8efae9 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -70,7 +70,7 @@
       mouse_over_scrollbar_(false),
       needs_show_scrollbar_layers_(false) {}
 
-ScrollableArea::~ScrollableArea() {}
+ScrollableArea::~ScrollableArea() = default;
 
 void ScrollableArea::ClearScrollableArea() {
 #if defined(OS_MACOSX)
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
index 8cb0a49..8a7ad06 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
@@ -44,8 +44,8 @@
   USING_FAST_MALLOC(ScrollbarTheme);
 
  public:
-  ScrollbarTheme() {}
-  virtual ~ScrollbarTheme() {}
+  ScrollbarTheme() = default;
+  virtual ~ScrollbarTheme() = default;
 
   // If true, then scrollbars with this theme will be painted every time
   // Scrollbar::setNeedsPaintInvalidation is called. If false, then only parts
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h
index b6bc8f1..189c250 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeClient.h
@@ -82,7 +82,7 @@
   virtual void SetElasticOverscroll(float) = 0;
 
  protected:
-  virtual ~ScrollbarThemeClient() {}
+  virtual ~ScrollbarThemeClient() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h
index d39e290..277aa872 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeOverlay.h
@@ -44,7 +44,7 @@
                         int scrollbar_margin,
                         HitTestBehavior,
                         Color);
-  ~ScrollbarThemeOverlay() override {}
+  ~ScrollbarThemeOverlay() override = default;
 
   bool ShouldRepaintAllPartsOnInvalidation() const override;
 
diff --git a/third_party/WebKit/Source/platform/scroll/SmoothScrollSequencer.h b/third_party/WebKit/Source/platform/scroll/SmoothScrollSequencer.h
index 3c1ac41..da497ea 100644
--- a/third_party/WebKit/Source/platform/scroll/SmoothScrollSequencer.h
+++ b/third_party/WebKit/Source/platform/scroll/SmoothScrollSequencer.h
@@ -40,7 +40,7 @@
 class PLATFORM_EXPORT SmoothScrollSequencer final
     : public GarbageCollected<SmoothScrollSequencer> {
  public:
-  SmoothScrollSequencer() {}
+  SmoothScrollSequencer() = default;
   // Add a scroll offset animation to the back of a queue.
   void QueueAnimation(ScrollableArea*, ScrollOffset, ScrollBehavior);
 
diff --git a/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesisUtterance.h b/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesisUtterance.h
index a5c4b5d0..33423900 100644
--- a/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesisUtterance.h
+++ b/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesisUtterance.h
@@ -38,7 +38,7 @@
  public:
   // Implement methods as needed.
  protected:
-  virtual ~PlatformSpeechSynthesisUtteranceClient() {}
+  virtual ~PlatformSpeechSynthesisUtteranceClient() = default;
 };
 
 class PLATFORM_EXPORT PlatformSpeechSynthesisUtterance final
diff --git a/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesizer.cpp b/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesizer.cpp
index a3f8907..c278930 100644
--- a/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesizer.cpp
+++ b/third_party/WebKit/Source/platform/speech/PlatformSpeechSynthesizer.cpp
@@ -52,7 +52,7 @@
       web_speech_synthesizer_client_);
 }
 
-PlatformSpeechSynthesizer::~PlatformSpeechSynthesizer() {}
+PlatformSpeechSynthesizer::~PlatformSpeechSynthesizer() = default;
 
 void PlatformSpeechSynthesizer::Speak(
     PlatformSpeechSynthesisUtterance* utterance) {
diff --git a/third_party/WebKit/Source/platform/testing/ArenaTestHelpers.h b/third_party/WebKit/Source/platform/testing/ArenaTestHelpers.h
index 63a7d4d..d7df5409 100644
--- a/third_party/WebKit/Source/platform/testing/ArenaTestHelpers.h
+++ b/third_party/WebKit/Source/platform/testing/ArenaTestHelpers.h
@@ -61,7 +61,7 @@
   int NumRegions() const { return allocated_regions_.size(); }
 
  private:
-  TrackedAllocator() {}
+  TrackedAllocator() = default;
   Vector<void*> allocated_regions_;
 };
 
diff --git a/third_party/WebKit/Source/platform/testing/CompositorTest.cpp b/third_party/WebKit/Source/platform/testing/CompositorTest.cpp
index 5f2078eb..547d81f 100644
--- a/third_party/WebKit/Source/platform/testing/CompositorTest.cpp
+++ b/third_party/WebKit/Source/platform/testing/CompositorTest.cpp
@@ -9,6 +9,6 @@
 CompositorTest::CompositorTest()
     : runner_(new base::TestMockTimeTaskRunner), runner_handle_(runner_) {}
 
-CompositorTest::~CompositorTest() {}
+CompositorTest::~CompositorTest() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/testing/EmptyWebMediaPlayer.h b/third_party/WebKit/Source/platform/testing/EmptyWebMediaPlayer.h
index b9f9f6a1..2e4eaaab 100644
--- a/third_party/WebKit/Source/platform/testing/EmptyWebMediaPlayer.h
+++ b/third_party/WebKit/Source/platform/testing/EmptyWebMediaPlayer.h
@@ -14,7 +14,7 @@
 // they don't care their behavior.
 class EmptyWebMediaPlayer : public WebMediaPlayer {
  public:
-  ~EmptyWebMediaPlayer() override {}
+  ~EmptyWebMediaPlayer() override = default;
 
   void Load(LoadType, const WebMediaPlayerSource&, CORSMode) override {}
   void Play() override {}
diff --git a/third_party/WebKit/Source/platform/testing/FontTestHelpers.cpp b/third_party/WebKit/Source/platform/testing/FontTestHelpers.cpp
index 5d67380..c8b57a8 100644
--- a/third_party/WebKit/Source/platform/testing/FontTestHelpers.cpp
+++ b/third_party/WebKit/Source/platform/testing/FontTestHelpers.cpp
@@ -25,7 +25,7 @@
         FontCustomPlatformData::Create(font_buffer.get(), ots_parse_message));
   }
 
-  ~TestFontSelector() override {}
+  ~TestFontSelector() override = default;
 
   scoped_refptr<FontData> GetFontData(
       const FontDescription& font_description,
diff --git a/third_party/WebKit/Source/platform/testing/HistogramTester.cpp b/third_party/WebKit/Source/platform/testing/HistogramTester.cpp
index 3b08e83..5e71075 100644
--- a/third_party/WebKit/Source/platform/testing/HistogramTester.cpp
+++ b/third_party/WebKit/Source/platform/testing/HistogramTester.cpp
@@ -12,7 +12,7 @@
 HistogramTester::HistogramTester()
     : histogram_tester_(WTF::WrapUnique(new base::HistogramTester)) {}
 
-HistogramTester::~HistogramTester() {}
+HistogramTester::~HistogramTester() = default;
 
 void HistogramTester::ExpectUniqueSample(
     const std::string& name,
diff --git a/third_party/WebKit/Source/platform/testing/MockWebCrypto.h b/third_party/WebKit/Source/platform/testing/MockWebCrypto.h
index 309aa038..edbc01fa 100644
--- a/third_party/WebKit/Source/platform/testing/MockWebCrypto.h
+++ b/third_party/WebKit/Source/platform/testing/MockWebCrypto.h
@@ -15,7 +15,7 @@
 
 class MockWebCrypto : public WebCrypto {
  public:
-  ~MockWebCrypto() override {}
+  ~MockWebCrypto() override = default;
 
   static std::unique_ptr<MockWebCrypto> Create() {
     return std::unique_ptr<MockWebCrypto>(
@@ -102,7 +102,7 @@
                bool(const WebCryptoKey&, WebVector<unsigned char>&));
 
  protected:
-  MockWebCrypto() {}
+  MockWebCrypto() = default;
 
   std::unique_ptr<WebCryptoDigestor> CreateDigestor(
       WebCryptoAlgorithmId id) override {
@@ -114,7 +114,7 @@
 
 class MockWebCryptoDigestor : public WebCryptoDigestor {
  public:
-  ~MockWebCryptoDigestor() override {}
+  ~MockWebCryptoDigestor() override = default;
 
   static MockWebCryptoDigestor* Create() {
     return new ::testing::StrictMock<MockWebCryptoDigestor>();
@@ -129,7 +129,7 @@
   MOCK_METHOD2(Finish, bool(unsigned char*&, unsigned&));
 
  protected:
-  MockWebCryptoDigestor() {}
+  MockWebCryptoDigestor() = default;
 
   DISALLOW_COPY_AND_ASSIGN(MockWebCryptoDigestor);
 };
diff --git a/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp b/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
index f93f859..013b593e 100644
--- a/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
@@ -41,7 +41,7 @@
 
 TestPaintArtifact::TestPaintArtifact() : display_item_list_(0), built_(false) {}
 
-TestPaintArtifact::~TestPaintArtifact() {}
+TestPaintArtifact::~TestPaintArtifact() = default;
 
 TestPaintArtifact& TestPaintArtifact::Chunk(
     scoped_refptr<const TransformPaintPropertyNode> transform,
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
index a4c3db14..9c4cc18 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -206,7 +206,7 @@
 class ScopedUnittestsEnvironmentSetup::DummyPlatform final
     : public blink::Platform {
  public:
-  DummyPlatform() {}
+  DummyPlatform() = default;
 
   blink::WebThread* CurrentThread() override {
     static DummyThread dummy_thread;
@@ -261,6 +261,6 @@
   WebRuntimeFeatures::EnableTestOnlyFeatures(true);
 }
 
-ScopedUnittestsEnvironmentSetup::~ScopedUnittestsEnvironmentSetup() {}
+ScopedUnittestsEnvironmentSetup::~ScopedUnittestsEnvironmentSetup() = default;
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithWebRTC.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithWebRTC.cpp
index 7dc21692..2a0c5b6 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithWebRTC.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithWebRTC.cpp
@@ -13,9 +13,9 @@
 
 namespace blink {
 
-MockWebRTCPeerConnectionHandler::MockWebRTCPeerConnectionHandler() {}
+MockWebRTCPeerConnectionHandler::MockWebRTCPeerConnectionHandler() = default;
 
-MockWebRTCPeerConnectionHandler::~MockWebRTCPeerConnectionHandler() {}
+MockWebRTCPeerConnectionHandler::~MockWebRTCPeerConnectionHandler() = default;
 
 bool MockWebRTCPeerConnectionHandler::Initialize(const WebRTCConfiguration&,
                                                  const WebMediaConstraints&) {
diff --git a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
index 71b172a..04bcefe2 100644
--- a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
+++ b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
@@ -34,7 +34,7 @@
   DCHECK(layer_tree_host_);
 }
 
-WebLayerTreeViewImplForTesting::~WebLayerTreeViewImplForTesting() {}
+WebLayerTreeViewImplForTesting::~WebLayerTreeViewImplForTesting() = default;
 
 // static
 cc::LayerTreeSettings
diff --git a/third_party/WebKit/Source/platform/testing/weburl_loader_mock_factory_impl.cc b/third_party/WebKit/Source/platform/testing/weburl_loader_mock_factory_impl.cc
index 761f5131..49384af 100644
--- a/third_party/WebKit/Source/platform/testing/weburl_loader_mock_factory_impl.cc
+++ b/third_party/WebKit/Source/platform/testing/weburl_loader_mock_factory_impl.cc
@@ -31,7 +31,7 @@
     TestingPlatformSupport* platform)
     : platform_(platform) {}
 
-WebURLLoaderMockFactoryImpl::~WebURLLoaderMockFactoryImpl() {}
+WebURLLoaderMockFactoryImpl::~WebURLLoaderMockFactoryImpl() = default;
 
 std::unique_ptr<WebURLLoader> WebURLLoaderMockFactoryImpl::CreateURLLoader(
     std::unique_ptr<WebURLLoader> default_loader) {
diff --git a/third_party/WebKit/Source/platform/text/DateTimeFormatTest.cpp b/third_party/WebKit/Source/platform/text/DateTimeFormatTest.cpp
index ceb80f45..76e2386 100644
--- a/third_party/WebKit/Source/platform/text/DateTimeFormatTest.cpp
+++ b/third_party/WebKit/Source/platform/text/DateTimeFormatTest.cpp
@@ -74,7 +74,7 @@
 
   class Tokens {
    public:
-    Tokens() {}
+    Tokens() = default;
 
     explicit Tokens(const Vector<Token> tokens) : tokens_(tokens) {}
 
@@ -167,7 +167,7 @@
  private:
   class TokenHandler : public DateTimeFormat::TokenHandler {
    public:
-    ~TokenHandler() override {}
+    ~TokenHandler() override = default;
 
     FieldType GetFieldType(int index) const {
       return index >= 0 && index < static_cast<int>(tokens_.size())
diff --git a/third_party/WebKit/Source/platform/text/Hyphenation.h b/third_party/WebKit/Source/platform/text/Hyphenation.h
index 9b2739b..df999a3 100644
--- a/third_party/WebKit/Source/platform/text/Hyphenation.h
+++ b/third_party/WebKit/Source/platform/text/Hyphenation.h
@@ -18,7 +18,7 @@
 
 class PLATFORM_EXPORT Hyphenation : public RefCounted<Hyphenation> {
  public:
-  virtual ~Hyphenation() {}
+  virtual ~Hyphenation() = default;
 
   // Find the last hyphenation location before |before_index|.
   // Returns 0 if no hyphenation locations were found.
diff --git a/third_party/WebKit/Source/platform/text/LineEnding.cpp b/third_party/WebKit/Source/platform/text/LineEnding.cpp
index 2f4a46d9..d823aa8 100644
--- a/third_party/WebKit/Source/platform/text/LineEnding.cpp
+++ b/third_party/WebKit/Source/platform/text/LineEnding.cpp
@@ -45,16 +45,16 @@
   WTF_MAKE_NONCOPYABLE(OutputBuffer);
 
  public:
-  OutputBuffer() {}
+  OutputBuffer() = default;
   virtual char* Allocate(size_t) = 0;
   virtual void Copy(const CString&) = 0;
-  virtual ~OutputBuffer() {}
+  virtual ~OutputBuffer() = default;
 };
 
 class CStringBuffer final : public OutputBuffer {
  public:
   CStringBuffer(CString& buffer) : buffer_(buffer) {}
-  ~CStringBuffer() override {}
+  ~CStringBuffer() override = default;
 
   char* Allocate(size_t size) override {
     char* ptr;
@@ -73,7 +73,7 @@
 class VectorCharAppendBuffer final : public OutputBuffer {
  public:
   VectorCharAppendBuffer(Vector<char>& buffer) : buffer_(buffer) {}
-  ~VectorCharAppendBuffer() override {}
+  ~VectorCharAppendBuffer() override = default;
 
   char* Allocate(size_t size) override {
     size_t old_size = buffer_.size();
diff --git a/third_party/WebKit/Source/platform/text/PlatformLocale.cpp b/third_party/WebKit/Source/platform/text/PlatformLocale.cpp
index 3771fff2..4667b19 100644
--- a/third_party/WebKit/Source/platform/text/PlatformLocale.cpp
+++ b/third_party/WebKit/Source/platform/text/PlatformLocale.cpp
@@ -195,7 +195,7 @@
   g_default_locale = nullptr;
 }
 
-Locale::~Locale() {}
+Locale::~Locale() = default;
 
 String Locale::QueryString(WebLocalizedString::Name name) {
   // FIXME: Returns a string locazlied for this locale.
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIteratorICU.cpp b/third_party/WebKit/Source/platform/text/TextBreakIteratorICU.cpp
index d20c9fe..a2fd111 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIteratorICU.cpp
+++ b/third_party/WebKit/Source/platform/text/TextBreakIteratorICU.cpp
@@ -26,6 +26,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "platform/text/ICUError.h"
 #include "platform/text/TextBreakIteratorInternalICU.h"
 #include "platform/wtf/Assertions.h"
 #include "platform/wtf/HashMap.h"
@@ -780,12 +781,14 @@
       iterator_ &&
       CompareAndSwapNonSharedCharacterBreakIterator(iterator_, nullptr);
   if (!created_iterator) {
-    UErrorCode error_code = U_ZERO_ERROR;
+    ICUError error_code;
     iterator_ = icu::BreakIterator::createCharacterInstance(
         icu::Locale(CurrentTextBreakLocaleID()), error_code);
-    DCHECK(U_SUCCESS(error_code))
+    CHECK(U_SUCCESS(error_code) && iterator_)
         << "ICU could not open a break iterator: " << u_errorName(error_code)
         << " (" << error_code << ")";
+  } else {
+    CHECK(iterator_);
   }
 
   SetText16(iterator_, buffer, length);
diff --git a/third_party/WebKit/Source/platform/transforms/IdentityTransformOperation.h b/third_party/WebKit/Source/platform/transforms/IdentityTransformOperation.h
index 8e428ba6f..66e2ff8 100644
--- a/third_party/WebKit/Source/platform/transforms/IdentityTransformOperation.h
+++ b/third_party/WebKit/Source/platform/transforms/IdentityTransformOperation.h
@@ -58,7 +58,7 @@
 
   scoped_refptr<TransformOperation> Zoom(double factor) final { return this; }
 
-  IdentityTransformOperation() {}
+  IdentityTransformOperation() = default;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/transforms/TransformOperation.h b/third_party/WebKit/Source/platform/transforms/TransformOperation.h
index c0750def..776b66fe 100644
--- a/third_party/WebKit/Source/platform/transforms/TransformOperation.h
+++ b/third_party/WebKit/Source/platform/transforms/TransformOperation.h
@@ -67,8 +67,8 @@
     kRotateAroundOrigin,
   };
 
-  TransformOperation() {}
-  virtual ~TransformOperation() {}
+  TransformOperation() = default;
+  virtual ~TransformOperation() = default;
 
   virtual bool operator==(const TransformOperation&) const = 0;
   bool operator!=(const TransformOperation& o) const { return !(*this == o); }
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.cpp b/third_party/WebKit/Source/platform/weborigin/KURL.cpp
index 82f21b46..3b3c82fe 100644
--- a/third_party/WebKit/Source/platform/weborigin/KURL.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/KURL.cpp
@@ -262,7 +262,7 @@
     inner_url_ = WTF::WrapUnique(new KURL(other.inner_url_->Copy()));
 }
 
-KURL::~KURL() {}
+KURL::~KURL() = default;
 
 KURL& KURL::operator=(const KURL& other) {
   is_valid_ = other.is_valid_;
diff --git a/third_party/WebKit/Source/platform/weborigin/ReportingServiceProxyPtrHolder.h b/third_party/WebKit/Source/platform/weborigin/ReportingServiceProxyPtrHolder.h
index e0efe44..afa61b13 100644
--- a/third_party/WebKit/Source/platform/weborigin/ReportingServiceProxyPtrHolder.h
+++ b/third_party/WebKit/Source/platform/weborigin/ReportingServiceProxyPtrHolder.h
@@ -18,7 +18,7 @@
     Platform::Current()->GetInterfaceProvider()->GetInterface(
         mojo::MakeRequest(&reporting_service_proxy));
   }
-  ~ReportingServiceProxyPtrHolder() {}
+  ~ReportingServiceProxyPtrHolder() = default;
 
   void QueueInterventionReport(const KURL& url,
                                const String& message,
diff --git a/third_party/WebKit/Source/platform/weborigin/URLSecurityOriginMap.h b/third_party/WebKit/Source/platform/weborigin/URLSecurityOriginMap.h
index ceae170..46626f0 100644
--- a/third_party/WebKit/Source/platform/weborigin/URLSecurityOriginMap.h
+++ b/third_party/WebKit/Source/platform/weborigin/URLSecurityOriginMap.h
@@ -44,8 +44,8 @@
   WTF_MAKE_NONCOPYABLE(URLSecurityOriginMap);
 
  public:
-  URLSecurityOriginMap() {}
-  virtual ~URLSecurityOriginMap() {}
+  URLSecurityOriginMap() = default;
+  virtual ~URLSecurityOriginMap() = default;
   virtual SecurityOrigin* GetOrigin(const KURL&) = 0;
 };
 
diff --git a/third_party/WebKit/Source/platform/wtf/Deque.h b/third_party/WebKit/Source/platform/wtf/Deque.h
index b8f158c..f82b1455 100644
--- a/third_party/WebKit/Source/platform/wtf/Deque.h
+++ b/third_party/WebKit/Source/platform/wtf/Deque.h
@@ -625,7 +625,8 @@
 }
 
 template <typename T, size_t inlineCapacity, typename Allocator>
-inline DequeIteratorBase<T, inlineCapacity, Allocator>::~DequeIteratorBase() {}
+inline DequeIteratorBase<T, inlineCapacity, Allocator>::~DequeIteratorBase() =
+    default;
 
 template <typename T, size_t inlineCapacity, typename Allocator>
 inline bool DequeIteratorBase<T, inlineCapacity, Allocator>::IsEqual(
diff --git a/third_party/WebKit/Source/platform/wtf/Functional.h b/third_party/WebKit/Source/platform/wtf/Functional.h
index b42729e..61f3682d 100644
--- a/third_party/WebKit/Source/platform/wtf/Functional.h
+++ b/third_party/WebKit/Source/platform/wtf/Functional.h
@@ -301,7 +301,7 @@
   USING_FAST_MALLOC(CrossThreadFunction);
 
  public:
-  CrossThreadFunction() {}
+  CrossThreadFunction() = default;
   explicit CrossThreadFunction(base::Callback<R(Args...)> callback)
       : callback_(std::move(callback)) {}
   ~CrossThreadFunction() = default;
diff --git a/third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp b/third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp
index 2ad3e32c..9c087dc3 100644
--- a/third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/FunctionalTest.cpp
@@ -72,7 +72,7 @@
 class A {
  public:
   explicit A(int i) : i_(i) {}
-  virtual ~A() {}
+  virtual ~A() = default;
 
   int F() { return i_; }
   int AddF(int j) { return i_ + j; }
diff --git a/third_party/WebKit/Source/platform/wtf/HashIterators.h b/third_party/WebKit/Source/platform/wtf/HashIterators.h
index 97448e0a..31cce4e 100644
--- a/third_party/WebKit/Source/platform/wtf/HashIterators.h
+++ b/third_party/WebKit/Source/platform/wtf/HashIterators.h
@@ -53,7 +53,7 @@
   typedef HashTableConstValuesIterator<HashTableType, KeyType, MappedType>
       ValuesIterator;
 
-  HashTableConstIteratorAdapter() {}
+  HashTableConstIteratorAdapter() = default;
   HashTableConstIteratorAdapter(
       const typename HashTableType::const_iterator& impl)
       : impl_(impl) {}
@@ -88,7 +88,7 @@
   typedef HashTableValuesIterator<HashTableType, KeyType, MappedType>
       ValuesIterator;
 
-  HashTableIteratorAdapter() {}
+  HashTableIteratorAdapter() = default;
   HashTableIteratorAdapter(const typename HashTableType::iterator& impl)
       : impl_(impl) {}
 
diff --git a/third_party/WebKit/Source/platform/wtf/HashMap.h b/third_party/WebKit/Source/platform/wtf/HashMap.h
index b014528..ef2661203 100644
--- a/third_party/WebKit/Source/platform/wtf/HashMap.h
+++ b/third_party/WebKit/Source/platform/wtf/HashMap.h
@@ -245,11 +245,10 @@
  private:
   friend class HashMap;
 
-  // These are intentionally not implemented.
-  HashMapKeysProxy();
-  HashMapKeysProxy(const HashMapKeysProxy&);
-  HashMapKeysProxy& operator=(const HashMapKeysProxy&);
-  ~HashMapKeysProxy();
+  HashMapKeysProxy() = delete;
+  HashMapKeysProxy(const HashMapKeysProxy&) = delete;
+  HashMapKeysProxy& operator=(const HashMapKeysProxy&) = delete;
+  ~HashMapKeysProxy() = delete;
 };
 
 template <typename KeyArg,
@@ -293,11 +292,10 @@
  private:
   friend class HashMap;
 
-  // These are intentionally not implemented.
-  HashMapValuesProxy();
-  HashMapValuesProxy(const HashMapValuesProxy&);
-  HashMapValuesProxy& operator=(const HashMapValuesProxy&);
-  ~HashMapValuesProxy();
+  HashMapValuesProxy() = delete;
+  HashMapValuesProxy(const HashMapValuesProxy&) = delete;
+  HashMapValuesProxy& operator=(const HashMapValuesProxy&) = delete;
+  ~HashMapValuesProxy() = delete;
 };
 
 template <typename KeyTraits, typename MappedTraits>
diff --git a/third_party/WebKit/Source/platform/wtf/HashTable.h b/third_party/WebKit/Source/platform/wtf/HashTable.h
index b337742..d76a78b 100644
--- a/third_party/WebKit/Source/platform/wtf/HashTable.h
+++ b/third_party/WebKit/Source/platform/wtf/HashTable.h
@@ -335,7 +335,7 @@
   }
 
  public:
-  HashTableConstIterator() {}
+  HashTableConstIterator() = default;
 
   GetType Get() const {
     CheckModifications();
@@ -463,7 +463,7 @@
       : iterator_(pos, end, container, tag) {}
 
  public:
-  HashTableIterator() {}
+  HashTableIterator() = default;
 
   // default copy, assignment and destructor are OK
 
@@ -2181,7 +2181,7 @@
 template <typename HashTableType, typename Traits>
 struct HashTableConstIteratorAdapter {
   STACK_ALLOCATED();
-  HashTableConstIteratorAdapter() {}
+  HashTableConstIteratorAdapter() = default;
   HashTableConstIteratorAdapter(
       const typename HashTableType::const_iterator& impl)
       : impl_(impl) {}
@@ -2219,7 +2219,7 @@
   typedef typename Traits::IteratorGetType GetType;
   typedef typename HashTableType::ValueTraits::IteratorGetType SourceGetType;
 
-  HashTableIteratorAdapter() {}
+  HashTableIteratorAdapter() = default;
   HashTableIteratorAdapter(const typename HashTableType::iterator& impl)
       : impl_(impl) {}
 
diff --git a/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h b/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h
index a664690..89d33135 100644
--- a/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h
+++ b/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h
@@ -133,7 +133,7 @@
 
  private:
   // Should not be used.
-  LinkedHashSetNodeBase& operator=(const LinkedHashSetNodeBase& other);
+  LinkedHashSetNodeBase& operator=(const LinkedHashSetNodeBase& other) = delete;
 };
 
 template <typename ValueArg, typename Allocator>
diff --git a/third_party/WebKit/Source/platform/wtf/ListHashSet.h b/third_party/WebKit/Source/platform/wtf/ListHashSet.h
index 7b3f79e4..95b2bb0b 100644
--- a/third_party/WebKit/Source/platform/wtf/ListHashSet.h
+++ b/third_party/WebKit/Source/platform/wtf/ListHashSet.h
@@ -514,7 +514,7 @@
       : iterator_(set, position) {}
 
  public:
-  ListHashSetIterator() {}
+  ListHashSetIterator() = default;
 
   // default copy, assignment and destructor are OK
 
@@ -574,7 +574,7 @@
       : set_(set), position_(position) {}
 
  public:
-  ListHashSetConstIterator() {}
+  ListHashSetConstIterator() = default;
 
   PointerType Get() const { return &position_->value_; }
   ReferenceType operator*() const { return *Get(); }
@@ -636,7 +636,7 @@
       : iterator_(set, position) {}
 
  public:
-  ListHashSetReverseIterator() {}
+  ListHashSetReverseIterator() = default;
 
   // default copy, assignment and destructor are OK
 
@@ -696,7 +696,7 @@
       : set_(set), position_(position) {}
 
  public:
-  ListHashSetConstReverseIterator() {}
+  ListHashSetConstReverseIterator() = default;
 
   PointerType Get() const { return &position_->value_; }
   ReferenceType operator*() const { return *Get(); }
diff --git a/third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp b/third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp
index 6df2301..612a24dc 100644
--- a/third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/ListHashSetTest.cpp
@@ -497,7 +497,7 @@
   static int objects_constructed_;
 
  private:
-  Complicated();
+  Complicated() = delete;
 };
 
 int Complicated::objects_constructed_ = 0;
diff --git a/third_party/WebKit/Source/platform/wtf/PrintStream.cpp b/third_party/WebKit/Source/platform/wtf/PrintStream.cpp
index 04ea32b..86ca3b28 100644
--- a/third_party/WebKit/Source/platform/wtf/PrintStream.cpp
+++ b/third_party/WebKit/Source/platform/wtf/PrintStream.cpp
@@ -31,8 +31,8 @@
 
 namespace WTF {
 
-PrintStream::PrintStream() {}
-PrintStream::~PrintStream() {}  // Force the vtable to be in this module
+PrintStream::PrintStream() = default;
+PrintStream::~PrintStream() = default;  // Force the vtable to be in this module
 
 void PrintStream::Printf(const char* format, ...) {
   va_list arg_list;
diff --git a/third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp b/third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp
index 9c378eef..2ffc01a 100644
--- a/third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/RefPtrTest.cpp
@@ -50,7 +50,7 @@
 
  private:
   friend struct Deleter;
-  ~CustomDeleter() {}
+  ~CustomDeleter() = default;
 
   bool* deleted_;
 };
@@ -83,7 +83,7 @@
 
  private:
   friend struct DeleterThreadSafe;
-  ~CustomDeleterThreadSafe() {}
+  ~CustomDeleterThreadSafe() = default;
 
   bool* deleted_;
 };
diff --git a/third_party/WebKit/Source/platform/wtf/RefVector.h b/third_party/WebKit/Source/platform/wtf/RefVector.h
index 49c5d75e..d4f5e516 100644
--- a/third_party/WebKit/Source/platform/wtf/RefVector.h
+++ b/third_party/WebKit/Source/platform/wtf/RefVector.h
@@ -42,7 +42,7 @@
 
  private:
   Vector<T> vector_;
-  RefVector() {}
+  RefVector() = default;
   RefVector(const Vector<T>& vector) : vector_(vector) {}
   RefVector(Vector<T>&& vector) : vector_(vector) {}
 };
diff --git a/third_party/WebKit/Source/platform/wtf/TerminatedArray.h b/third_party/WebKit/Source/platform/wtf/TerminatedArray.h
index ea368adb..147645e 100644
--- a/third_party/WebKit/Source/platform/wtf/TerminatedArray.h
+++ b/third_party/WebKit/Source/platform/wtf/TerminatedArray.h
@@ -115,7 +115,7 @@
 
   // Prohibit construction. Allocator makes TerminatedArray instances for
   // TerminatedArrayBuilder by pointer casting.
-  TerminatedArray();
+  TerminatedArray() = delete;
 
   template <typename, template <typename> class>
   friend class TerminatedArrayBuilder;
diff --git a/third_party/WebKit/Source/platform/wtf/Time.h b/third_party/WebKit/Source/platform/wtf/Time.h
index 1543519..62fee87 100644
--- a/third_party/WebKit/Source/platform/wtf/Time.h
+++ b/third_party/WebKit/Source/platform/wtf/Time.h
@@ -46,7 +46,7 @@
 
 class TimeTicks {
  public:
-  TimeTicks() {}
+  TimeTicks() = default;
   TimeTicks(base::TimeTicks value) : value_(value) {}
 
   static TimeTicks UnixEpoch() {
diff --git a/third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp b/third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp
index 388331b..ec2a9bb 100644
--- a/third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/TypeTraitsTest.cpp
@@ -37,7 +37,7 @@
               "VirtualClass should not be trivially move assignable");
 
 struct DestructorClass {
-  ~DestructorClass() {}
+  ~DestructorClass() = default;
 };
 static_assert(std::is_trivially_move_assignable<DestructorClass>::value,
               "DestructorClass should be trivially move assignable");
diff --git a/third_party/WebKit/Source/platform/wtf/Vector.h b/third_party/WebKit/Source/platform/wtf/Vector.h
index c8a7677..77c5fb8f 100644
--- a/third_party/WebKit/Source/platform/wtf/Vector.h
+++ b/third_party/WebKit/Source/platform/wtf/Vector.h
@@ -487,7 +487,7 @@
  public:
   using OffsetRange = typename Base::OffsetRange;
 
-  VectorBuffer() {}
+  VectorBuffer() = default;
 
   explicit VectorBuffer(size_t capacity) {
     // Calling malloc(0) might take a lock and may actually do an allocation
diff --git a/third_party/WebKit/Source/platform/wtf/WTFThreadData.cpp b/third_party/WebKit/Source/platform/wtf/WTFThreadData.cpp
index 952822b..e85d5e46 100644
--- a/third_party/WebKit/Source/platform/wtf/WTFThreadData.cpp
+++ b/third_party/WebKit/Source/platform/wtf/WTFThreadData.cpp
@@ -39,7 +39,7 @@
       cached_converter_icu_(new ICUConverterWrapper),
       thread_id_(internal::CurrentThreadSyscall()) {}
 
-WTFThreadData::~WTFThreadData() {}
+WTFThreadData::~WTFThreadData() = default;
 
 void WTFThreadData::Initialize() {
   DCHECK(!WTFThreadData::static_data_);
diff --git a/third_party/WebKit/Source/platform/wtf/text/AtomicString.h b/third_party/WebKit/Source/platform/wtf/text/AtomicString.h
index 681bc41..f5e1934 100644
--- a/third_party/WebKit/Source/platform/wtf/text/AtomicString.h
+++ b/third_party/WebKit/Source/platform/wtf/text/AtomicString.h
@@ -56,7 +56,7 @@
   // The function is defined in StringStatics.cpp.
   static void Init();
 
-  AtomicString() {}
+  AtomicString() = default;
   AtomicString(const LChar* chars)
       : AtomicString(chars,
                      chars ? strlen(reinterpret_cast<const char*>(chars)) : 0) {
diff --git a/third_party/WebKit/Source/platform/wtf/text/CString.h b/third_party/WebKit/Source/platform/wtf/text/CString.h
index 1611c7a..dcd195f 100644
--- a/third_party/WebKit/Source/platform/wtf/text/CString.h
+++ b/third_party/WebKit/Source/platform/wtf/text/CString.h
@@ -70,7 +70,7 @@
 
  public:
   // Construct a null string, distinguishable from an empty string.
-  CString() {}
+  CString() = default;
 
   // Construct a string from arbitrary bytes.
   CString(const char* chars) : CString(chars, chars ? strlen(chars) : 0) {}
diff --git a/third_party/WebKit/Source/platform/wtf/text/StringBuffer.h b/third_party/WebKit/Source/platform/wtf/text/StringBuffer.h
index 7dc1b10..8b03e62 100644
--- a/third_party/WebKit/Source/platform/wtf/text/StringBuffer.h
+++ b/third_party/WebKit/Source/platform/wtf/text/StringBuffer.h
@@ -42,14 +42,14 @@
   DISALLOW_NEW();
 
  public:
-  StringBuffer() {}
+  StringBuffer() = default;
 
   explicit StringBuffer(unsigned length) {
     CharType* characters;
     data_ = StringImpl::CreateUninitialized(length, characters);
   }
 
-  ~StringBuffer() {}
+  ~StringBuffer() = default;
 
   void Shrink(unsigned new_length);
 
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp
index ddcafffe..fd78f69 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp
@@ -30,7 +30,7 @@
 
 namespace WTF {
 
-TextCodec::~TextCodec() {}
+TextCodec::~TextCodec() = default;
 
 int TextCodec::GetUnencodableReplacement(
     unsigned code_point,
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextCodec.h b/third_party/WebKit/Source/platform/wtf/text/TextCodec.h
index dddd7d74..9c23de8 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextCodec.h
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodec.h
@@ -76,7 +76,7 @@
   USING_FAST_MALLOC(TextCodec);
 
  public:
-  TextCodec() {}
+  TextCodec() = default;
   virtual ~TextCodec();
 
   String Decode(const char* str,
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextPosition.h b/third_party/WebKit/Source/platform/wtf/text/TextPosition.h
index 20c3c00..38fc9f97 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextPosition.h
+++ b/third_party/WebKit/Source/platform/wtf/text/TextPosition.h
@@ -76,7 +76,7 @@
  public:
   TextPosition(OrdinalNumber line, OrdinalNumber column)
       : line_(line), column_(column) {}
-  TextPosition() {}
+  TextPosition() = default;
   bool operator==(const TextPosition& other) const {
     return line_ == other.line_ && column_ == other.column_;
   }
diff --git a/third_party/WebKit/Source/platform/wtf/text/WTFString.h b/third_party/WebKit/Source/platform/wtf/text/WTFString.h
index 2340922..918171b 100644
--- a/third_party/WebKit/Source/platform/wtf/text/WTFString.h
+++ b/third_party/WebKit/Source/platform/wtf/text/WTFString.h
@@ -64,7 +64,7 @@
 
  public:
   // Construct a null string, distinguishable from an empty string.
-  String() {}
+  String() = default;
 
   // Construct a string with UTF-16 data.
   String(const UChar* characters, unsigned length);
diff --git a/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBuffer.h b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBuffer.h
index 5846ef2e..74796cfc 100644
--- a/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBuffer.h
+++ b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBuffer.h
@@ -84,7 +84,7 @@
   bool IsNeutered() const { return is_neutered_; }
   bool IsShared() const { return contents_.IsShared(); }
 
-  ~ArrayBuffer() {}
+  ~ArrayBuffer() = default;
 
  protected:
   inline explicit ArrayBuffer(ArrayBufferContents&);
diff --git a/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp
index 99511a1..5f4ee5c 100644
--- a/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp
+++ b/third_party/WebKit/Source/platform/wtf/typed_arrays/ArrayBufferContents.cpp
@@ -84,7 +84,7 @@
   }
 }
 
-ArrayBufferContents::~ArrayBufferContents() {}
+ArrayBufferContents::~ArrayBufferContents() = default;
 
 void ArrayBufferContents::Neuter() {
   holder_ = nullptr;
diff --git a/third_party/WebKit/common/BUILD.gn b/third_party/WebKit/common/BUILD.gn
index 4daa094..ac54566 100644
--- a/third_party/WebKit/common/BUILD.gn
+++ b/third_party/WebKit/common/BUILD.gn
@@ -134,6 +134,7 @@
 
   public_deps = [
     "//mojo/common:common_custom_types",
+    "//services/network/public/interfaces",
     "//ui/gfx/geometry/mojo",
     "//url/mojo:url_mojom_gurl",
     "//url/mojo:url_mojom_origin",
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 087dad2..6d802ce8 100644
--- a/third_party/WebKit/common/service_worker/service_worker_client.mojom
+++ b/third_party/WebKit/common/service_worker/service_worker_client.mojom
@@ -4,6 +4,11 @@
 
 module blink.mojom;
 
+import "mojo/common/time.mojom";
+import "services/network/public/interfaces/request_context_frame_type.mojom";
+import "third_party/WebKit/common/page/page_visibility_state.mojom";
+import "url/mojo/url.mojom";
+
 // Indicates the service worker client type.
 // See https://w3c.github.io/ServiceWorker/#service-worker-client-concept
 // and https://w3c.github.io/ServiceWorker/#dom-clientqueryoptions-type.
@@ -13,3 +18,38 @@
   kAll,
   kLast = kAll
 };
+
+// Holds the information related to a service worker window or non-window
+// client.
+// https://w3c.github.io/ServiceWorker/#client
+// An invalid client info can be indicated by setting the client_uuid to the
+// empty string. Sometimes this is needed when the browser process couldn't
+// find a client.
+struct ServiceWorkerClientInfo {
+  // Client#url
+  url.mojom.Url url;
+
+  // Client#id
+  string client_uuid;
+
+  // Client#type
+  ServiceWorkerClientType client_type;
+
+  // WindowClient#visibilityState
+  // Set to |kHidden| if it's a non-window client.
+  PageVisibilityState page_visibility_state = PageVisibilityState.kHidden;
+
+  // WindowClient#focused
+  // Set to false if it's a non-window client.
+  bool is_focused = false;
+
+  // Set to |kNone| if it's a non-window client.
+  network.mojom.RequestContextFrameType frame_type = network.mojom.RequestContextFrameType.kNone;
+
+  // The time this window was last focused. Set to base::TimeTicks() if it's
+  // a non-window client.
+  mojo.common.mojom.TimeTicks last_focus_time;
+
+  // The time this client was created.
+  mojo.common.mojom.TimeTicks creation_time;
+};
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 9aa4657..80c91f7 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -473,8 +473,6 @@
     "web/WebDateTimeChooserParams.h",
     "web/WebDateTimeInputType.h",
     "web/WebDateTimeSuggestion.h",
-    "web/WebDevToolsAgent.h",
-    "web/WebDevToolsAgentClient.h",
     "web/WebDeviceEmulationParams.h",
     "web/WebDocument.h",
     "web/WebDocumentLoader.h",
@@ -778,6 +776,7 @@
     "platform/reporting.mojom",
     "platform/site_engagement.mojom",
     "web/console_message.mojom",
+    "web/devtools_agent.mojom",
     "web/devtools_frontend.mojom",
     "web/selection_menu_behavior.mojom",
     "web/shared_worker_creation_context_type.mojom",
diff --git a/third_party/WebKit/public/web/WebDevToolsAgent.h b/third_party/WebKit/public/web/WebDevToolsAgent.h
deleted file mode 100644
index 50a75bf..0000000
--- a/third_party/WebKit/public/web/WebDevToolsAgent.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WebDevToolsAgent_h
-#define WebDevToolsAgent_h
-
-#include "public/platform/WebCommon.h"
-
-namespace blink {
-
-class WebString;
-struct WebPoint;
-
-class WebDevToolsAgent {
- public:
-  virtual ~WebDevToolsAgent() = default;
-
-  virtual void Attach(int session_id) = 0;
-  virtual void Reattach(int session_id, const WebString& saved_state) = 0;
-  virtual void Detach(int session_id) = 0;
-
-  virtual void DispatchOnInspectorBackend(int session_id,
-                                          int call_id,
-                                          const WebString& method,
-                                          const WebString& message) = 0;
-
-  virtual void InspectElementAt(int session_id, const WebPoint&) = 0;
-
-  class MessageDescriptor {
-   public:
-    virtual ~MessageDescriptor() = default;
-    virtual WebDevToolsAgent* Agent() = 0;
-    virtual WebString Message() = 0;
-    virtual WebString Method() = 0;
-  };
-  // Asynchronously request debugger to pause immediately and run the command.
-  BLINK_EXPORT static void InterruptAndDispatch(int session_id,
-                                                MessageDescriptor*);
-  BLINK_EXPORT static bool ShouldInterruptForMethod(const WebString&);
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/web/WebDevToolsAgentClient.h b/third_party/WebKit/public/web/WebDevToolsAgentClient.h
deleted file mode 100644
index f0146470..0000000
--- a/third_party/WebKit/public/web/WebDevToolsAgentClient.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef WebDevToolsAgentClient_h
-#define WebDevToolsAgentClient_h
-
-#include "public/platform/WebCommon.h"
-#include "public/platform/WebString.h"
-
-namespace blink {
-
-class WebString;
-
-class WebDevToolsAgentClient {
- public:
-  // Sends response message over the protocol, update agent state on the browser
-  // side for potential re-attach. |callId| for notifications is 0, |state| for
-  // notifications is empty.
-  virtual void SendProtocolMessage(int session_id,
-                                   int call_id,
-                                   const WebString& response,
-                                   const WebString& state) {}
-
-  // Returns process id.
-  virtual long ProcessId() { return -1; }
-
-  // Returns unique identifier of the entity within process.
-  virtual int DebuggerId() { return -1; }
-
-  // Resume the inspected renderer that is waiting for DevTools front-end to
-  // initialize its state.
-  virtual void ResumeStartup() {}
-
- protected:
-  ~WebDevToolsAgentClient() = default;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index 7d4cede..55f7d0f 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -34,8 +34,6 @@
 class WebContentSettingsClient;
 class WebData;
 class WebDocumentLoader;
-class WebDevToolsAgent;
-class WebDevToolsAgentClient;
 class WebDocument;
 class WebDoubleSize;
 class WebDOMEvent;
@@ -133,8 +131,6 @@
 
   virtual void SetAutofillClient(WebAutofillClient*) = 0;
   virtual WebAutofillClient* AutofillClient() = 0;
-  virtual void SetDevToolsAgentClient(WebDevToolsAgentClient*) = 0;
-  virtual WebDevToolsAgent* DevToolsAgent() = 0;
   virtual void SetSharedWorkerRepositoryClient(
       WebSharedWorkerRepositoryClient*) = 0;
 
diff --git a/third_party/WebKit/public/web/WebSharedWorkerClient.h b/third_party/WebKit/public/web/WebSharedWorkerClient.h
index a8dc8970..67bc90d 100644
--- a/third_party/WebKit/public/web/WebSharedWorkerClient.h
+++ b/third_party/WebKit/public/web/WebSharedWorkerClient.h
@@ -34,7 +34,6 @@
 #include "public/platform/WebContentSettingsClient.h"
 #include "public/platform/WebWorkerFetchContext.h"
 #include "public/platform/web_feature.mojom-shared.h"
-#include "public/web/WebDevToolsAgentClient.h"
 
 namespace blink {
 
diff --git a/content/common/devtools.mojom b/third_party/WebKit/public/web/devtools_agent.mojom
similarity index 98%
rename from content/common/devtools.mojom
rename to third_party/WebKit/public/web/devtools_agent.mojom
index 279eae3d..2ec4c35 100644
--- a/content/common/devtools.mojom
+++ b/third_party/WebKit/public/web/devtools_agent.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module content.mojom;
+module blink.mojom;
 
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
index f7f83c1..ec03537 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
+++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
@@ -39,7 +39,6 @@
 #include "public/platform/modules/serviceworker/WebServiceWorkerClientsInfo.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerSkipWaitingCallbacks.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerStreamHandle.h"
-#include "public/web/WebDevToolsAgentClient.h"
 #include "third_party/WebKit/common/service_worker/service_worker_event_status.mojom-shared.h"
 #include "v8/include/v8.h"
 
diff --git a/third_party/openh264/README.chromium b/third_party/openh264/README.chromium
index 4798d4b5..94ea277 100644
--- a/third_party/openh264/README.chromium
+++ b/third_party/openh264/README.chromium
@@ -1,7 +1,9 @@
 Name: OpenH264
 Short Name: openh264
 URL: http://www.openh264.org/
-Version: v.1.6.0
+Version: unknown
+(Cut at 5a5c4f14f471b9f434a55c39e942153453f25661, which is between 1.7.0 and
+1.8.0)
 License: 2-Clause BSD
 License File: src/LICENSE
 Security Critical: yes
diff --git a/third_party/webrtc_overrides/rtc_base/diagnostic_logging.h b/third_party/webrtc_overrides/rtc_base/diagnostic_logging.h
index aee7a1d..0838024 100644
--- a/third_party/webrtc_overrides/rtc_base/diagnostic_logging.h
+++ b/third_party/webrtc_overrides/rtc_base/diagnostic_logging.h
@@ -131,27 +131,11 @@
 // Logging Helpers
 //////////////////////////////////////////////////////////////////////
 
-class LogMultilineState {
- public:
-  size_t unprintable_count_[2];
-  LogMultilineState() { unprintable_count_[0] = unprintable_count_[1] = 0; }
-};
-
 class LogMessage {
  public:
   static void LogToDebug(int min_sev);
 };
 
-// When possible, pass optional state variable to track various data across
-// multiple calls to LogMultiline.  Otherwise, pass NULL.
-void LogMultiline(LoggingSeverity level,
-                  const char* label,
-                  bool input,
-                  const void* data,
-                  size_t len,
-                  bool hex_mode,
-                  LogMultilineState* state);
-
 // TODO(grunell): Change name to InitDiagnosticLoggingDelegate or
 // InitDiagnosticLogging. Change also in init_webrtc.h/cc.
 // TODO(grunell): typedef the delegate function.
diff --git a/third_party/webrtc_overrides/rtc_base/logging.cc b/third_party/webrtc_overrides/rtc_base/logging.cc
index df802387..fac4004 100644
--- a/third_party/webrtc_overrides/rtc_base/logging.cc
+++ b/third_party/webrtc_overrides/rtc_base/logging.cc
@@ -18,7 +18,6 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/threading/platform_thread.h"
-#include "third_party/webrtc/rtc_base/stringencode.h"
 #include "third_party/webrtc/rtc_base/stringutils.h"
 
 // This needs to be included after base/logging.h.
@@ -216,130 +215,6 @@
   logging::SetMinLogLevel(min_sev);
 }
 
-// Note: this function is a copy from the overriden libjingle implementation.
-void LogMultiline(LoggingSeverity level,
-                  const char* label,
-                  bool input,
-                  const void* data,
-                  size_t len,
-                  bool hex_mode,
-                  LogMultilineState* state) {
-  // TODO(grunell): This will not do the expected verbosity level checking. We
-  // need a macro for the multiline logging.
-  // https://code.google.com/p/webrtc/issues/detail?id=5011
-  if (!RTC_LOG_CHECK_LEVEL_V(level))
-    return;
-
-  const char* direction = (input ? " << " : " >> ");
-
-  // NULL data means to flush our count of unprintable characters.
-  if (!data) {
-    if (state && state->unprintable_count_[input]) {
-      RTC_LOG_V(level) << label << direction << "## "
-                       << state->unprintable_count_[input]
-                       << " consecutive unprintable ##";
-      state->unprintable_count_[input] = 0;
-    }
-    return;
-  }
-
-  // The ctype classification functions want unsigned chars.
-  const unsigned char* udata = static_cast<const unsigned char*>(data);
-
-  if (hex_mode) {
-    const size_t LINE_SIZE = 24;
-    char hex_line[LINE_SIZE * 9 / 4 + 2], asc_line[LINE_SIZE + 1];
-    while (len > 0) {
-      memset(asc_line, ' ', sizeof(asc_line));
-      memset(hex_line, ' ', sizeof(hex_line));
-      size_t line_len = std::min(len, LINE_SIZE);
-      for (size_t i = 0; i < line_len; ++i) {
-        unsigned char ch = udata[i];
-        asc_line[i] = isprint(ch) ? ch : '.';
-        hex_line[i * 2 + i / 4] = hex_encode(ch >> 4);
-        hex_line[i * 2 + i / 4 + 1] = hex_encode(ch & 0xf);
-      }
-      asc_line[sizeof(asc_line) - 1] = 0;
-      hex_line[sizeof(hex_line) - 1] = 0;
-      RTC_LOG_V(level) << label << direction << asc_line << " " << hex_line
-                       << " ";
-      udata += line_len;
-      len -= line_len;
-    }
-    return;
-  }
-
-  size_t consecutive_unprintable = state ? state->unprintable_count_[input] : 0;
-
-  const unsigned char* end = udata + len;
-  while (udata < end) {
-    const unsigned char* line = udata;
-    const unsigned char* end_of_line =
-        strchrn<unsigned char>(udata, end - udata, '\n');
-    if (!end_of_line) {
-      udata = end_of_line = end;
-    } else {
-      udata = end_of_line + 1;
-    }
-
-    bool is_printable = true;
-
-    // If we are in unprintable mode, we need to see a line of at least
-    // kMinPrintableLine characters before we'll switch back.
-    const ptrdiff_t kMinPrintableLine = 4;
-    if (consecutive_unprintable && ((end_of_line - line) < kMinPrintableLine)) {
-      is_printable = false;
-    } else {
-      // Determine if the line contains only whitespace and printable
-      // characters.
-      bool is_entirely_whitespace = true;
-      for (const unsigned char* pos = line; pos < end_of_line; ++pos) {
-        if (isspace(*pos))
-          continue;
-        is_entirely_whitespace = false;
-        if (!isprint(*pos)) {
-          is_printable = false;
-          break;
-        }
-      }
-      // Treat an empty line following unprintable data as unprintable.
-      if (consecutive_unprintable && is_entirely_whitespace) {
-        is_printable = false;
-      }
-    }
-    if (!is_printable) {
-      consecutive_unprintable += (udata - line);
-      continue;
-    }
-    // Print out the current line, but prefix with a count of prior unprintable
-    // characters.
-    if (consecutive_unprintable) {
-      RTC_LOG_V(level) << label << direction << "## " << consecutive_unprintable
-                       << " consecutive unprintable ##";
-      consecutive_unprintable = 0;
-    }
-    // Strip off trailing whitespace.
-    while ((end_of_line > line) && isspace(*(end_of_line - 1))) {
-      --end_of_line;
-    }
-    // Filter out any private data
-    std::string substr(reinterpret_cast<const char*>(line), end_of_line - line);
-    std::string::size_type pos_private = substr.find("Email");
-    if (pos_private == std::string::npos) {
-      pos_private = substr.find("Passwd");
-    }
-    if (pos_private == std::string::npos) {
-      RTC_LOG_V(level) << label << direction << substr;
-    } else {
-      RTC_LOG_V(level) << label << direction << "## omitted for privacy ##";
-    }
-  }
-
-  if (state) {
-    state->unprintable_count_[input] = consecutive_unprintable;
-  }
-}
-
 void InitDiagnosticLoggingDelegateFunction(
     void (*delegate)(const std::string&)) {
 #ifndef NDEBUG
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9fead18..cf613d7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3246,6 +3246,11 @@
   <int value="12" label="Copy"/>
   <int value="13" label="Cut"/>
   <int value="14" label="Paste"/>
+  <int value="15" label="Sort"/>
+  <int value="16" label="AddBookmark"/>
+  <int value="17" label="AddFolder"/>
+  <int value="18" label="Import"/>
+  <int value="19" label="Export"/>
 </enum>
 
 <enum name="BookmarksEntryPoint">
@@ -25388,6 +25393,7 @@
   <int value="-508143738" label="disable-accelerated-fixed-root-background"/>
   <int value="-506706655" label="respect-autocomplete-off-autofill"/>
   <int value="-505679399" label="FontCacheScaling:enabled"/>
+  <int value="-498740735" label="ArcUsbHost:disabled"/>
   <int value="-498463128" label="MacSystemShareMenu:enabled"/>
   <int value="-496119023" label="WebXR:enabled"/>
   <int value="-495585885" label="enable-spdy-proxy-dev-auth-origin"/>
@@ -25485,6 +25491,7 @@
   <int value="-275619817"
       label="disable-proximity-auth-bluetooth-low-energy-discovery"/>
   <int value="-275164173" label="QuickUnlockPinSignin:enabled"/>
+  <int value="-271790049" label="ArcUsbHost:enabled"/>
   <int value="-270626757" label="log-net-log"/>
   <int value="-268357961" label="enable-feature-policy"/>
   <int value="-254887599" label="google-profile-info"/>
@@ -26099,6 +26106,7 @@
   <int value="1406354320" label="MacViewsWebUIDialogs:enabled"/>
   <int value="1407625309"
       label="disable-minimize-on-second-launcher-item-click"/>
+  <int value="1408139320" label="disable-zip-archiver-packer"/>
   <int value="1408331660" label="enhanced-bookmarks-experiment"/>
   <int value="1409437197" label="OfflinePagesLimitlessPrefetching:enabled"/>
   <int value="1410697724" label="mediadrm-enable-non-compositing"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d745870..503b318 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -28287,6 +28287,23 @@
   </summary>
 </histogram>
 
+<histogram name="History.ExpireVisits.GetRedirectsDurationPercentage" units="%">
+  <owner>calamity@chromium.org</owner>
+  <summary>
+    The percentage of time taken in ExpireHistoryBackend::ExpireVisits for
+    calculating the redirect parent.
+  </summary>
+</histogram>
+
+<histogram name="History.ExpireVisits.TotalDuration" units="ms">
+  <owner>calamity@chromium.org</owner>
+  <summary>
+    The time taken to expire a list of visits. This is not scaled to the number
+    of visits deleted, but gives an idea of how long a single request to
+    ExpireHistoryBackend::ExpireVisits takes.
+  </summary>
+</histogram>
+
 <histogram name="History.FaviconDatabaseAdvancedMetricsTime" units="ticks">
   <owner>rogerm@chromium.org</owner>
   <summary>
@@ -54497,6 +54514,10 @@
 </histogram>
 
 <histogram name="OfflinePages.ClearStorageBatchSize" units="pages">
+  <obsolete>
+    Deprecated as of Jan 2018, replaced by
+    OfflinePages.ClearTemporaryPages.BatchSize.
+  </obsolete>
   <owner>romax@chromium.org</owner>
   <summary>
     Number of pages deleted in a batch during one clear-storage request.
@@ -54525,10 +54546,29 @@
 
 <histogram name="OfflinePages.ClearStorageResult"
     enum="OfflinePagesClearStorageResult">
+  <obsolete>
+    Deprecated as of Jan 2018, replaced by
+    OfflinePages.ClearTemporaryPages.Result.
+  </obsolete>
   <owner>romax@chromium.org</owner>
   <summary>Result of asking storage manager to clear storage.</summary>
 </histogram>
 
+<histogram name="OfflinePages.ClearTemporaryPages.BatchSize" units="pages">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Number of pages deleted in a batch in one clear storage task.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.ClearTemporaryPages.Result"
+    enum="OfflinePagesClearStorageResult">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Result of clearing temporary pages to release storage space.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.Consistency.DeleteOrphanedArchivesResult"
     enum="BooleanSuccess">
   <obsolete>
@@ -54675,6 +54715,9 @@
 </histogram>
 
 <histogram name="OfflinePages.DeletePage.LastOpenToCreated" units="minutes">
+  <obsolete>
+    Deprecated as of 01/2018. Replaced by OfflinePages.PageAccessInterval.
+  </obsolete>
   <owner>jianli@chromium.org</owner>
   <summary>
     Length of time between when an offline page was created and was opened last
@@ -54688,6 +54731,9 @@
 </histogram>
 
 <histogram name="OfflinePages.DeletePage.TimeSinceLastOpen" units="minutes">
+  <obsolete>
+    Deprecated as of 01/2018. Replaced by OfflinePages.PageAccessInterval.
+  </obsolete>
   <owner>jianli@chromium.org</owner>
   <summary>
     Length of time between when an offline page was last opened and was deleted.
@@ -54963,6 +55009,15 @@
   <summary>Length of time between two consecutive opens.</summary>
 </histogram>
 
+<histogram base="true" name="OfflinePages.PageAccessInterval" units="minutes">
+  <owner>romax@chromium.org</owner>
+  <summary>
+    Length of time between accesses to an offline page. This is the same time
+    period used for expiring temporary pages. This metric is recorded when an
+    offline page is accessed.
+  </summary>
+</histogram>
+
 <histogram base="true" name="OfflinePages.PageLifetime" units="minutes">
   <owner>jianli@chromium.org</owner>
   <summary>
@@ -106661,6 +106716,7 @@
   <affected-histogram name="OfflinePages.ExpirePage.TimeSinceLastAccess"/>
   <affected-histogram name="OfflinePages.FirstOpenSinceCreated"/>
   <affected-histogram name="OfflinePages.OpenSinceLastOpen"/>
+  <affected-histogram name="OfflinePages.PageAccessInterval"/>
   <affected-histogram name="OfflinePages.PageLifetime"/>
   <affected-histogram name="OfflinePages.PageSize"/>
   <affected-histogram name="OfflinePages.PageSizeOnAccess.Offline"/>
diff --git a/tools/perf/contrib/leak_detection/page_sets.py b/tools/perf/contrib/leak_detection/page_sets.py
index bf42fe1..8575be4 100644
--- a/tools/perf/contrib/leak_detection/page_sets.py
+++ b/tools/perf/contrib/leak_detection/page_sets.py
@@ -16,11 +16,23 @@
     action_runner.PrepareForLeakDetection()
     action_runner.MeasureMemory()
     action_runner.Navigate(self.url)
-    py_utils.WaitFor(action_runner.tab.HasReachedQuiescence, timeout=30)
+    self._WaitForPageLoadToComplete(action_runner)
     action_runner.Navigate('about:blank')
     action_runner.PrepareForLeakDetection()
     action_runner.MeasureMemory()
 
+  def _WaitForPageLoadToComplete(self, action_runner):
+    py_utils.WaitFor(action_runner.tab.HasReachedQuiescence, timeout=30)
+
+
+# Some websites have a script that loads resources continuously, in which cases
+# HasReachedQuiescence would not be reached. This class waits for document ready
+# state to be complete to avoid timeout for those pages.
+class ResourceLoadingLeakDetectionPage(LeakDetectionPage):
+  def _WaitForPageLoadToComplete(self, action_runner):
+    action_runner.tab.WaitForDocumentReadyStateToBeComplete()
+
+
 class LeakDetectionStorySet(story.StorySet):
   def __init__(self):
     super(LeakDetectionStorySet, self).__init__(
@@ -35,24 +47,26 @@
       'https://www.facebook.com',
       'https://www.baidu.com',
       'https://www.wikipedia.org',
-      # TODO(yuzus) Disabling yahoo & quora for the moment because they time
-      # out on a trybot.
-      # 'https://www.yahoo.com'.
       'https://www.reddit.com',
       'http://www.qq.com',
       'http://www.amazon.com',
       'http://www.twitter.com',
-      # websites which found to be leaking in the past
+      # websites which were found to be leaking in the past
       'https://www.macys.com',
       'https://www.prezi.com',
       'http://www.time.com',
       'http://infomoney.com.br',
       'http://www.cheapoair.com',
-      # 'http://www.quora.com',
       'http://www.onlinedown.net',
       'http://www.dailypost.ng',
       'http://www.listindiario.com',
       'http://www.aljazeera.net',
     ]
+    resource_loading_urls_list = [
+      'https://www.yahoo.com',
+      'http://www.quora.com',
+    ]
     for url in urls_list:
       self.AddStory(LeakDetectionPage(url, self, url))
+    for url in resource_loading_urls_list:
+      self.AddStory(ResourceLoadingLeakDetectionPage(url, self, url))
diff --git a/tools/traffic_annotation/auditor/auditor_result.cc b/tools/traffic_annotation/auditor/auditor_result.cc
index e09f10c..85bbded9 100644
--- a/tools/traffic_annotation/auditor/auditor_result.cc
+++ b/tools/traffic_annotation/auditor/auditor_result.cc
@@ -28,7 +28,6 @@
          type == AuditorResult::Type::ERROR_MISSING_TAG_USED ||
          type == AuditorResult::Type::ERROR_NO_ANNOTATION ||
          type == AuditorResult::Type::ERROR_MISSING_SECOND_ID ||
-         type == AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION ||
          type == AuditorResult::Type::ERROR_DIRECT_ASSIGNMENT);
   if (!message.empty())
     details_.push_back(message);
@@ -58,7 +57,7 @@
 std::string AuditorResult::ToText() const {
   switch (type_) {
     case AuditorResult::Type::ERROR_FATAL:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return details_[0];
 
     case AuditorResult::Type::ERROR_MISSING_TAG_USED:
@@ -71,7 +70,7 @@
                                 file_path_.c_str(), line_);
 
     case AuditorResult::Type::ERROR_SYNTAX: {
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       std::string flat_message(details_[0]);
       std::replace(flat_message.begin(), flat_message.end(), '\n', ' ');
       return base::StringPrintf("Syntax error in '%s': %s", file_path_.c_str(),
@@ -79,14 +78,14 @@
     }
 
     case AuditorResult::Type::ERROR_RESERVED_ID_HASH_CODE:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf(
           "Id '%s' in '%s:%i' has a hash code equal to a reserved word and "
           "should be changed.",
           details_[0].c_str(), file_path_.c_str(), line_);
 
     case AuditorResult::Type::ERROR_DEPRECATED_ID_HASH_CODE:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf(
           "Id '%s' in '%s:%i' has a hash code equal to a deprecated id and "
           "should be changed.",
@@ -107,18 +106,18 @@
           details_[0].c_str(), details_[1].c_str());
 
     case AuditorResult::Type::ERROR_ID_INVALID_CHARACTER:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf(
           "Id '%s' in '%s:%i' contains an invalid character.",
           details_[0].c_str(), file_path_.c_str(), line_);
 
     case AuditorResult::Type::ERROR_MISSING_ANNOTATION:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf("Function '%s' in '%s:%i' requires annotation.",
                                 details_[0].c_str(), file_path_.c_str(), line_);
 
     case AuditorResult::Type::ERROR_INCOMPLETE_ANNOTATION:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf(
           "Annotation at '%s:%i' has the following missing fields: %s",
           file_path_.c_str(), line_, details_[0].c_str());
@@ -130,7 +129,7 @@
           file_path_.c_str(), line_);
 
     case AuditorResult::Type::ERROR_INCONSISTENT_ANNOTATION:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf(
           "Annotation at '%s:%i' has the following inconsistencies: %s",
           file_path_.c_str(), line_, details_[0].c_str());
@@ -143,8 +142,9 @@
           details_[1].c_str(), details_[2].c_str(), details_[0].c_str());
 
     case AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION:
-      return base::StringPrintf("Annotation at '%s:%i' is never completed.",
-                                file_path_.c_str(), line_);
+      DCHECK(!details_.empty());
+      return base::StringPrintf("Annotation '%s' is never completed.",
+                                details_[0].c_str());
 
     case AuditorResult::Type::ERROR_DIRECT_ASSIGNMENT:
       return base::StringPrintf(
@@ -153,7 +153,7 @@
           file_path_.c_str(), line_);
 
     case AuditorResult::Type::ERROR_ANNOTATIONS_XML_UPDATE:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf(
           "'tools/traffic_annotation/summary/annotations.xml' requires update. "
           "It is recommended to run traffic_annotation_auditor locally to do "
@@ -171,12 +171,12 @@
 std::string AuditorResult::ToShortText() const {
   switch (type_) {
     case AuditorResult::Type::ERROR_INCOMPLETE_ANNOTATION:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf("the following fields are missing: %s",
                                 details_[0].c_str());
 
     case AuditorResult::Type::ERROR_INCONSISTENT_ANNOTATION:
-      DCHECK(details_.size());
+      DCHECK(!details_.empty());
       return base::StringPrintf("the following inconsistencies: %s",
                                 details_[0].c_str());
 
diff --git a/tools/traffic_annotation/auditor/instance.cc b/tools/traffic_annotation/auditor/instance.cc
index 2644bba..dad0645 100644
--- a/tools/traffic_annotation/auditor/instance.cc
+++ b/tools/traffic_annotation/auditor/instance.cc
@@ -112,6 +112,8 @@
     : type(Type::ANNOTATION_COMPLETE),
       unique_id_hash_code(0),
       second_id_hash_code(0),
+      archive_content_hash_code(0),
+      is_loaded_from_archive(false),
       is_merged(false) {}
 
 AnnotationInstance::AnnotationInstance(const AnnotationInstance& other)
@@ -120,6 +122,8 @@
       second_id(other.second_id),
       unique_id_hash_code(other.unique_id_hash_code),
       second_id_hash_code(other.second_id_hash_code),
+      archive_content_hash_code(other.archive_content_hash_code),
+      is_loaded_from_archive(other.is_loaded_from_archive),
       is_merged(other.is_merged){};
 
 AuditorResult AnnotationInstance::Deserialize(
@@ -392,13 +396,24 @@
   combination->type = AnnotationInstance::Type::ANNOTATION_COMPLETE;
   combination->second_id.clear();
   combination->second_id_hash_code = 0;
-  combination->comments = base::StringPrintf(
+
+  // Update comment.
+  std::string new_comments = combination->proto.comments();
+  if (!other->proto.comments().empty()) {
+    if (!new_comments.empty())
+      new_comments += "\n";
+    new_comments += other->proto.comments();
+  }
+  if (!new_comments.empty())
+    new_comments += "\n";
+  new_comments += base::StringPrintf(
       "This annotation is a merge of the following two annotations:\n"
       "'%s' in '%s:%i' and '%s' in '%s:%i'.",
       proto.unique_id().c_str(), proto.source().file().c_str(),
       proto.source().line(), completing_annotation.proto.unique_id().c_str(),
       completing_annotation.proto.source().file().c_str(),
       completing_annotation.proto.source().line());
+  combination->proto.set_comments(new_comments);
 
   // Copy TrafficSemantics.
   const traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics
@@ -471,13 +486,134 @@
 }
 
 int AnnotationInstance::GetContentHashCode() const {
-  AnnotationInstance source_free(*this);
+  if (is_loaded_from_archive)
+    return archive_content_hash_code;
+
+  traffic_annotation::NetworkTrafficAnnotation source_free_proto = proto;
+  source_free_proto.clear_source();
   std::string content;
-  source_free.proto.clear_source();
-  google::protobuf::TextFormat::PrintToString(source_free.proto, &content);
+  google::protobuf::TextFormat::PrintToString(source_free_proto, &content);
   return TrafficAnnotationAuditor::ComputeHashValue(content);
 }
 
+// static
+AnnotationInstance AnnotationInstance::LoadFromArchive(
+    AnnotationInstance::Type type,
+    const std::string& unique_id,
+    int unique_id_hash_code,
+    int second_id_hash_code,
+    int content_hash_code,
+    const std::set<int>& semantics_fields,
+    const std::set<int>& policy_fields) {
+  AnnotationInstance annotation;
+
+  annotation.is_loaded_from_archive = true;
+  annotation.type = type;
+  annotation.proto.set_unique_id(unique_id);
+  annotation.unique_id_hash_code = unique_id_hash_code;
+
+  if (annotation.NeedsTwoIDs()) {
+    annotation.second_id_hash_code = second_id_hash_code;
+    // As we don't have the actual second id, a generated value is written to
+    // ensure that the field is not empty. Current set of auditor tests and
+    // unittests just check if this field is not empty when a second id is
+    // required. Tests that are based on matching the ids (like
+    // partial/completing annotations) are based on the hash codes.
+    annotation.second_id =
+        base::StringPrintf("ARCHIVED_ID_%i", annotation.second_id_hash_code);
+  }
+
+  annotation.archive_content_hash_code = content_hash_code;
+
+  // The values of the semantics and policy are set so that the tests would know
+  // which fields were available before archive.
+  if (base::ContainsKey(
+          semantics_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics::
+              kSenderFieldNumber)) {
+    annotation.proto.mutable_semantics()->set_sender("[Archived]");
+  }
+
+  if (base::ContainsKey(
+          semantics_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics::
+              kDescriptionFieldNumber)) {
+    annotation.proto.mutable_semantics()->set_description("[Archived]");
+  }
+
+  if (base::ContainsKey(
+          semantics_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics::
+              kTriggerFieldNumber)) {
+    annotation.proto.mutable_semantics()->set_trigger("[Archived]");
+  }
+
+  if (base::ContainsKey(
+          semantics_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics::
+              kDataFieldNumber)) {
+    annotation.proto.mutable_semantics()->set_data("[Archived]");
+  }
+
+  if (base::ContainsKey(
+          semantics_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficSemantics::
+              kDestinationFieldNumber)) {
+    annotation.proto.mutable_semantics()->set_destination(
+        traffic_annotation::
+            NetworkTrafficAnnotation_TrafficSemantics_Destination_WEBSITE);
+  }
+
+  if (base::ContainsKey(
+          policy_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy::
+              kCookiesAllowedFieldNumber)) {
+    annotation.proto.mutable_policy()->set_cookies_allowed(
+        traffic_annotation::
+            NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_YES);
+  }
+
+  if (base::ContainsKey(
+          policy_fields,
+          -traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy::
+              kCookiesAllowedFieldNumber)) {
+    annotation.proto.mutable_policy()->set_cookies_allowed(
+        traffic_annotation::
+            NetworkTrafficAnnotation_TrafficPolicy_CookiesAllowed_NO);
+  }
+
+  if (base::ContainsKey(
+          policy_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy::
+              kCookiesStoreFieldNumber)) {
+    annotation.proto.mutable_policy()->set_cookies_store("[Archived]");
+  }
+
+  if (base::ContainsKey(
+          policy_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy::
+              kSettingFieldNumber)) {
+    annotation.proto.mutable_policy()->set_setting("[Archived]");
+  }
+
+  if (base::ContainsKey(
+          policy_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy::
+              kChromePolicyFieldNumber)) {
+    annotation.proto.mutable_policy()->add_chrome_policy();
+  }
+
+  if (base::ContainsKey(
+          policy_fields,
+          traffic_annotation::NetworkTrafficAnnotation_TrafficPolicy::
+              kPolicyExceptionJustificationFieldNumber)) {
+    annotation.proto.mutable_policy()->set_policy_exception_justification(
+        "[Archived]");
+  }
+
+  return annotation;
+}
+
 CallInstance::CallInstance() : line_number(0), is_annotated(false) {}
 
 CallInstance::CallInstance(const CallInstance& other)
diff --git a/tools/traffic_annotation/auditor/instance.h b/tools/traffic_annotation/auditor/instance.h
index cd69154..2fd13efe 100644
--- a/tools/traffic_annotation/auditor/instance.h
+++ b/tools/traffic_annotation/auditor/instance.h
@@ -62,6 +62,16 @@
   // -kCookiesAllowedFieldNumber is added.
   void GetPolicyFieldNumbers(std::set<int>* field_numbers) const;
 
+  // Loads annotation based on the data from archive in annotations.xml.
+  static AnnotationInstance LoadFromArchive(
+      AnnotationInstance::Type type,
+      const std::string& unique_id,
+      int unique_id_hash_code,
+      int second_id_hash_code,
+      int content_hash_code,
+      const std::set<int>& semantics_fields,
+      const std::set<int>& policy_fields);
+
   // Checks if an annotation has all required fields.
   AuditorResult IsComplete() const;
 
@@ -82,9 +92,10 @@
            type == Type::ANNOTATION_BRANCHED_COMPLETING;
   }
 
-  // Computes a hashcode for the annotation content. Source field is not used in
-  // this computation as we don't need sensitivity to changes in source
-  // location, i.e. filepath, line number and function.
+  // If annotation is loaded from archive, returns |archive_content_hash_code|.
+  // Otherwise computes a hashcode for the annotation content. Source field is
+  // not used in this computation as we don't need sensitivity to changes in
+  // source location, i.e. filepath, line number and function.
   int GetContentHashCode() const;
 
   // Combines |*this| partial annotation with a completing/branched_completing
@@ -107,7 +118,11 @@
   int unique_id_hash_code;
   int second_id_hash_code;
 
-  std::string comments;
+  // The hash code of annotation content for archived annotations.
+  int archive_content_hash_code;
+
+  // Flag stating if annotation is loaded from annotations.xml.
+  bool is_loaded_from_archive;
 
   // This annotation is generated from merging two other incomplete annotations.
   bool is_merged;
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
index 080c3b2..888e6fe 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -18,7 +18,6 @@
 #include "build/build_config.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "tools/traffic_annotation/auditor/traffic_annotation_exporter.h"
 #include "tools/traffic_annotation/auditor/traffic_annotation_file_filter.h"
 #include "tools/traffic_annotation/auditor/traffic_annotation_id_checker.h"
 
@@ -78,6 +77,23 @@
         .Append(FILE_PATH_LITERAL("scripts"))
         .Append(FILE_PATH_LITERAL("run_tool.py"));
 
+// Checks if the list of |path_filters| include the given |file_path|, or there
+// are path filters which are a folder (don't have a '.' in their name), and
+// match the file name.
+// TODO(https://crbug.com/690323): Update to a more general policy.
+bool PathFiltersMatch(const std::vector<std::string>& path_filters,
+                      const std::string file_path) {
+  if (base::ContainsValue(path_filters, file_path))
+    return true;
+  for (const std::string& path_filter : path_filters) {
+    if (path_filter.find(".") == std::string::npos &&
+        file_path.substr(0, path_filter.length()) == path_filter) {
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace
 
 TrafficAnnotationAuditor::TrafficAnnotationAuditor(
@@ -87,6 +103,7 @@
     : source_path_(source_path),
       build_path_(build_path),
       clang_tool_path_(clang_tool_path),
+      exporter_(source_path),
       safe_list_loaded_(false) {
   DCHECK(!source_path.empty());
   DCHECK(!build_path.empty());
@@ -110,11 +127,21 @@
 
 bool TrafficAnnotationAuditor::RunClangTool(
     const std::vector<std::string>& path_filters,
-    bool filter_files,
+    bool filter_files_based_on_heuristics,
     bool use_compile_commands) {
   if (!safe_list_loaded_ && !LoadSafeList())
     return false;
 
+  // Get list of files/folders to process.
+  std::vector<std::string> file_paths;
+  if (!GenerateFilesListForClangTool(path_filters,
+                                     filter_files_based_on_heuristics,
+                                     use_compile_commands, &file_paths)) {
+    return false;
+  }
+  if (file_paths.empty())
+    return true;
+
   // Create a file to pass options to the clang tool running script.
   base::FilePath options_filepath;
   if (!base::CreateTemporaryFile(&options_filepath)) {
@@ -141,55 +168,9 @@
   if (use_compile_commands)
     fprintf(options_file, "--all ");
 
-  // If |use_compile_commands| is requested or |filter_files| is false, we pass
-  // all given file paths to the running script and the files in the safe list
-  // will be later removed from the results.
-  if (!filter_files || use_compile_commands) {
-    for (const std::string& file_path : path_filters)
-      fprintf(options_file, "%s ", file_path.c_str());
-  } else {
-    TrafficAnnotationFileFilter filter;
-    std::vector<std::string> file_paths;
+  for (const std::string& file_path : file_paths)
+    fprintf(options_file, "%s ", file_path.c_str());
 
-    if (path_filters.size()) {
-      for (const auto& path_filter : path_filters) {
-// If path filter is a directory, search and add its contents.
-// Otherwise add it if it is a relevant file which is not safe listed.
-#if defined(OS_WIN)
-        base::FilePath current_path = base::FilePath(
-            base::FilePath::StringPieceType((base::UTF8ToWide(path_filter))));
-#else
-        base::FilePath current_path = base::FilePath(path_filter);
-#endif
-        if (base::DirectoryExists(current_path)) {
-          filter.GetRelevantFiles(source_path_,
-                                  safe_list_[static_cast<int>(
-                                      AuditorException::ExceptionType::ALL)],
-                                  path_filter, &file_paths);
-        } else {
-          if (!TrafficAnnotationAuditor::IsSafeListed(
-                  path_filter, AuditorException::ExceptionType::ALL) &&
-              filter.IsFileRelevant(path_filter)) {
-            file_paths.push_back(path_filter);
-          }
-        }
-      }
-    } else {
-      filter.GetRelevantFiles(
-          source_path_,
-          safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)],
-          "", &file_paths);
-    }
-
-    if (!file_paths.size()) {
-      base::CloseFile(options_file);
-      base::DeleteFile(options_filepath, false);
-      LOG(ERROR) << "No file is specified for annotation tests.";
-      return false;
-    }
-    for (const auto& file_path : file_paths)
-      fprintf(options_file, "%s ", file_path.c_str());
-  }
   base::CloseFile(options_file);
 
   base::CommandLine cmdline(
@@ -243,6 +224,77 @@
   return result;
 }
 
+bool TrafficAnnotationAuditor::GenerateFilesListForClangTool(
+    const std::vector<std::string>& path_filters,
+    bool filter_files_based_on_heuristics,
+    bool use_compile_commands,
+    std::vector<std::string>* file_paths) {
+  // If |use_compile_commands| is requested or
+  // |filter_files_based_on_heuristics| is false, we pass all given file paths
+  // to the running script and the files in the safe list will be later removed
+  // from the results.
+  if (!filter_files_based_on_heuristics || use_compile_commands) {
+    *file_paths = path_filters;
+    return true;
+  }
+
+  TrafficAnnotationFileFilter filter;
+
+  // If no path filter is provided, get all relevant files, except the safe
+  // listed ones.
+  if (path_filters.empty()) {
+    filter.GetRelevantFiles(
+        source_path_,
+        safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)], "",
+        file_paths);
+    return true;
+  }
+
+  base::FilePath original_path;
+  base::GetCurrentDirectory(&original_path);
+  base::SetCurrentDirectory(source_path_);
+
+  bool possibly_deleted_files = false;
+  for (const auto& path_filter : path_filters) {
+#if defined(OS_WIN)
+    base::FilePath path = base::FilePath(
+        base::FilePath::StringPieceType((base::UTF8ToWide(path_filter))));
+#else
+    base::FilePath path = base::FilePath(path_filter);
+#endif
+
+    // If path filter is a directory, add its relevent, not safe-listed
+    // contents.
+    if (base::DirectoryExists(path)) {
+      filter.GetRelevantFiles(
+          source_path_,
+          safe_list_[static_cast<int>(AuditorException::ExceptionType::ALL)],
+          path_filter, file_paths);
+    } else {
+      // Add the file if it exists and is a relevant file which is not
+      // safe-listed.
+      if (base::PathExists(path)) {
+        if (!TrafficAnnotationAuditor::IsSafeListed(
+                path_filter, AuditorException::ExceptionType::ALL) &&
+            filter.IsFileRelevant(path_filter)) {
+          file_paths->push_back(path_filter);
+        }
+      } else {
+        possibly_deleted_files = true;
+      }
+    }
+  }
+
+  base::SetCurrentDirectory(original_path);
+
+  if (file_paths->empty() && !possibly_deleted_files) {
+    LOG(ERROR) << "No file is specified for annotation tests.";
+    return false;
+  }
+
+  return true;
+}
+
 bool TrafficAnnotationAuditor::IsSafeListed(
     const std::string& file_path,
     AuditorException::ExceptionType exception_type) {
@@ -492,6 +544,9 @@
   for (AnnotationInstance& instance : extracted_annotations_) {
     switch (instance.type) {
       case AnnotationInstance::Type::ANNOTATION_COMPLETE: {
+        // Instances loaded from archive are already checked before archiving.
+        if (instance.is_loaded_from_archive)
+          continue;
         AuditorResult result = instance.IsComplete();
         if (result.IsOK())
           result = instance.IsConsistent();
@@ -516,6 +571,12 @@
         found_a_pair = true;
         used_completing_annotations.insert(completing);
 
+        // Instances loaded from archive are already checked before archiving.
+        if (partial->is_loaded_from_archive &&
+            completing->is_loaded_from_archive) {
+          break;
+        }
+
         AnnotationInstance completed;
         AuditorResult result =
             partial->CreateCompleteAnnotation(*completing, &completed);
@@ -539,17 +600,17 @@
     }
 
     if (!found_a_pair) {
-      errors_.push_back(AuditorResult(
-          AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION, std::string(),
-          partial->proto.source().file(), partial->proto.source().line()));
+      errors_.push_back(
+          AuditorResult(AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION,
+                        partial->proto.unique_id()));
     }
   }
 
   for (AnnotationInstance* instance : completing_annotations) {
     if (!base::ContainsKey(used_completing_annotations, instance)) {
-      errors_.push_back(AuditorResult(
-          AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION, std::string(),
-          instance->proto.source().file(), instance->proto.source().line()));
+      errors_.push_back(
+          AuditorResult(AuditorResult::Type::ERROR_INCOMPLETED_ANNOTATION,
+                        instance->proto.unique_id()));
     }
   }
 
@@ -559,13 +620,33 @@
                                   new_annotations.end());
 }
 
-bool TrafficAnnotationAuditor::RunAllChecks() {
+void TrafficAnnotationAuditor::AddMissingAnnotations(
+    const std::vector<std::string>& path_filters) {
+  for (const auto& item : exporter_.GetArchivedAnnotations()) {
+    if (item.second.deprecation_date.empty() &&
+        exporter_.MatchesCurrentPlatform(item.second) &&
+        !item.second.file_path.empty() &&
+        !PathFiltersMatch(path_filters, item.second.file_path)) {
+      extracted_annotations_.push_back(AnnotationInstance::LoadFromArchive(
+          item.second.type, item.first, item.second.unique_id_hash_code,
+          item.second.second_id_hash_code, item.second.content_hash_code,
+          item.second.semantics_fields, item.second.policy_fields));
+    }
+  }
+}
+
+bool TrafficAnnotationAuditor::RunAllChecks(
+    const std::vector<std::string>& path_filters,
+    bool report_xml_updates) {
   std::set<int> deprecated_ids;
 
-  if (!TrafficAnnotationExporter(source_path_)
-           .GetDeprecatedHashCodes(&deprecated_ids)) {
+  if (!exporter_.GetDeprecatedHashCodes(&deprecated_ids)) {
     return false;
   }
+
+  if (path_filters.size())
+    AddMissingAnnotations(path_filters);
+
   TrafficAnnotationIDChecker id_checker(GetReservedIDsSet(), deprecated_ids);
   id_checker.Load(extracted_annotations_);
   id_checker.CheckIDs(&errors_);
@@ -578,5 +659,18 @@
 
   CheckAllRequiredFunctionsAreAnnotated();
 
+  if (errors_.empty()) {
+    if (!exporter_.UpdateAnnotations(extracted_annotations_,
+                                     GetReservedIDsMap())) {
+      return false;
+    }
+  }
+
+  if (report_xml_updates && exporter_.modified()) {
+    errors_.push_back(
+        AuditorResult(AuditorResult::Type::ERROR_ANNOTATIONS_XML_UPDATE,
+                      exporter_.GetRequiredUpdates()));
+  }
+
   return true;
 }
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
index dda0b8e..c109112 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "tools/traffic_annotation/auditor/auditor_result.h"
 #include "tools/traffic_annotation/auditor/instance.h"
+#include "tools/traffic_annotation/auditor/traffic_annotation_exporter.h"
 #include "tools/traffic_annotation/traffic_annotation.pb.h"
 
 // Holds an item of safe list rules for auditor.
@@ -50,13 +51,13 @@
   ~TrafficAnnotationAuditor();
 
   // Runs traffic_annotation_extractor clang tool and puts its output in
-  // |clang_tool_raw_output_|. If |filter_files| flag is set, the list of files
-  // will be received from repository and heuristically filtered to only
-  // process the relevant files. If |use_compile_commands| flag is set, the
-  // list of files is extracted from compile_commands.json instead of git and
-  // will not be filtered.
+  // |clang_tool_raw_output_|. If |filter_files_based_on_heuristics| flag is
+  // set, the list of files will be received from repository and heuristically
+  // filtered to only process the relevant files. If |use_compile_commands| flag
+  // is set, the list of files is extracted from compile_commands.json instead
+  // of git and will not be filtered.
   bool RunClangTool(const std::vector<std::string>& path_filters,
-                    bool filter_files,
+                    bool filter_files_based_on_heuristics,
                     bool use_compile_commands);
 
   // Parses the output of clang tool (|clang_tool_raw_output_|) and populates
@@ -88,8 +89,12 @@
   // Checks if a call instance can stay not annotated.
   bool CheckIfCallCanBeUnannotated(const CallInstance& call);
 
-  // Performs all checks on extracted annotations and calls.
-  bool RunAllChecks();
+  // Performs all checks on extracted annotations and calls. The input path
+  // filters are passed so that the data for files that were not tested would be
+  // read from annotations.xml. If |report_xml_updates| is set and
+  // annotations.xml requires updates, the updates are added to |errors_|.
+  bool RunAllChecks(const std::vector<std::string>& path_filters,
+                    bool report_xml_updates);
 
   // Returns a mapping of reserved unique ids' hash codes to the unique ids'
   // texts. This list includes all unique ids that are defined in
@@ -126,7 +131,9 @@
     return extracted_calls_;
   }
 
-  std::vector<AuditorResult> errors() { return errors_; }
+  const std::vector<AuditorResult>& errors() const { return errors_; }
+
+  const TrafficAnnotationExporter& exporter() const { return exporter_; }
 
   void ClearErrorsForTesting() { errors_.clear(); }
 
@@ -146,6 +153,8 @@
   const base::FilePath build_path_;
   const base::FilePath clang_tool_path_;
 
+  TrafficAnnotationExporter exporter_;
+
   std::string clang_tool_raw_output_;
   std::vector<AnnotationInstance> extracted_annotations_;
   std::vector<CallInstance> extracted_calls_;
@@ -157,6 +166,22 @@
                      AuditorException::ExceptionType::EXCEPTION_TYPE_LAST) +
                  1];
 
+  // Adds all archived annotations (from annotations.xml) that match the
+  // following features, to |extracted_annotations_|:
+  //  1- Not deprecated.
+  //  2- OS list includes current platform.
+  //  2- Has a path (is not a reserved word).
+  //  3- Path matches an item in |path_filters|.
+  void AddMissingAnnotations(const std::vector<std::string>& path_filters);
+
+  // Generates files list to Run clang tool on. Please refer to RunClangTool
+  // function's comment.
+  bool GenerateFilesListForClangTool(
+      const std::vector<std::string>& path_filters,
+      bool filter_files_based_on_heuristics,
+      bool use_compile_commands,
+      std::vector<std::string>* file_paths);
+
   base::FilePath gn_file_for_test_;
   std::map<std::string, bool> checked_dependencies_;
 };
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
index f8b935c..be741ea 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_ui.cc
@@ -59,7 +59,9 @@
   --annotations-file  Optional path to a TSV output file with all annotations.
   --limit             Limit for the maximum number of returned errors.
                       Use 0 for unlimited.
-  path_filters        Optional paths to filter what files the tool is run on.
+  path_filters        Optional paths to filter which files the tool is run on.
+                      It can also include deleted files names when auditor is
+                      run on a partial repository.
 
 Example:
   traffic_annotation_auditor --build-dir=out/Debug summary-file=report.txt
@@ -187,7 +189,8 @@
 
 // Writes a TSV file of all annotations and their content.
 bool WriteAnnotationsFile(const base::FilePath& filepath,
-                          const std::vector<AnnotationInstance>& annotations) {
+                          const std::vector<AnnotationInstance>& annotations,
+                          const std::vector<std::string>& missing_ids) {
   std::vector<std::string> lines;
   std::string title =
       "Unique ID\tLast Update\tSender\tDescription\tTrigger\tData\t"
@@ -196,6 +199,8 @@
       "ID Hash Code\tContent Hash Code";
 
   for (auto& instance : annotations) {
+    if (instance.type != AnnotationInstance::Type::ANNOTATION_COMPLETE)
+      continue;
     // Unique ID
     std::string line = instance.proto.unique_id();
 
@@ -226,11 +231,13 @@
         break;
       case traffic_annotation::
           NetworkTrafficAnnotation_TrafficSemantics_Destination_OTHER:
-        if (!semantics.destination_other().empty())
+        if (!semantics.destination_other().empty()) {
+          line += "\t";
           line += UpdateTextForTSV(base::StringPrintf(
-              "\tOther: %s", semantics.destination_other().c_str()));
-        else
+              "Other: %s", semantics.destination_other().c_str()));
+        } else {
           line += "\tOther";
+        }
         break;
 
       default:
@@ -267,7 +274,7 @@
     line += base::StringPrintf("\t%s", UpdateTextForTSV(policies_text).c_str());
 
     // Comments.
-    line += "\t" + instance.proto.comments();
+    line += "\t" + UpdateTextForTSV(instance.proto.comments());
 
     // Source.
     const auto source = instance.proto.source();
@@ -283,11 +290,20 @@
     lines.push_back(line);
   }
 
+  // Add missing annotations.
+  int columns = std::count(title.begin(), title.end(), '\t');
+  std::string tabs(columns, '\t');
+
+  for (const std::string& id : missing_ids) {
+    lines.push_back(id + tabs);
+  }
+
   std::sort(lines.begin(), lines.end());
   lines.insert(lines.begin(), title);
   std::string report;
-  for (const std::string& line : lines)
+  for (const std::string& line : lines) {
     report += line + "\n";
+  }
 
   return base::WriteFile(filepath, report.c_str(), report.length()) != -1;
 }
@@ -331,8 +347,11 @@
   }
 
 #if defined(OS_WIN)
-  for (const auto& path : command_line.GetArgs())
-    path_filters.push_back(base::UTF16ToASCII(path));
+  for (const auto& path : command_line.GetArgs()) {
+    std::string repaired_path(base::UTF16ToASCII(path));
+    base::ReplaceChars(repaired_path, "\\", "/", &repaired_path);
+    path_filters.push_back(repaired_path);
+  }
 #else
   path_filters = command_line.GetArgs();
 #endif
@@ -390,7 +409,7 @@
     return 1;
 
   // Perform checks.
-  if (!auditor.RunAllChecks()) {
+  if (!auditor.RunAllChecks(path_filters, test_only)) {
     LOG(ERROR) << "Running checks failed.";
     return 1;
   }
@@ -404,34 +423,25 @@
   }
 
   // Write annotations TSV file.
-  if (!annotations_file.empty() &&
-      !WriteAnnotationsFile(annotations_file,
-                            auditor.extracted_annotations())) {
-    LOG(ERROR) << "Could not write TSV file.";
-    return 1;
-  }
-
-  std::vector<AuditorResult> errors = auditor.errors();
-
-  // Test/Update annotations.xml if everything else is OK and the auditor is
-  // run on the whole repository (without path filters).
-  if (errors.empty() && path_filters.empty()) {
-    TrafficAnnotationExporter exporter(source_path);
-    if (!exporter.UpdateAnnotations(
-            auditor.extracted_annotations(),
-            TrafficAnnotationAuditor::GetReservedIDsMap())) {
+  if (!annotations_file.empty()) {
+    std::vector<std::string> missing_ids;
+    if (!auditor.exporter().GetOtherPlatformsAnnotationIDs(&missing_ids) ||
+        !WriteAnnotationsFile(annotations_file, auditor.extracted_annotations(),
+                              missing_ids)) {
+      LOG(ERROR) << "Could not write TSV file.";
       return 1;
     }
-    if (exporter.modified()) {
-      if (test_only) {
-        errors.push_back(
-            AuditorResult(AuditorResult::Type::ERROR_ANNOTATIONS_XML_UPDATE,
-                          exporter.GetRequiredUpdates()));
-      } else if (!exporter.SaveAnnotationsXML() ||
-                 !RunAnnotationDownstreamUpdater(source_path)) {
-        LOG(ERROR) << "Could not update annotations XML or downstream files.";
-        return 1;
-      }
+  }
+
+  const std::vector<AuditorResult>& errors = auditor.errors();
+
+  // Update annotations.xml if everything else is OK and the auditor is not
+  // run in test-only mode.
+  if (errors.empty() && !test_only && auditor.exporter().modified()) {
+    if (!auditor.exporter().SaveAnnotationsXML() ||
+        !RunAnnotationDownstreamUpdater(source_path)) {
+      LOG(ERROR) << "Could not update annotations XML or downstream files.";
+      return 1;
     }
   }
 
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
index f8aa6ea..0dab1425 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -916,7 +916,7 @@
   TrafficAnnotationExporter exporter(source_path());
 
   EXPECT_TRUE(exporter.LoadAnnotationsXML());
-  EXPECT_TRUE(exporter.CheckAnnotationItems());
+  EXPECT_TRUE(exporter.CheckArchivedAnnotations());
 }
 
 // Tests if downstream files depending on of Annotations.xml are updated.
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc b/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
index 44b8a4a..00f6c2b1 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
@@ -7,7 +7,6 @@
 #include <ctime>
 
 #include "base/files/file_util.h"
-#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
@@ -63,28 +62,36 @@
 
 }  // namespace
 
-TrafficAnnotationExporter::AnnotationItem::AnnotationItem()
+TrafficAnnotationExporter::ArchivedAnnotation::ArchivedAnnotation()
     : type(AnnotationInstance::Type::ANNOTATION_COMPLETE),
       unique_id_hash_code(-1),
       second_id_hash_code(-1),
       content_hash_code(-1) {}
 
-TrafficAnnotationExporter::AnnotationItem::AnnotationItem(
-    const TrafficAnnotationExporter::AnnotationItem& other) = default;
+TrafficAnnotationExporter::ArchivedAnnotation::ArchivedAnnotation(
+    const TrafficAnnotationExporter::ArchivedAnnotation& other) = default;
 
-TrafficAnnotationExporter::AnnotationItem::~AnnotationItem() = default;
+TrafficAnnotationExporter::ArchivedAnnotation::~ArchivedAnnotation() = default;
 
 TrafficAnnotationExporter::TrafficAnnotationExporter(
     const base::FilePath& source_path)
     : source_path_(source_path), modified_(false) {
   all_supported_platforms_.push_back("linux");
   all_supported_platforms_.push_back("windows");
+#if defined(OS_LINUX)
+  current_platform_ = "linux";
+#elif defined(OS_WIN)
+  current_platform_ = "windows";
+#else
+  NOTREACHED() << "Other platforms are not supported yet.";
+  current_platform_ = "undefined";
+#endif
 }
 
 TrafficAnnotationExporter::~TrafficAnnotationExporter() = default;
 
 bool TrafficAnnotationExporter::LoadAnnotationsXML() {
-  annotation_items_.clear();
+  archive_.clear();
   XmlReader reader;
   if (!reader.LoadFile(
           source_path_.Append(kAnnotationsXmlPath).MaybeAsASCII())) {
@@ -100,7 +107,7 @@
     if (reader.NodeName() != "item")
       continue;
 
-    AnnotationItem item;
+    ArchivedAnnotation item;
     std::string temp_str;
     int temp_int = 0;
     std::string unique_id;
@@ -152,7 +159,7 @@
       break;
     }
 
-    annotation_items_.insert(std::make_pair(unique_id, item));
+    archive_.insert(std::make_pair(unique_id, item));
   }
 
   modified_ = false;
@@ -162,16 +169,7 @@
 bool TrafficAnnotationExporter::UpdateAnnotations(
     const std::vector<AnnotationInstance>& annotations,
     const std::map<int, std::string>& reserved_ids) {
-  std::string platform;
-#if defined(OS_LINUX)
-  platform = "linux";
-#elif defined(OS_WIN)
-  platform = "windows";
-#else
-  NOTREACHED() << "Other platforms are not supported yet.";
-#endif
-
-  if (annotation_items_.empty() && !LoadAnnotationsXML())
+  if (archive_.empty() && !LoadAnnotationsXML())
     return false;
 
   std::set<int> current_platform_hashcodes;
@@ -186,21 +184,20 @@
     int content_hash_code = annotation.GetContentHashCode();
     // If annotation unique id is already in the imported annotations list,
     // check if other fields have changed.
-    if (base::ContainsKey(annotation_items_, annotation.proto.unique_id())) {
-      AnnotationItem* current =
-          &annotation_items_[annotation.proto.unique_id()];
+    if (base::ContainsKey(archive_, annotation.proto.unique_id())) {
+      ArchivedAnnotation* current = &archive_[annotation.proto.unique_id()];
 
       // Check second id.
       if (current->second_id_hash_code !=
-          annotation_items_[annotation.proto.unique_id()].second_id_hash_code) {
-        annotation_items_[annotation.proto.unique_id()].second_id_hash_code =
+          archive_[annotation.proto.unique_id()].second_id_hash_code) {
+        archive_[annotation.proto.unique_id()].second_id_hash_code =
             current->second_id_hash_code;
         modified_ = true;
       }
 
       // Check platform.
-      if (!base::ContainsValue(current->os_list, platform)) {
-        current->os_list.push_back(platform);
+      if (!base::ContainsValue(current->os_list, current_platform_)) {
+        current->os_list.push_back(current_platform_);
         modified_ = true;
       }
 
@@ -212,7 +209,7 @@
     } else {
       // If annotation is new, add it and assume it is on all platforms. Tests
       // running on other platforms will request updating this if required.
-      AnnotationItem new_item;
+      ArchivedAnnotation new_item;
       new_item.type = annotation.type;
       new_item.unique_id_hash_code = annotation.unique_id_hash_code;
       if (annotation.NeedsTwoIDs())
@@ -224,37 +221,37 @@
         annotation.GetPolicyFieldNumbers(&new_item.policy_fields);
       }
       new_item.file_path = annotation.proto.source().file();
-      annotation_items_[annotation.proto.unique_id()] = new_item;
+      archive_[annotation.proto.unique_id()] = new_item;
       modified_ = true;
     }
     current_platform_hashcodes.insert(annotation.unique_id_hash_code);
   }
 
   // If a none-reserved annotation is removed from current platform, update it.
-  for (auto& item : annotation_items_) {
-    if (base::ContainsValue(item.second.os_list, platform) &&
+  for (auto& item : archive_) {
+    if (base::ContainsValue(item.second.os_list, current_platform_) &&
         item.second.content_hash_code != -1 &&
         !base::ContainsKey(current_platform_hashcodes,
                            item.second.unique_id_hash_code)) {
-      base::Erase(item.second.os_list, platform);
+      base::Erase(item.second.os_list, current_platform_);
       modified_ = true;
     }
   }
 
   // If there is a new reserved id, add it.
   for (const auto& item : reserved_ids) {
-    if (!base::ContainsKey(annotation_items_, item.second)) {
-      AnnotationItem new_item;
+    if (!base::ContainsKey(archive_, item.second)) {
+      ArchivedAnnotation new_item;
       new_item.unique_id_hash_code = item.first;
       new_item.os_list = all_supported_platforms_;
-      annotation_items_[item.second] = new_item;
+      archive_[item.second] = new_item;
       modified_ = true;
     }
   }
 
   // If there are annotations that are not used in any OS, set the deprecation
   // flag.
-  for (auto& item : annotation_items_) {
+  for (auto& item : archive_) {
     if (item.second.os_list.empty() && item.second.deprecation_date.empty()) {
       base::Time::Exploded now;
       base::Time::Now().UTCExplode(&now);
@@ -264,15 +261,15 @@
     }
   }
 
-  return CheckAnnotationItems();
+  return CheckArchivedAnnotations();
 }
 
-std::string TrafficAnnotationExporter::GenerateSerializedXML() {
+std::string TrafficAnnotationExporter::GenerateSerializedXML() const {
   XmlWriter writer;
   writer.StartWriting();
   writer.StartElement("annotations");
 
-  for (const auto& item : annotation_items_) {
+  for (const auto& item : archive_) {
     writer.StartElement("item");
     writer.AddAttribute("id", item.first);
     writer.AddAttribute(
@@ -335,7 +332,7 @@
   return xml_content;
 }
 
-bool TrafficAnnotationExporter::SaveAnnotationsXML() {
+bool TrafficAnnotationExporter::SaveAnnotationsXML() const {
   std::string xml_content = GenerateSerializedXML();
 
   return base::WriteFile(source_path_.Append(kAnnotationsXmlPath),
@@ -344,21 +341,21 @@
 
 bool TrafficAnnotationExporter::GetDeprecatedHashCodes(
     std::set<int>* hash_codes) {
-  if (annotation_items_.empty() && !LoadAnnotationsXML())
+  if (archive_.empty() && !LoadAnnotationsXML())
     return false;
 
   hash_codes->clear();
-  for (const auto& item : annotation_items_) {
+  for (const auto& item : archive_) {
     if (!item.second.deprecation_date.empty())
       hash_codes->insert(item.second.unique_id_hash_code);
   }
   return true;
 }
 
-bool TrafficAnnotationExporter::CheckAnnotationItems() {
+bool TrafficAnnotationExporter::CheckArchivedAnnotations() {
   // Check for annotation hash code duplications.
   std::set<int> used_codes;
-  for (auto& item : annotation_items_) {
+  for (auto& item : archive_) {
     if (base::ContainsKey(used_codes, item.second.unique_id_hash_code)) {
       LOG(ERROR) << "Unique id hash code " << item.second.unique_id_hash_code
                  << " is used more than once.";
@@ -369,7 +366,7 @@
   }
 
   // Check for coexistence of OS(es) and deprecation date.
-  for (auto& item : annotation_items_) {
+  for (auto& item : archive_) {
     if (!item.second.deprecation_date.empty() && !item.second.os_list.empty()) {
       LOG(ERROR) << "Annotation " << item.first
                  << " has a deprecation date and at least one active OS.";
@@ -451,4 +448,18 @@
   }
 
   return message;
+}
+
+bool TrafficAnnotationExporter::GetOtherPlatformsAnnotationIDs(
+    std::vector<std::string>* ids) const {
+  if (archive_.empty())
+    return false;
+
+  ids->clear();
+  for (const std::pair<std::string, ArchivedAnnotation>& item : archive_) {
+    if (item.second.deprecation_date.empty() &&
+        !MatchesCurrentPlatform(item.second))
+      ids->push_back(item.first);
+  }
+  return true;
 }
\ No newline at end of file
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_exporter.h b/tools/traffic_annotation/auditor/traffic_annotation_exporter.h
index e06d5ed3..1ba6f29e 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_exporter.h
+++ b/tools/traffic_annotation/auditor/traffic_annotation_exporter.h
@@ -10,51 +10,15 @@
 #include <vector>
 
 #include "base/files/file_path.h"
+#include "base/stl_util.h"
 #include "tools/traffic_annotation/auditor/instance.h"
 
 class TrafficAnnotationExporter {
  public:
-  TrafficAnnotationExporter(const base::FilePath& source_path);
-  ~TrafficAnnotationExporter();
-  TrafficAnnotationExporter(const TrafficAnnotationExporter&) = delete;
-  TrafficAnnotationExporter(TrafficAnnotationExporter&&) = delete;
-
-  // Loads annotations from annotations.xml file into |annotation_items_|.
-  bool LoadAnnotationsXML();
-
-  // Updates |annotation_items_| with current set of extracted annotations and
-  // reserved ids. Sets the |modified_| flag if any item is updated.
-  bool UpdateAnnotations(const std::vector<AnnotationInstance>& annotations,
-                         const std::map<int, std::string>& reserved_ids);
-
-  // Saves |annotation_items_| into annotations.xml.
-  bool SaveAnnotationsXML();
-
-  // Returns the required updates for annotations.xml.
-  std::string GetRequiredUpdates();
-
-  std::string GetXMLDifferencesForTesting(const std::string& old_xml,
-                                          const std::string& new_xml) {
-    return GetXMLDifferences(old_xml, new_xml);
-  }
-
-  // Produces the list of deprecated hash codes. Returns false if
-  // annotations.xml is not and cannot be loaded.
-  bool GetDeprecatedHashCodes(std::set<int>* hash_codes);
-
-  bool modified() { return modified_; }
-
-  // Runs tests on content of |annotation_items_|.
-  bool CheckAnnotationItems();
-
-  // Returns the number of items in annotations.xml for testing.
-  unsigned GetXMLItemsCountForTesting();
-
- private:
-  struct AnnotationItem {
-    AnnotationItem();
-    AnnotationItem(const AnnotationItem& other);
-    ~AnnotationItem();
+  struct ArchivedAnnotation {
+    ArchivedAnnotation();
+    ArchivedAnnotation(const ArchivedAnnotation& other);
+    ~ArchivedAnnotation();
 
     AnnotationInstance::Type type;
 
@@ -70,16 +34,68 @@
     std::string file_path;
   };
 
+  TrafficAnnotationExporter(const base::FilePath& source_path);
+  ~TrafficAnnotationExporter();
+  TrafficAnnotationExporter(const TrafficAnnotationExporter&) = delete;
+  TrafficAnnotationExporter(TrafficAnnotationExporter&&) = delete;
+
+  // Loads annotations from annotations.xml file into |archive_|.
+  bool LoadAnnotationsXML();
+
+  // Updates |archive_| with current set of extracted annotations and
+  // reserved ids. Sets the |modified_| flag if any item is updated.
+  bool UpdateAnnotations(const std::vector<AnnotationInstance>& annotations,
+                         const std::map<int, std::string>& reserved_ids);
+
+  // Saves |archive_| into annotations.xml.
+  bool SaveAnnotationsXML() const;
+
+  // Returns the required updates for annotations.xml.
+  std::string GetRequiredUpdates();
+
+  // Produces the list of deprecated hash codes. Returns false if
+  // annotations.xml is not loaded and cannot be loaded.
+  bool GetDeprecatedHashCodes(std::set<int>* hash_codes);
+
+  bool modified() const { return modified_; }
+
+  // Runs tests on content of |archive_|.
+  bool CheckArchivedAnnotations();
+
+  const std::map<std::string, ArchivedAnnotation>& GetArchivedAnnotations()
+      const {
+    return archive_;
+  }
+
+  // Checks if the current platform is in the os list of archived annotation.
+  bool MatchesCurrentPlatform(const ArchivedAnnotation& annotation) const {
+    return base::ContainsValue(annotation.os_list, current_platform_);
+  }
+
+  // Produces the list of annotations that are not defined in this platform.
+  // Returns false if annotations.xml is not loaded.
+  bool GetOtherPlatformsAnnotationIDs(std::vector<std::string>* ids) const;
+
+  // Returns the number of items in annotations.xml for testing.
+  unsigned GetXMLItemsCountForTesting();
+
+  std::string GetXMLDifferencesForTesting(const std::string& old_xml,
+                                          const std::string& new_xml) {
+    return GetXMLDifferences(old_xml, new_xml);
+  }
+
+ private:
   // Generates a text serialized XML for current report items.
-  std::string GenerateSerializedXML();
+  std::string GenerateSerializedXML() const;
 
   // Returns the required updates to convert one serialized XML to another.
   std::string GetXMLDifferences(const std::string& old_xml,
                                 const std::string& new_xml);
 
   std::vector<std::string> all_supported_platforms_;
-  std::map<std::string, AnnotationItem> annotation_items_;
+  std::map<std::string, ArchivedAnnotation> archive_;
   const base::FilePath source_path_;
+  std::string current_platform_;
   bool modified_;
 };
 
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc
index f5abd0e..235dcdc 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.cc
@@ -32,6 +32,7 @@
     }
     item.file_path = instance.proto.source().file();
     item.line_number = instance.proto.source().line();
+    item.loaded_from_archive = instance.is_loaded_from_archive;
     annotations_.push_back(item);
   }
 }
@@ -83,9 +84,16 @@
   for (AnnotationItem& item : annotations_) {
     for (int i = 0; i < item.ids_count; i++) {
       if (!base::ContainsKey(collisions, item.ids[i].hash_code)) {
-        collisions.insert(
-            std::make_pair(item.ids[i].hash_code, item.ids[i].text));
+        // If item is loaded from archive, and it is the second id, do not keep
+        // the id for checks. Archive just keeps the hash code of the second id
+        // and the text value of it is not correct.
+        if (!item.loaded_from_archive || !i) {
+          collisions.insert(
+              std::make_pair(item.ids[i].hash_code, item.ids[i].text));
+        }
       } else {
+        if (item.loaded_from_archive && i)
+          continue;
         if (item.ids[i].text != collisions[item.ids[i].hash_code]) {
           AuditorResult error(AuditorResult::Type::ERROR_HASH_CODE_COLLISION,
                               item.ids[i].text);
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h
index efca132..4f366052 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h
+++ b/tools/traffic_annotation/auditor/traffic_annotation_id_checker.h
@@ -26,6 +26,7 @@
   void CheckIDs(std::vector<AuditorResult>* errors);
 
  private:
+  // TODO(https://crbug.com/690323): Merge struct with AnnotationInstance.
   struct AnnotationItem {
     struct {
       std::string text;
@@ -35,6 +36,7 @@
     AnnotationInstance::Type type;
     std::string file_path;
     int line_number;
+    bool loaded_from_archive;
   };
 
   // Checks if the ids in |invalid_set| are not used in annotations. If found,
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_media.js b/ui/file_manager/file_manager/foreground/elements/files_safe_media.js
index 4df8aedb..a5dc3cf 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_safe_media.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_safe_media.js
@@ -68,7 +68,8 @@
       data.type = this.type;
       data.src = this.src;
       window.setTimeout(function() {
-        this.webview_.contentWindow.postMessage(data, FILES_APP_ORIGIN);
+        if (this.webview_ && this.webview_.contentWindow)
+          this.webview_.contentWindow.postMessage(data, FILES_APP_ORIGIN);
       }.bind(this));
     }
   },
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index ef792f2b..d43a0c0e 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -348,8 +348,8 @@
       this.updateAvailability.bind(this));
 
   chrome.commandLinePrivate.hasSwitch(
-      'enable-zip-archiver-packer', function(enabled) {
-        CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ = enabled;
+      'disable-zip-archiver-packer', function(disabled) {
+        CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ = !disabled;
       }.bind(this));
 };
 
diff --git a/ui/keyboard/container_behavior.h b/ui/keyboard/container_behavior.h
index 993b29e..e6224c3 100644
--- a/ui/keyboard/container_behavior.h
+++ b/ui/keyboard/container_behavior.h
@@ -7,6 +7,7 @@
 
 #include "ui/aura/window.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event.h"
 #include "ui/keyboard/container_type.h"
 #include "ui/keyboard/keyboard_export.h"
 #include "ui/wm/core/window_animations.h"
@@ -61,8 +62,7 @@
 
   virtual void SavePosition(const gfx::Point& position) = 0;
 
-  virtual void HandlePointerEvent(bool isMouseButtonPressed,
-                                  const gfx::Vector2d& kb_offset) = 0;
+  virtual void HandlePointerEvent(const ui::LocatedEvent& event) = 0;
 
   virtual ContainerType GetType() const = 0;
 
diff --git a/ui/keyboard/container_floating_behavior.cc b/ui/keyboard/container_floating_behavior.cc
index 19d71ce..4ad47aa0 100644
--- a/ui/keyboard/container_floating_behavior.cc
+++ b/ui/keyboard/container_floating_behavior.cc
@@ -14,9 +14,6 @@
 
 namespace keyboard {
 
-// Width of the floatin keyboard
-constexpr int kKeyboardWidth = 600;
-
 // Length of the animation to show and hide the keyboard.
 constexpr int kAnimationDurationMs = 200;
 
@@ -72,9 +69,6 @@
     const gfx::Rect& requested_bounds) {
   gfx::Rect keyboard_bounds = requested_bounds;
 
-  // floating keyboard has a fixed width.
-  keyboard_bounds.set_width(kKeyboardWidth);
-
   if (UseDefaultPosition()) {
     // If the keyboard hasn't been shown yet, ignore the request and use
     // default.
@@ -162,10 +156,10 @@
 }
 
 void ContainerFloatingBehavior::HandlePointerEvent(
-    bool isMouseButtonPressed,
-    const gfx::Vector2d& kb_offset) {
+    const ui::LocatedEvent& event) {
   // Cannot call UI-backed operations without a KeyboardController
   DCHECK(controller_);
+  auto kb_offset = gfx::Vector2d(event.x(), event.y());
 
   aura::Window* container = controller_->GetContainerWindow();
 
@@ -175,15 +169,26 @@
   if (keyboard_bounds.height() <= 0)
     return;
 
-  if (isMouseButtonPressed &&
-      (drag_descriptor_ || IsDragHandle(kb_offset, keyboard_bounds.size()))) {
-    if (!drag_descriptor_) {
-      // If there is no active drag, start a new one.
-      drag_descriptor_.reset(
-          new DragDescriptor(keyboard_bounds.origin(), kb_offset));
-    } else {
-      // If there is an active drag, use it to determine the new location of the
-      // keyboard.
+  bool handle_drag = false;
+  if (IsDragHandle(kb_offset, keyboard_bounds.size())) {
+    auto type = event.type();
+    if (type == ui::ET_TOUCH_PRESSED ||
+        (type == ui::ET_MOUSE_PRESSED &&
+         ((const ui::MouseEvent*)&event)->IsOnlyLeftMouseButton())) {
+      // Mouse events are limited to just the left mouse button.
+
+      drag_started_by_touch_ = (type == ui::ET_TOUCH_PRESSED);
+      if (!drag_descriptor_) {
+        // If there is no active drag descriptor, start a new one.
+        drag_descriptor_.reset(
+            new DragDescriptor(keyboard_bounds.origin(), kb_offset));
+      }
+      handle_drag = true;
+    } else if (drag_descriptor_ &&
+               (type == ui::ET_MOUSE_DRAGGED ||
+                (drag_started_by_touch_ && type == ui::ET_TOUCH_MOVED))) {
+      // If there is an active drag, use it to determine the new location
+      // of the keyboard.
       const gfx::Point original_click_location =
           drag_descriptor_->original_keyboard_location() +
           drag_descriptor_->original_click_offset();
@@ -197,28 +202,24 @@
       const gfx::Rect new_bounds =
           gfx::Rect(new_keyboard_location, keyboard_bounds.size());
       controller_->MoveKeyboard(new_bounds);
+      SavePosition(container->bounds().origin());
+      handle_drag = true;
     }
-
-    // re-query the container for the new bounds
-    SavePosition(container->bounds().origin());
-  } else if (drag_descriptor_) {
+  }
+  if (!handle_drag && drag_descriptor_) {
     // drag has ended
     drag_descriptor_ = nullptr;
-
-    // save the current bounds.
-    SavePosition(keyboard_bounds.origin());
   }
 }
 
 void ContainerFloatingBehavior::SetCanonicalBounds(
     aura::Window* container,
     const gfx::Rect& display_bounds) {
-  gfx::Size keyboard_size =
-      gfx::Size(kKeyboardWidth, container->bounds().height());
   gfx::Point keyboard_location =
-      GetPositionForShowingKeyboard(keyboard_size, display_bounds);
+      GetPositionForShowingKeyboard(container->bounds().size(), display_bounds);
   SavePosition(keyboard_location);
-  container->SetBounds(gfx::Rect(keyboard_location, keyboard_size));
+  container->SetBounds(
+      gfx::Rect(keyboard_location, container->bounds().size()));
 }
 
 bool ContainerFloatingBehavior::TextBlurHidesKeyboard() const {
diff --git a/ui/keyboard/container_floating_behavior.h b/ui/keyboard/container_floating_behavior.h
index 82f005a..89124dfa 100644
--- a/ui/keyboard/container_floating_behavior.h
+++ b/ui/keyboard/container_floating_behavior.h
@@ -7,6 +7,7 @@
 
 #include "ui/aura/window.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/keyboard/container_behavior.h"
 #include "ui/keyboard/container_type.h"
@@ -42,8 +43,7 @@
   bool IsDragHandle(const gfx::Vector2d& offset,
                     const gfx::Size& keyboard_size) const override;
   void SavePosition(const gfx::Point& position) override;
-  void HandlePointerEvent(bool isMouseButtonPressed,
-                          const gfx::Vector2d& kb_offset) override;
+  void HandlePointerEvent(const ui::LocatedEvent& event) override;
   void SetCanonicalBounds(aura::Window* container,
                           const gfx::Rect& display_bounds) override;
   ContainerType GetType() const override;
@@ -80,6 +80,10 @@
   // Otherwise nullptr.
   std::unique_ptr<DragDescriptor> drag_descriptor_ = nullptr;
 
+  // Distinguish whether the current drag is from a touch event or mouse event,
+  // so drag/move events can be filtered accordingly
+  bool drag_started_by_touch_ = false;
+
   gfx::Rect draggable_area_ = gfx::Rect();
 };
 
diff --git a/ui/keyboard/container_full_width_behavior.cc b/ui/keyboard/container_full_width_behavior.cc
index 15ba063a..15cbf04 100644
--- a/ui/keyboard/container_full_width_behavior.cc
+++ b/ui/keyboard/container_full_width_behavior.cc
@@ -93,8 +93,7 @@
 }
 
 void ContainerFullWidthBehavior::HandlePointerEvent(
-    bool isMouseButtonPressed,
-    const gfx::Vector2d& kb_offset) {
+    const ui::LocatedEvent& event) {
   // No-op. Nothing special to do for pointer events.
 }
 
diff --git a/ui/keyboard/container_full_width_behavior.h b/ui/keyboard/container_full_width_behavior.h
index 3d6681e9..5a5d1a4 100644
--- a/ui/keyboard/container_full_width_behavior.h
+++ b/ui/keyboard/container_full_width_behavior.h
@@ -7,6 +7,7 @@
 
 #include "ui/aura/window.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event.h"
 #include "ui/keyboard/container_behavior.h"
 #include "ui/keyboard/container_type.h"
 #include "ui/keyboard/keyboard_controller.h"
@@ -39,8 +40,7 @@
   bool IsDragHandle(const gfx::Vector2d& offset,
                     const gfx::Size& keyboard_size) const override;
   void SavePosition(const gfx::Point& position) override;
-  void HandlePointerEvent(bool isMouseButtonPressed,
-                          const gfx::Vector2d& kb_offset) override;
+  void HandlePointerEvent(const ui::LocatedEvent& event) override;
   void SetCanonicalBounds(aura::Window* container,
                           const gfx::Rect& display_bounds) override;
   ContainerType GetType() const override;
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index ed64c39a..3a90e91 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -735,9 +735,8 @@
   return container_behavior_->IsOverscrollAllowed();
 }
 
-void KeyboardController::HandlePointerEvent(bool isMouseButtonPressed,
-                                            const gfx::Vector2d& kb_offset) {
-  container_behavior_->HandlePointerEvent(isMouseButtonPressed, kb_offset);
+void KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) {
+  container_behavior_->HandlePointerEvent(event);
 }
 
 void KeyboardController::SetContainerType(const ContainerType type) {
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index 0102563..c702b72 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -12,6 +12,7 @@
 #include "ui/aura/window_observer.h"
 #include "ui/base/ime/input_method_observer.h"
 #include "ui/base/ime/text_input_type.h"
+#include "ui/events/event.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/keyboard/container_behavior.h"
@@ -161,8 +162,7 @@
 
   // Handle mouse and touch events on the keyboard. The effects of this method
   // will not stop propagation to the keyboard extension.
-  void HandlePointerEvent(bool isMouseButtonPressed,
-                          const gfx::Vector2d& kb_scoped_location);
+  void HandlePointerEvent(const ui::LocatedEvent& event);
 
   // Moves an already loaded keyboard.
   void MoveKeyboard(const gfx::Rect new_bounds);
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc
index 448c32b4..9426979 100644
--- a/ui/keyboard/keyboard_controller_unittest.cc
+++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -255,8 +255,6 @@
   }
   void OnKeyboardClosed() override { keyboard_closed_ = true; }
 
-  // TODO(blakeo): remove this method
-  int bounds_number_of_calls() const { return 0; }
   int visible_bounds_number_of_calls() const {
     return visible_bounds_number_of_calls_;
   }
diff --git a/ui/keyboard/keyboard_event_filter.cc b/ui/keyboard/keyboard_event_filter.cc
index dca614d..47dd504 100644
--- a/ui/keyboard/keyboard_event_filter.cc
+++ b/ui/keyboard/keyboard_event_filter.cc
@@ -23,18 +23,17 @@
 }
 
 void KeyboardEventFilter::OnMouseEvent(ui::MouseEvent* event) {
-  ProcessPointerEvent(event->IsOnlyLeftMouseButton(), event->x(), event->y());
+  ProcessPointerEvent(*event);
 }
 
 void KeyboardEventFilter::OnTouchEvent(ui::TouchEvent* event) {
-  ProcessPointerEvent(event->type() != ui::ET_TOUCH_RELEASED, event->x(),
-                      event->y());
+  ProcessPointerEvent(*event);
 }
 
-void KeyboardEventFilter::ProcessPointerEvent(bool isDrag, int x, int y) {
+void KeyboardEventFilter::ProcessPointerEvent(const ui::LocatedEvent& event) {
   KeyboardController* controller = KeyboardController::GetInstance();
   if (controller)
-    controller->HandlePointerEvent(isDrag, gfx::Vector2d(x, y));
+    controller->HandlePointerEvent(event);
 }
 
 }  // nemespace keyboard
diff --git a/ui/keyboard/keyboard_event_filter.h b/ui/keyboard/keyboard_event_filter.h
index ba5634e..3be7e45 100644
--- a/ui/keyboard/keyboard_event_filter.h
+++ b/ui/keyboard/keyboard_event_filter.h
@@ -6,6 +6,7 @@
 #define UI_KEYBOARD_KEYBOARD_EVENT_FILTER_H_
 
 #include "base/macros.h"
+#include "ui/events/event.h"
 #include "ui/events/event_handler.h"
 #include "ui/keyboard/keyboard_export.h"
 
@@ -24,7 +25,7 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
 
  private:
-  void ProcessPointerEvent(bool isDrag, int x, int y);
+  void ProcessPointerEvent(const ui::LocatedEvent& event);
 
   DISALLOW_COPY_AND_ASSIGN(KeyboardEventFilter);
 };