diff --git a/DEPS b/DEPS
index 070e909..7a082e7 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,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': '22eb2f1aa09b0fb27c199c2cc96cd74b2098d502',
+  'skia_revision': '8a0bfc5201f14c994fe8062ecf1ca34a172de9d3',
   # 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': 'cb94cd4e695fa0221cbd7c17d7ebe6433dac9cf2',
+  'v8_revision': '00805bbf75fb604986fb77d223060d97f3b03ad1',
   # 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.
@@ -96,7 +96,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': '0cc3f7ab57ee2fab3930f80fa6c74bab20838728',
+  'catapult_revision': 'bbfc356b5b6ec0200b27805acef8486938522968',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -366,7 +366,7 @@
       Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '2fe5887b69b53ebf78966cc764aadd39c750f453',
 
     'src/ios/third_party/material_font_disk_loader_ios/src':
-      Var('chromium_git') + '/external/github.com/material-foundation/material-font-disk-loader-ios.git' + '@' + '93acc021e3034898716028822cb802a3a816be7e',
+      Var('chromium_git') + '/external/github.com/material-foundation/material-font-disk-loader-ios.git' + '@' + '8e30188777b016182658fbaa0a4a020a48183224',
 
     'src/ios/third_party/material_roboto_font_loader_ios/src':
       Var('chromium_git') + '/external/github.com/material-foundation/material-roboto-font-loader-ios.git' + '@' + '2e25f314512e71d3413315a20e62a4d0126671f5',
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index 751b553..5fd4ac4 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -28,6 +28,9 @@
 namespace android_webview {
 
 namespace {
+// The client_id used here should not conflict with the client_id generated
+// from RenderWidgetHostImpl.
+constexpr uint32_t kDefaultClientId = 0u;
 SurfacesInstance* g_surfaces_instance = nullptr;
 }  // namespace
 
@@ -39,7 +42,8 @@
 }
 
 SurfacesInstance::SurfacesInstance()
-    : next_client_id_(1u), frame_sink_id_(AllocateFrameSinkId()) {
+    : frame_sink_id_allocator_(kDefaultClientId),
+      frame_sink_id_(AllocateFrameSinkId()) {
   cc::RendererSettings settings;
 
   // Should be kept in sync with compositor_impl_android.cc.
@@ -93,7 +97,7 @@
 }
 
 cc::FrameSinkId SurfacesInstance::AllocateFrameSinkId() {
-  return cc::FrameSinkId(next_client_id_++, 0 /* sink_id */);
+  return frame_sink_id_allocator_.NextFrameSinkId();
 }
 
 cc::SurfaceManager* SurfacesInstance::GetSurfaceManager() {
diff --git a/android_webview/browser/surfaces_instance.h b/android_webview/browser/surfaces_instance.h
index ab5cf1a..0eaf985 100644
--- a/android_webview/browser/surfaces_instance.h
+++ b/android_webview/browser/surfaces_instance.h
@@ -12,6 +12,7 @@
 #include "cc/surfaces/compositor_frame_sink_support_client.h"
 #include "cc/surfaces/display_client.h"
 #include "cc/surfaces/frame_sink_id.h"
+#include "cc/surfaces/frame_sink_id_allocator.h"
 #include "cc/surfaces/surface_id.h"
 
 namespace cc {
@@ -72,7 +73,7 @@
 
   void SetEmptyRootFrame();
 
-  uint32_t next_client_id_;
+  cc::FrameSinkIdAllocator frame_sink_id_allocator_;
 
   cc::FrameSinkId frame_sink_id_;
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index ec4f910..49cda58 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1098,6 +1098,8 @@
     "content/display/screen_orientation_controller_chromeos_unittest.cc",
     "content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc",
     "content/keyboard_overlay/keyboard_overlay_view_unittest.cc",
+    "test/ash_test_suite.cc",
+    "test/ash_test_suite.h",
     "test/ash_unittests.cc",
   ]
   configs += [
@@ -1132,6 +1134,7 @@
     "//ui/chromeos",
     "//ui/display",
     "//ui/display:test_support",
+    "//ui/gl:test_support",
     "//ui/message_center",
     "//ui/message_center:test_support",
     "//ui/views",
@@ -1147,10 +1150,58 @@
   ]
 }
 
+# This target includes the tests that are run by both ash and mash. Eventually
+# the majority of tests in |ash_unittests| should move here.
+source_set("common_unittests") {
+  testonly = true
+  sources = [
+    "accelerators/accelerator_controller_unittest.cc",
+    "common/accelerators/accelerator_table_unittest.cc",
+    "common/drag_drop/drag_image_view_unittest.cc",
+    "common/mus_property_mirror_ash_unittest.cc",
+    "common/system/chromeos/audio/tray_audio_unittest.cc",
+    "common/system/chromeos/brightness/tray_brightness_unittest.cc",
+    "common/system/chromeos/network/vpn_list_unittest.cc",
+    "common/system/chromeos/screen_security/screen_tray_item_unittest.cc",
+    "common/system/chromeos/supervised/tray_supervised_user_unittest.cc",
+    "common/system/date/date_view_unittest.cc",
+    "common/system/update/tray_update_unittest.cc",
+    "common/wm/container_finder_unittest.cc",
+    "common/wm/mru_window_tracker_unittest.cc",
+    "common/wm/workspace/workspace_layout_manager_unittest.cc",
+    "common/wm_window_unittest.cc",
+    "common/wm_window_user_data_unittest.cc",
+  ]
+  deps = [
+    "//ash",
+    "//ash/common/test:test_support",
+    "//ash/public/cpp:ash_public_cpp",
+    "//ash/public/interfaces",
+    "//ash/test:test_support_without_content",
+    "//base",
+    "//base/test:test_support",
+    "//services/ui/public/interfaces",
+    "//ui/app_list/presenter",
+    "//ui/app_list/presenter:test_support",
+    "//ui/aura",
+    "//ui/aura:test_support",
+    "//ui/base",
+    "//ui/base:test_support",
+    "//ui/display",
+    "//ui/events:test_support",
+    "//ui/keyboard",
+    "//ui/message_center",
+    "//ui/views",
+    "//ui/wm",
+  ]
+  public_deps = [
+    "//ash/test:test_support_without_content",
+  ]
+}
+
 test("ash_unittests") {
   sources = [
     "accelerators/accelerator_commands_unittest.cc",
-    "accelerators/accelerator_controller_unittest.cc",
     "accelerators/accelerator_filter_unittest.cc",
     "accelerators/magnifier_key_scroller_unittest.cc",
     "accelerators/spoken_feedback_toggler_unittest.cc",
@@ -1258,8 +1309,9 @@
     "system/toast/toast_manager_unittest.cc",
     "system/web_notification/ash_popup_alignment_delegate_unittest.cc",
     "system/web_notification/web_notification_tray_unittest.cc",
-    "test/ash_test_environment_default.cc",
     "test/ash_test_helper_unittest.cc",
+    "test/ash_test_suite.cc",
+    "test/ash_test_suite.h",
     "test/ash_unittests.cc",
     "tooltips/tooltip_controller_unittest.cc",
     "touch/touch_observer_hud_unittest.cc",
@@ -1315,8 +1367,8 @@
 
   deps = [
     ":ash",
+    ":common_unittests",
     "//ash/autoclick/common:autoclick",
-    "//ash/common:unittests",
     "//ash/common/strings",
     "//ash/common/test:test_support",
     "//ash/public/cpp:ash_public_cpp",
@@ -1364,6 +1416,7 @@
     "//ui/gfx",
     "//ui/gfx:test_support",
     "//ui/gfx/geometry",
+    "//ui/gl:test_support",
     "//ui/keyboard",
     "//ui/message_center",
     "//ui/message_center:test_support",
diff --git a/ash/DEPS b/ash/DEPS
index 528f4fcd..aa4d4f5 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -7,7 +7,6 @@
   "+components/user_manager",
   "+components/wallpaper",
   "+gpu/config",
-  "+grit/ash_resources.h",
   "+grit/ash_strings.h",
   "+media",
   "+mojo/public",
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index aec86f7..32025f5 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -667,6 +667,9 @@
 
 TEST_F(EnabledDockedWindowsAcceleratorControllerTest,
        WindowPanelDockLeftDockRightRestore) {
+  // TODO: http://crbug.com/632209.
+  if (WmShell::Get()->IsRunningInMash())
+    return;
   std::unique_ptr<aura::Window> window0(
       CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20)));
 
@@ -848,6 +851,10 @@
 #endif
 
 TEST_F(AcceleratorControllerTest, GlobalAccelerators) {
+  // TODO: TestScreenshotDelegate is null in mash http://crbug.com/632111.
+  if (WmShell::Get()->IsRunningInMash())
+    return;
+
   // CycleBackward
   EXPECT_TRUE(ProcessInController(
       ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)));
@@ -1223,6 +1230,10 @@
 }  // namespace
 
 TEST_F(PreferredReservedAcceleratorsTest, AcceleratorsWithFullscreen) {
+  // TODO: needs LockStateController ported: http://crbug.com/632189.
+  if (WmShell::Get()->IsRunningInMash())
+    return;
+
   aura::Window* w1 = CreateTestWindowInShellWithId(0);
   aura::Window* w2 = CreateTestWindowInShellWithId(1);
   wm::ActivateWindow(w1);
@@ -1270,6 +1281,9 @@
 }
 
 TEST_F(PreferredReservedAcceleratorsTest, AcceleratorsWithPinned) {
+  // TODO: needs LockStateController ported: http://crbug.com/632189.
+  if (WmShell::Get()->IsRunningInMash())
+    return;
   aura::Window* w1 = CreateTestWindowInShellWithId(0);
   aura::Window* w2 = CreateTestWindowInShellWithId(1);
   wm::ActivateWindow(w1);
@@ -1299,6 +1313,10 @@
 }
 
 TEST_F(AcceleratorControllerTest, DisallowedAtModalWindow) {
+  // TODO: TestScreenshotDelegate is null in mash http://crbug.com/632111.
+  if (WmShell::Get()->IsRunningInMash())
+    return;
+
   std::set<AcceleratorAction> all_actions;
   for (size_t i = 0; i < kAcceleratorDataLength; ++i)
     all_actions.insert(kAcceleratorData[i].action);
@@ -1484,6 +1502,10 @@
 }  // namespace
 
 TEST_F(DeprecatedAcceleratorTester, TestDeprecatedAcceleratorsBehavior) {
+  // TODO: disabled because of UnblockUserSession() not working:
+  // http://crbug.com/632201.
+  if (WmShell::Get()->IsRunningInMash())
+    return;
   for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) {
     const AcceleratorData& entry = kDeprecatedAccelerators[i];
 
diff --git a/ash/common/BUILD.gn b/ash/common/BUILD.gn
deleted file mode 100644
index 80c98b0..0000000
--- a/ash/common/BUILD.gn
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-assert(is_chromeos)
-
-source_set("unittests") {
-  testonly = true
-  sources = [
-    "accelerators/accelerator_table_unittest.cc",
-    "drag_drop/drag_image_view_unittest.cc",
-    "mus_property_mirror_ash_unittest.cc",
-    "system/chromeos/audio/tray_audio_unittest.cc",
-    "system/chromeos/brightness/tray_brightness_unittest.cc",
-    "system/chromeos/network/vpn_list_unittest.cc",
-    "system/chromeos/screen_security/screen_tray_item_unittest.cc",
-    "system/chromeos/supervised/tray_supervised_user_unittest.cc",
-    "system/date/date_view_unittest.cc",
-    "system/update/tray_update_unittest.cc",
-    "wm/container_finder_unittest.cc",
-    "wm/mru_window_tracker_unittest.cc",
-    "wm/workspace/workspace_layout_manager_unittest.cc",
-    "wm_window_unittest.cc",
-    "wm_window_user_data_unittest.cc",
-  ]
-  deps = [
-    "//ash",
-    "//ash/common/test:test_support",
-    "//ash/public/cpp:ash_public_cpp",
-    "//ash/public/interfaces",
-    "//ash/test:test_support_without_content",
-    "//ui/aura",
-    "//ui/base",
-    "//ui/display",
-    "//ui/keyboard",
-    "//ui/message_center",
-    "//ui/views",
-    "//ui/wm",
-  ]
-}
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
index 21fce7ca..f84fe43 100644
--- a/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
+++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -8,9 +8,9 @@
 #include "ash/common/frame/caption_buttons/frame_caption_button.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/test/ash_test_base.h"
-#include "grit/ash_resources.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
diff --git a/ash/common/frame/default_header_painter.cc b/ash/common/frame/default_header_painter.cc
index bf95ba97..519cfe2 100644
--- a/ash/common/frame/default_header_painter.cc
+++ b/ash/common/frame/default_header_painter.cc
@@ -7,10 +7,10 @@
 #include "ash/common/ash_layout_constants.h"
 #include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/common/frame/header_painter_util.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/debug/leak_annotations.h"
 #include "base/logging.h"  // DCHECK
-#include "grit/ash_resources.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/animation/slide_animation.h"
diff --git a/ash/common/shelf/app_list_button.cc b/ash/common/shelf/app_list_button.cc
index ad6a5d6..c71df023 100644
--- a/ash/common/shelf/app_list_button.cc
+++ b/ash/common/shelf/app_list_button.cc
@@ -15,9 +15,9 @@
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/wm_shell.h"
 #include "ash/public/cpp/shelf_types.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/app_list/app_list_switches.h"
diff --git a/ash/common/shelf/overflow_button.cc b/ash/common/shelf/overflow_button.cc
index 1b656ac0..aafbb25 100644
--- a/ash/common/shelf/overflow_button.cc
+++ b/ash/common/shelf/overflow_button.cc
@@ -11,9 +11,9 @@
 #include "ash/common/shelf/shelf_view.h"
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/shelf/wm_shelf_util.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/memory/ptr_util.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/common/shelf/shelf_button.cc b/ash/common/shelf/shelf_button.cc
index 5e1fc2d..deb6529ae 100644
--- a/ash/common/shelf/shelf_button.cc
+++ b/ash/common/shelf/shelf_button.cc
@@ -12,9 +12,9 @@
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/shelf/shelf_view.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/memory/ptr_util.h"
 #include "base/time/time.h"
-#include "grit/ash_resources.h"
 #include "skia/ext/image_operations.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc b/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc
index be1b47b..0ca538d 100644
--- a/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc
+++ b/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc
@@ -4,9 +4,9 @@
 
 #include "ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.h"
 
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "chromeos/audio/cras_audio_handler.h"
-#include "grit/ash_resources.h"
 #include "ui/gfx/paint_vector_icon.h"
 
 using chromeos::CrasAudioHandler;
diff --git a/ash/common/system/chromeos/audio/volume_view.cc b/ash/common/system/chromeos/audio/volume_view.cc
index 95509e4..7ec1d53 100644
--- a/ash/common/system/chromeos/audio/volume_view.cc
+++ b/ash/common/system/chromeos/audio/volume_view.cc
@@ -16,8 +16,8 @@
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc b/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc
index 057ab001..5a08cf0c 100644
--- a/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc
+++ b/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/common/system/system_notifier.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
@@ -15,7 +16,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
index 8e573fc..7b2cde3 100644
--- a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
+++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
@@ -17,9 +17,9 @@
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "device/bluetooth/bluetooth_common.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/brightness/tray_brightness.cc b/ash/common/system/chromeos/brightness/tray_brightness.cc
index 70282d5..72fd9909 100644
--- a/ash/common/system/chromeos/brightness/tray_brightness.cc
+++ b/ash/common/system/chromeos/brightness/tray_brightness.cc
@@ -14,13 +14,13 @@
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager_client.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/display/display.h"
diff --git a/ash/common/system/chromeos/cast/tray_cast.cc b/ash/common/system/chromeos/cast/tray_cast.cc
index 44df98f9..93d4d40 100644
--- a/ash/common/system/chromeos/cast/tray_cast.cc
+++ b/ash/common/system/chromeos/cast/tray_cast.cc
@@ -27,10 +27,10 @@
 #include "ash/common/wm_shell.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/interfaces/cast_config.mojom.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/enterprise/tray_enterprise.cc b/ash/common/system/chromeos/enterprise/tray_enterprise.cc
index f58f670..26f48cab 100644
--- a/ash/common/system/chromeos/enterprise/tray_enterprise.cc
+++ b/ash/common/system/chromeos/enterprise/tray_enterprise.cc
@@ -9,9 +9,9 @@
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/system_tray_notifier.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/logging.h"
 #include "base/strings/string16.h"
-#include "grit/ash_resources.h"
 
 namespace ash {
 
diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.cc b/ash/common/system/chromeos/ime_menu/ime_list_view.cc
index e3303da..b0f3a89 100644
--- a/ash/common/system/chromeos/ime_menu/ime_list_view.cc
+++ b/ash/common/system/chromeos/ime_menu/ime_list_view.cc
@@ -16,7 +16,7 @@
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/wm_shell.h"
-#include "grit/ash_resources.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc
index b9eacd2..ad4b17be 100644
--- a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc
+++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc
@@ -24,10 +24,10 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/ime/ime_bridge.h"
diff --git a/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc
index 9c0bdf6d..0029822e 100644
--- a/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc
+++ b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc
@@ -11,8 +11,8 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_item_view.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/image_view.h"
diff --git a/ash/common/system/chromeos/network/network_icon.cc b/ash/common/system/chromeos/network/network_icon.cc
index 0ec7e275..b82244c0 100644
--- a/ash/common/system/chromeos/network/network_icon.cc
+++ b/ash/common/system/chromeos/network/network_icon.cc
@@ -7,6 +7,7 @@
 #include "ash/common/system/chromeos/network/network_icon_animation.h"
 #include "ash/common/system/chromeos/network/network_icon_animation_observer.h"
 #include "ash/common/system/tray/tray_constants.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
@@ -15,7 +16,6 @@
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "third_party/skia/include/core/SkPaint.h"
diff --git a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc
index 1a30147..9b889d9 100644
--- a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc
+++ b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc
@@ -33,6 +33,7 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
@@ -46,7 +47,6 @@
 #include "chromeos/network/network_connect.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/accessibility/ax_node_data.h"
diff --git a/ash/common/system/chromeos/network/tray_network.cc b/ash/common/system/chromeos/network/tray_network.cc
index 14de552..5e2ef3e 100644
--- a/ash/common/system/chromeos/network/tray_network.cc
+++ b/ash/common/system/chromeos/network/tray_network.cc
@@ -19,11 +19,11 @@
 #include "ash/common/system/tray/tray_popup_item_style.h"
 #include "ash/common/system/tray/tray_utils.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/accessibility/ax_node_data.h"
diff --git a/ash/common/system/chromeos/palette/common_palette_tool.cc b/ash/common/system/chromeos/palette/common_palette_tool.cc
index fa8624c..23d59ad 100644
--- a/ash/common/system/chromeos/palette/common_palette_tool.cc
+++ b/ash/common/system/chromeos/palette/common_palette_tool.cc
@@ -10,10 +10,10 @@
 #include "ash/common/system/tray/hover_highlight_view.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/view_click_listener.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
diff --git a/ash/common/system/chromeos/palette/palette_tray.cc b/ash/common/system/chromeos/palette/palette_tray.cc
index 31c6778..7582c47 100644
--- a/ash/common/system/chromeos/palette/palette_tray.cc
+++ b/ash/common/system/chromeos/palette/palette_tray.cc
@@ -22,10 +22,10 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "base/metrics/histogram_macros.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/power/battery_notification.cc b/ash/common/system/chromeos/power/battery_notification.cc
index 67cf3959..106812ac 100644
--- a/ash/common/system/chromeos/power/battery_notification.cc
+++ b/ash/common/system/chromeos/power/battery_notification.cc
@@ -6,11 +6,11 @@
 
 #include "ash/common/system/chromeos/power/power_status.h"
 #include "ash/common/system/system_notifier.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/i18n/message_formatter.h"
 #include "base/i18n/time_formatting.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
diff --git a/ash/common/system/chromeos/power/dual_role_notification.cc b/ash/common/system/chromeos/power/dual_role_notification.cc
index 9fbf29ac..e3d6cf0 100644
--- a/ash/common/system/chromeos/power/dual_role_notification.cc
+++ b/ash/common/system/chromeos/power/dual_role_notification.cc
@@ -10,8 +10,8 @@
 #include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_controller.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
diff --git a/ash/common/system/chromeos/power/power_status.cc b/ash/common/system/chromeos/power/power_status.cc
index f7356e14..e790a60 100644
--- a/ash/common/system/chromeos/power/power_status.cc
+++ b/ash/common/system/chromeos/power/power_status.cc
@@ -8,13 +8,13 @@
 #include <cmath>
 
 #include "ash/common/material_design/material_design_controller.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager_client.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
diff --git a/ash/common/system/chromeos/power/tray_power.cc b/ash/common/system/chromeos/power/tray_power.cc
index 3bf3208..4f60acc9 100644
--- a/ash/common/system/chromeos/power/tray_power.cc
+++ b/ash/common/system/chromeos/power/tray_power.cc
@@ -17,11 +17,11 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_item_view.h"
 #include "ash/common/system/tray/tray_utils.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc b/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc
index d9ff8ff..c2fb55e 100644
--- a/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc
+++ b/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc
@@ -10,7 +10,7 @@
 #include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_notifier.h"
 #include "ash/common/wm_shell.h"
-#include "grit/ash_resources.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc b/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc
index d74534c..942e90c 100644
--- a/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc
+++ b/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc
@@ -9,7 +9,7 @@
 #include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_notifier.h"
 #include "ash/common/wm_shell.h"
-#include "grit/ash_resources.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/screen_security/screen_tray_item.cc b/ash/common/system/chromeos/screen_security/screen_tray_item.cc
index aff5edc..8d9e6894 100644
--- a/ash/common/system/chromeos/screen_security/screen_tray_item.cc
+++ b/ash/common/system/chromeos/screen_security/screen_tray_item.cc
@@ -10,8 +10,8 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_item_style.h"
 #include "ash/common/system/tray/tray_popup_utils.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/message_center/message_center.h"
diff --git a/ash/common/system/chromeos/session/logout_button_tray.cc b/ash/common/system/chromeos/session/logout_button_tray.cc
index 4e5a763cf..06574c0 100644
--- a/ash/common/system/chromeos/session/logout_button_tray.cc
+++ b/ash/common/system/chromeos/session/logout_button_tray.cc
@@ -16,9 +16,9 @@
 #include "ash/common/system/user/login_status.h"
 #include "ash/common/wm_shell.h"
 #include "ash/public/cpp/shelf_types.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/logging.h"
-#include "grit/ash_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/events/event.h"
 #include "ui/gfx/color_palette.h"
diff --git a/ash/common/system/chromeos/session/tray_session_length_limit.cc b/ash/common/system/chromeos/session/tray_session_length_limit.cc
index d004601e..86b56b5 100644
--- a/ash/common/system/chromeos/session/tray_session_length_limit.cc
+++ b/ash/common/system/chromeos/session/tray_session_length_limit.cc
@@ -14,9 +14,9 @@
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/system_tray_notifier.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
diff --git a/ash/common/system/chromeos/settings/tray_settings.cc b/ash/common/system/chromeos/settings/tray_settings.cc
index 16dd1e70..4fe1c7c 100644
--- a/ash/common/system/chromeos/settings/tray_settings.cc
+++ b/ash/common/system/chromeos/settings/tray_settings.cc
@@ -15,9 +15,9 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/chromeos/supervised/tray_supervised_user.cc b/ash/common/system/chromeos/supervised/tray_supervised_user.cc
index 5693462..ffb6797a 100644
--- a/ash/common/system/chromeos/supervised/tray_supervised_user.cc
+++ b/ash/common/system/chromeos/supervised/tray_supervised_user.cc
@@ -11,9 +11,9 @@
 #include "ash/common/system/tray/label_tray_view.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/callback.h"
 #include "base/logging.h"
-#include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
diff --git a/ash/common/system/chromeos/tray_caps_lock.cc b/ash/common/system/chromeos/tray_caps_lock.cc
index 2162cf9..b2729da9 100644
--- a/ash/common/system/chromeos/tray_caps_lock.cc
+++ b/ash/common/system/chromeos/tray_caps_lock.cc
@@ -12,9 +12,9 @@
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/sys_info.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/ime/chromeos/ime_keyboard.h"
diff --git a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
index c75781c..74040a8 100644
--- a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
+++ b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
@@ -15,8 +15,8 @@
 #include "ash/common/system/tray/tray_utils.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/date/date_default_view.cc b/ash/common/system/date/date_default_view.cc
index a0b92e84..12c1671 100644
--- a/ash/common/system/date/date_default_view.cc
+++ b/ash/common/system/date/date_default_view.cc
@@ -14,12 +14,12 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_header_button.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/shell.h"
 #include "ash/wm/lock_state_controller.h"
 #include "base/i18n/rtl.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager_client.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/border.h"
diff --git a/ash/common/system/ime/tray_ime_chromeos.cc b/ash/common/system/ime/tray_ime_chromeos.cc
index 0bad4675..bef5d5b 100644
--- a/ash/common/system/ime/tray_ime_chromeos.cc
+++ b/ash/common/system/ime/tray_ime_chromeos.cc
@@ -23,10 +23,10 @@
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/system/tray_accessibility.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/accessibility/ax_enums.h"
 #include "ui/accessibility/ax_node_data.h"
diff --git a/ash/common/system/locale/locale_notification_controller.cc b/ash/common/system/locale/locale_notification_controller.cc
index 39444a7..128b393 100644
--- a/ash/common/system/locale/locale_notification_controller.cc
+++ b/ash/common/system/locale/locale_notification_controller.cc
@@ -10,8 +10,8 @@
 #include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_notifier.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/strings/string16.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/overview/overview_button_tray.cc b/ash/common/system/overview/overview_button_tray.cc
index 105320e..c65942e 100644
--- a/ash/common/system/overview/overview_button_tray.cc
+++ b/ash/common/system/overview/overview_button_tray.cc
@@ -15,8 +15,8 @@
 #include "ash/common/wm/overview/window_selector_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/public/cpp/shelf_types.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/tray/label_tray_view.cc b/ash/common/system/tray/label_tray_view.cc
index c1099be..0f2c943 100644
--- a/ash/common/system/tray/label_tray_view.cc
+++ b/ash/common/system/tray/label_tray_view.cc
@@ -8,8 +8,8 @@
 #include "ash/common/system/tray/hover_highlight_view.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/view_click_listener.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/paint_vector_icon.h"
diff --git a/ash/common/system/tray/special_popup_row.cc b/ash/common/system/tray/special_popup_row.cc
index a318117e..02bed8c 100644
--- a/ash/common/system/tray/special_popup_row.cc
+++ b/ash/common/system/tray/special_popup_row.cc
@@ -10,7 +10,7 @@
 #include "ash/common/system/tray/throbber_view.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_header_button.h"
-#include "grit/ash_resources.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
diff --git a/ash/common/system/tray/throbber_view.cc b/ash/common/system/tray/throbber_view.cc
index 76600c6..d326d81 100644
--- a/ash/common/system/tray/throbber_view.cc
+++ b/ash/common/system/tray/throbber_view.cc
@@ -5,7 +5,7 @@
 #include "ash/common/system/tray/throbber_view.h"
 
 #include "ash/common/system/tray/tray_constants.h"
-#include "grit/ash_resources.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
diff --git a/ash/common/system/tray/tray_background_view.cc b/ash/common/system/tray/tray_background_view.cc
index d76626b..1b5098f 100644
--- a/ash/common/system/tray/tray_background_view.cc
+++ b/ash/common/system/tray/tray_background_view.cc
@@ -18,8 +18,8 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "base/memory/ptr_util.h"
-#include "grit/ash_resources.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/nine_image_painter_factory.h"
 #include "ui/compositor/layer.h"
diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc
index dd28557b..6bf56323 100644
--- a/ash/common/system/tray/tray_constants.cc
+++ b/ash/common/system/tray/tray_constants.cc
@@ -49,7 +49,6 @@
 
 const int kTrayDetailedViewTransitionDelayMs = 100;
 
-const int kTrayPopupSliderPaddingMD = 16;
 const int kTrayPopupLabelRightPadding = 8;
 
 const int kTrayPopupDetailsIconWidth = 25;
diff --git a/ash/common/system/tray/tray_constants.h b/ash/common/system/tray/tray_constants.h
index 87f6175b..1da6f92b 100644
--- a/ash/common/system/tray/tray_constants.h
+++ b/ash/common/system/tray/tray_constants.h
@@ -52,10 +52,6 @@
 // before the transition starts.
 ASH_EXPORT extern const int kTrayDetailedViewTransitionDelayMs;
 
-// Padding used to adjust the slider position in volume row and brightness
-// row horizontally.
-extern const int kTrayPopupSliderPaddingMD;
-
 // Padding used on right side of labels to keep minimum distance to the next
 // item. This applies to all labels in the system menu.
 extern const int kTrayPopupLabelRightPadding;
diff --git a/ash/common/system/tray/tray_details_view_unittest.cc b/ash/common/system/tray/tray_details_view_unittest.cc
index e8543c4..7ada566 100644
--- a/ash/common/system/tray/tray_details_view_unittest.cc
+++ b/ash/common/system/tray/tray_details_view_unittest.cc
@@ -12,12 +12,12 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_header_button.h"
 #include "ash/common/system/tray/view_click_listener.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/test/ash_test_base.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
 #include "base/test/test_mock_time_task_runner.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/controls/button/button.h"
@@ -126,17 +126,30 @@
 
   void TransitionFromDetailedToDefaultView(TestDetailsView* detailed) {
     detailed->TransitionToDefaultView();
-    scoped_task_runner_->FastForwardBy(
-        base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs));
+    (*scoped_task_runner_)
+        ->FastForwardBy(base::TimeDelta::FromMilliseconds(
+            kTrayDetailedViewTransitionDelayMs));
   }
 
   void FocusBackButton(TestDetailsView* detailed) {
     detailed->back_button_->RequestFocus();
   }
 
+  void SetUp() override {
+    AshTestBase::SetUp();
+    scoped_task_runner_ =
+        base::MakeUnique<base::ScopedMockTimeMessageLoopTaskRunner>();
+  }
+
+  void TearDown() override {
+    scoped_task_runner_.reset();
+    AshTestBase::TearDown();
+  }
+
  private:
   // Used to control the |transition_delay_timer_|.
-  base::ScopedMockTimeMessageLoopTaskRunner scoped_task_runner_;
+  std::unique_ptr<base::ScopedMockTimeMessageLoopTaskRunner>
+      scoped_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(TrayDetailsViewTest);
 };
diff --git a/ash/common/system/tray/tray_notification_view.cc b/ash/common/system/tray/tray_notification_view.cc
index 687d460..01bb982a 100644
--- a/ash/common/system/tray/tray_notification_view.cc
+++ b/ash/common/system/tray/tray_notification_view.cc
@@ -7,8 +7,8 @@
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/system/tray/system_tray_item.h"
 #include "ash/common/system/tray/tray_constants.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
diff --git a/ash/common/system/tray/tray_popup_utils.cc b/ash/common/system/tray/tray_popup_utils.cc
index e0481892..8289326 100644
--- a/ash/common/system/tray/tray_popup_utils.cc
+++ b/ash/common/system/tray/tray_popup_utils.cc
@@ -9,7 +9,6 @@
 
 #include "ash/common/ash_constants.h"
 #include "ash/common/ash_view_ids.h"
-#include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/system/tray/fixed_sized_image_view.h"
 #include "ash/common/system/tray/size_range_layout.h"
@@ -230,15 +229,8 @@
 }
 
 views::Slider* TrayPopupUtils::CreateSlider(views::SliderListener* listener) {
-  const bool is_material = MaterialDesignController::IsSystemTrayMenuMaterial();
-  views::Slider* slider = views::Slider::CreateSlider(is_material, listener);
-  if (is_material) {
-    slider->SetBorder(
-        views::CreateEmptyBorder(gfx::Insets(0, kTrayPopupSliderPaddingMD)));
-  } else {
-    slider->SetBorder(
-        views::CreateEmptyBorder(0, 0, 0, kTrayPopupPaddingBetweenItems));
-  }
+  views::Slider* slider = new views::Slider(listener);
+  slider->SetBorder(views::CreateEmptyBorder(gfx::Insets(0, 16)));
   return slider;
 }
 
diff --git a/ash/common/system/tray/tray_utils.cc b/ash/common/system/tray/tray_utils.cc
index 2fa65d2..752394e 100644
--- a/ash/common/system/tray/tray_utils.cc
+++ b/ash/common/system/tray/tray_utils.cc
@@ -74,21 +74,4 @@
   }
 }
 
-void GetAccessibleLabelFromDescendantViews(
-    views::View* view,
-    std::vector<base::string16>& out_labels) {
-  ui::AXNodeData temp_node_data;
-  view->GetAccessibleNodeData(&temp_node_data);
-  if (!temp_node_data.GetStringAttribute(ui::AX_ATTR_NAME).empty())
-    out_labels.push_back(temp_node_data.GetString16Attribute(ui::AX_ATTR_NAME));
-
-  // Do not descend into static text labels which may compute their own labels
-  // recursively.
-  if (temp_node_data.role == ui::AX_ROLE_STATIC_TEXT)
-    return;
-
-  for (int i = 0; i < view->child_count(); ++i)
-    GetAccessibleLabelFromDescendantViews(view->child_at(i), out_labels);
-}
-
 }  // namespace ash
diff --git a/ash/common/system/tray/tray_utils.h b/ash/common/system/tray/tray_utils.h
index 5d51783..8c0c136 100644
--- a/ash/common/system/tray/tray_utils.h
+++ b/ash/common/system/tray/tray_utils.h
@@ -30,12 +30,6 @@
 // around it.
 void SetTrayLabelItemBorder(TrayItemView* tray_view, ShelfAlignment alignment);
 
-// Computes an accessible label for this button based on all descendant view
-// labels by concatenating them in depth-first order.
-void GetAccessibleLabelFromDescendantViews(
-    views::View* view,
-    std::vector<base::string16>& out_labels);
-
 }  // namespace ash
 
 #endif  // ASH_COMMON_SYSTEM_TRAY_TRAY_UTILS_H_
diff --git a/ash/common/system/tray_accessibility.cc b/ash/common/system/tray_accessibility.cc
index 04f3945..1c641eb 100644
--- a/ash/common/system/tray_accessibility.cc
+++ b/ash/common/system/tray_accessibility.cc
@@ -20,9 +20,9 @@
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/system/tray/tri_view.h"
 #include "ash/common/wm_shell.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/system/user/button_from_view.cc b/ash/common/system/user/button_from_view.cc
index 69f352c1..c39610d 100644
--- a/ash/common/system/user/button_from_view.cc
+++ b/ash/common/system/user/button_from_view.cc
@@ -9,7 +9,6 @@
 #include "ash/common/ash_constants.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_utils.h"
-#include "ash/common/system/tray/tray_utils.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -75,11 +74,14 @@
 }
 
 void ButtonFromView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->role = ui::AX_ROLE_BUTTON;
-  std::vector<base::string16> labels;
-  for (int i = 0; i < child_count(); ++i)
-    GetAccessibleLabelFromDescendantViews(child_at(i), labels);
-  node_data->SetName(base::JoinString(labels, base::ASCIIToUTF16(" ")));
+  views::CustomButton::GetAccessibleNodeData(node_data);
+  // If no label has been explicitly set via CustomButton::SetAccessibleName(),
+  // use the content's label.
+  if (node_data->GetStringAttribute(ui::AX_ATTR_NAME).empty()) {
+    ui::AXNodeData content_data;
+    content_->GetAccessibleNodeData(&content_data);
+    node_data->SetName(content_data.GetStringAttribute(ui::AX_ATTR_NAME));
+  }
 }
 
 void ButtonFromView::Layout() {
diff --git a/ash/common/system/user/user_card_view.cc b/ash/common/system/user/user_card_view.cc
index ae0315a0..982887a9 100644
--- a/ash/common/system/user/user_card_view.cc
+++ b/ash/common/system/user/user_card_view.cc
@@ -16,7 +16,6 @@
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_popup_item_style.h"
-#include "ash/common/system/tray/tray_utils.h"
 #include "ash/common/system/user/rounded_image_view.h"
 #include "ash/common/wm_shell.h"
 #include "ash/resources/vector_icons/vector_icons.h"
@@ -90,6 +89,7 @@
   void Layout() override;
   gfx::Size GetPreferredSize() const override;
   void OnPaint(gfx::Canvas* canvas) override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
   // Overridden from views::LinkListener.
   void LinkClicked(views::Link* source, int event_flags) override;
@@ -222,6 +222,12 @@
   views::View::OnPaint(canvas);
 }
 
+void PublicAccountUserDetails::GetAccessibleNodeData(
+    ui::AXNodeData* node_data) {
+  node_data->role = ui::AX_ROLE_STATIC_TEXT;
+  node_data->SetName(text_);
+}
+
 void PublicAccountUserDetails::LinkClicked(views::Link* source,
                                            int event_flags) {
   DCHECK_EQ(source, learn_more_);
@@ -325,8 +331,30 @@
 void UserCardView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
   node_data->role = ui::AX_ROLE_STATIC_TEXT;
   std::vector<base::string16> labels;
-  for (int i = 0; i < child_count(); ++i)
-    GetAccessibleLabelFromDescendantViews(child_at(i), labels);
+
+  // Construct the name by concatenating descendants' names.
+  std::list<views::View*> descendants;
+  descendants.push_back(this);
+  while (!descendants.empty()) {
+    auto view = descendants.front();
+    descendants.pop_front();
+    if (view != this) {
+      ui::AXNodeData descendant_data;
+      view->GetAccessibleNodeData(&descendant_data);
+      base::string16 label =
+          descendant_data.GetString16Attribute(ui::AX_ATTR_NAME);
+      // If we find a non-empty name, use that and don't descend further into
+      // the tree.
+      if (!label.empty()) {
+        labels.push_back(label);
+        continue;
+      }
+    }
+
+    // This view didn't have its own name, so look over its children.
+    for (int i = view->child_count() - 1; i >= 0; --i)
+      descendants.push_front(view->child_at(i));
+  }
   node_data->SetName(base::JoinString(labels, base::ASCIIToUTF16(" ")));
 }
 
diff --git a/ash/common/system/user/user_view.cc b/ash/common/system/user/user_view.cc
index 947325e..3b843f7b 100644
--- a/ash/common/system/user/user_view.cc
+++ b/ash/common/system/user/user_view.cc
@@ -24,12 +24,12 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "base/memory/ptr_util.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_info.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/wm/dock/docked_window_layout_manager.cc b/ash/common/wm/dock/docked_window_layout_manager.cc
index 93bea20ca..3148ab7 100644
--- a/ash/common/wm/dock/docked_window_layout_manager.cc
+++ b/ash/common/wm/dock/docked_window_layout_manager.cc
@@ -19,12 +19,12 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
 #include "ash/wm/window_state_aura.h"
 #include "base/auto_reset.h"
 #include "base/metrics/histogram_macros.h"
-#include "grit/ash_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
diff --git a/ash/common/wm/workspace/multi_window_resize_controller.cc b/ash/common/wm/workspace/multi_window_resize_controller.cc
index dfeb77f..e0c96c2 100644
--- a/ash/common/wm/workspace/multi_window_resize_controller.cc
+++ b/ash/common/wm/workspace/multi_window_resize_controller.cc
@@ -8,8 +8,8 @@
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
-#include "grit/ash_resources.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/common/wm/workspace/phantom_window_controller.cc b/ash/common/wm/workspace/phantom_window_controller.cc
index 2843d93..0d2d766 100644
--- a/ash/common/wm/workspace/phantom_window_controller.cc
+++ b/ash/common/wm/workspace/phantom_window_controller.cc
@@ -10,8 +10,8 @@
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
-#include "grit/ash_resources.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/views/background.h"
diff --git a/ash/display/resolution_notification_controller.cc b/ash/display/resolution_notification_controller.cc
index 6730004..7b3c161 100644
--- a/ash/display/resolution_notification_controller.cc
+++ b/ash/display/resolution_notification_controller.cc
@@ -7,9 +7,9 @@
 #include <utility>
 
 #include "ash/common/system/system_notifier.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/shell.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
diff --git a/ash/display/window_tree_host_manager_unittest.cc b/ash/display/window_tree_host_manager_unittest.cc
index 99d37cf..2f1a3bc 100644
--- a/ash/display/window_tree_host_manager_unittest.cc
+++ b/ash/display/window_tree_host_manager_unittest.cc
@@ -185,11 +185,6 @@
       Shell::GetAllRootWindows()[0]);
 }
 
-display::Display GetSecondaryDisplay() {
-  return display::Screen::GetScreen()->GetDisplayNearestWindow(
-      Shell::GetAllRootWindows()[1]);
-}
-
 class TestHelper {
  public:
   explicit TestHelper(test::AshTestBase* delegate);
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index 7674b9b..e7bfe7b4 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -8,12 +8,12 @@
 #include "ash/common/frame/caption_buttons/frame_caption_button.h"
 #include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/common/wm/window_state.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/window_state_aura.h"
 #include "base/i18n/rtl.h"
-#include "grit/ash_resources.h"
 #include "ui/aura/window.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn
index abce61f4..dee2bab 100644
--- a/ash/mus/BUILD.gn
+++ b/ash/mus/BUILD.gn
@@ -191,9 +191,6 @@
   testonly = true
 
   sources = [
-    "accelerators/accelerator_controller_registrar_test_api.cc",
-    "accelerators/accelerator_controller_registrar_test_api.h",
-    "accelerators/accelerator_controller_unittest.cc",
     "app_launch_unittest.cc",
     "bridge/wm_shell_mus_test_api.h",
     "test/ash_test_impl_mus.cc",
diff --git a/ash/mus/accelerators/accelerator_controller_registrar_test_api.cc b/ash/mus/accelerators/accelerator_controller_registrar_test_api.cc
deleted file mode 100644
index ce70d2fe..0000000
--- a/ash/mus/accelerators/accelerator_controller_registrar_test_api.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/mus/accelerators/accelerator_controller_registrar_test_api.h"
-
-#include "ash/mus/accelerators/accelerator_controller_registrar.h"
-#include "ash/mus/accelerators/accelerator_ids.h"
-#include "ash/mus/bridge/wm_shell_mus_test_api.h"
-#include "ui/base/accelerators/accelerator.h"
-#include "ui/events/event.h"
-
-namespace ash {
-namespace mus {
-
-AcceleratorControllerRegistrarTestApi::AcceleratorControllerRegistrarTestApi() {
-}
-
-AcceleratorControllerRegistrarTestApi::
-    ~AcceleratorControllerRegistrarTestApi() {}
-
-void AcceleratorControllerRegistrarTestApi::ProcessAccelerator(
-    const ui::Accelerator& accelerator) {
-  const ui::KeyEvent key_event(accelerator.type(), accelerator.key_code(),
-                               accelerator.modifiers());
-  AcceleratorControllerRegistrar* registrar =
-      WmShellMusTestApi().accelerator_controller_registrar();
-  const AcceleratorControllerRegistrar::Ids& ids =
-      registrar->accelerator_to_ids_[accelerator];
-  const uint32_t pre_id =
-      ComputeAcceleratorId(registrar->id_namespace_, ids.pre_id);
-  if (registrar->OnAccelerator(pre_id, key_event) ==
-      ui::mojom::EventResult::HANDLED) {
-    return;
-  }
-
-  const uint32_t post_id =
-      ComputeAcceleratorId(registrar->id_namespace_, ids.post_id);
-  registrar->OnAccelerator(post_id, key_event);
-}
-
-}  // namespace mus
-}  // namespace ash
diff --git a/ash/mus/accelerators/accelerator_controller_registrar_test_api.h b/ash/mus/accelerators/accelerator_controller_registrar_test_api.h
deleted file mode 100644
index 5a52edbc..0000000
--- a/ash/mus/accelerators/accelerator_controller_registrar_test_api.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_MUS_ACCELERATORS_ACCELERATOR_CONTROLLER_REGISTRAR_TEST_API_H_
-#define ASH_MUS_ACCELERATORS_ACCELERATOR_CONTROLLER_REGISTRAR_TEST_API_H_
-
-#include "base/macros.h"
-
-namespace ui {
-class Accelerator;
-}
-
-namespace ash {
-namespace mus {
-
-class AcceleratorControllerRegistrarTestApi {
- public:
-  AcceleratorControllerRegistrarTestApi();
-  ~AcceleratorControllerRegistrarTestApi();
-
-  // Sends |accelerator| to AcceleratorControllerRegistrar for the pre phase,
-  // and if the pre phase does not process the event the post phase as well.
-  void ProcessAccelerator(const ui::Accelerator& accelerator);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AcceleratorControllerRegistrarTestApi);
-};
-
-}  // namespace mus
-}  // namespace ash
-
-#endif  // ASH_MUS_ACCELERATORS_ACCELERATOR_CONTROLLER_REGISTRAR_TEST_API_H_
diff --git a/ash/mus/accelerators/accelerator_controller_unittest.cc b/ash/mus/accelerators/accelerator_controller_unittest.cc
deleted file mode 100644
index 8366f06..0000000
--- a/ash/mus/accelerators/accelerator_controller_unittest.cc
+++ /dev/null
@@ -1,1454 +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 "ash/common/accelerators/accelerator_controller.h"
-
-#include "ash/common/accelerators/accelerator_table.h"
-#include "ash/common/accessibility_delegate.h"
-#include "ash/common/accessibility_types.h"
-#include "ash/common/ash_switches.h"
-#include "ash/common/ime_control_delegate.h"
-#include "ash/common/session/session_state_delegate.h"
-#include "ash/common/system/brightness_control_delegate.h"
-#include "ash/common/system/keyboard_brightness_control_delegate.h"
-#include "ash/common/system/tray/system_tray_delegate.h"
-#include "ash/common/test/ash_test.h"
-#include "ash/common/wm/panels/panel_layout_manager.h"
-#include "ash/common/wm/window_positioning_utils.h"
-#include "ash/common/wm/window_state.h"
-#include "ash/common/wm/wm_event.h"
-#include "ash/common/wm_lookup.h"
-#include "ash/common/wm_shell.h"
-#include "ash/common/wm_window.h"
-#include "ash/mus/accelerators/accelerator_controller_registrar_test_api.h"
-#include "ash/mus/bridge/wm_shell_mus_test_api.h"
-#include "ash/mus/property_util.h"
-#include "ash/mus/test/wm_test_base.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/root_window_controller.h"
-#include "base/command_line.h"
-#include "base/test/user_action_tester.cc"
-#include "services/ui/public/interfaces/window_manager.mojom.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
-#include "ui/events/event.h"
-#include "ui/events/event_processor.h"
-#include "ui/events/test/event_generator.h"
-#include "ui/message_center/message_center.h"
-#include "ui/views/widget/widget.h"
-
-#if defined(USE_X11)
-#include <X11/Xlib.h>
-#include "ui/events/test/events_test_utils_x11.h"
-#endif
-
-namespace ash {
-
-namespace {
-
-class TestTarget : public ui::AcceleratorTarget {
- public:
-  TestTarget() : accelerator_pressed_count_(0), accelerator_repeat_count_(0) {}
-  ~TestTarget() override {}
-
-  int accelerator_pressed_count() const { return accelerator_pressed_count_; }
-
-  int accelerator_repeat_count() const { return accelerator_repeat_count_; }
-
-  void reset() {
-    accelerator_pressed_count_ = 0;
-    accelerator_repeat_count_ = 0;
-  }
-
-  // Overridden from ui::AcceleratorTarget:
-  bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
-  bool CanHandleAccelerators() const override;
-
- private:
-  int accelerator_pressed_count_;
-  int accelerator_repeat_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestTarget);
-};
-
-class ReleaseAccelerator : public ui::Accelerator {
- public:
-  ReleaseAccelerator(ui::KeyboardCode keycode, int modifiers)
-      : ui::Accelerator(keycode, modifiers) {
-    set_type(ui::ET_KEY_RELEASED);
-  }
-};
-
-class DummyBrightnessControlDelegate : public BrightnessControlDelegate {
- public:
-  DummyBrightnessControlDelegate()
-      : handle_brightness_down_count_(0), handle_brightness_up_count_(0) {}
-  ~DummyBrightnessControlDelegate() override {}
-
-  void HandleBrightnessDown(const ui::Accelerator& accelerator) override {
-    ++handle_brightness_down_count_;
-    last_accelerator_ = accelerator;
-  }
-  void HandleBrightnessUp(const ui::Accelerator& accelerator) override {
-    ++handle_brightness_up_count_;
-    last_accelerator_ = accelerator;
-  }
-  void SetBrightnessPercent(double percent, bool gradual) override {}
-  void GetBrightnessPercent(
-      const base::Callback<void(double)>& callback) override {
-    callback.Run(100.0);
-  }
-
-  int handle_brightness_down_count() const {
-    return handle_brightness_down_count_;
-  }
-  int handle_brightness_up_count() const { return handle_brightness_up_count_; }
-  const ui::Accelerator& last_accelerator() const { return last_accelerator_; }
-
- private:
-  int handle_brightness_down_count_;
-  int handle_brightness_up_count_;
-  ui::Accelerator last_accelerator_;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyBrightnessControlDelegate);
-};
-
-class DummyImeControlDelegate : public ImeControlDelegate {
- public:
-  DummyImeControlDelegate()
-      : handle_next_ime_count_(0),
-        handle_previous_ime_count_(0),
-        handle_switch_ime_count_(0) {}
-  ~DummyImeControlDelegate() override {}
-
-  bool CanCycleIme() override { return true; }
-  void HandleNextIme() override { ++handle_next_ime_count_; }
-  void HandlePreviousIme() override { ++handle_previous_ime_count_; }
-  bool CanSwitchIme(const ui::Accelerator& accelerator) override {
-    return true;
-  }
-  void HandleSwitchIme(const ui::Accelerator& accelerator) override {
-    ++handle_switch_ime_count_;
-  }
-
-  int handle_next_ime_count() const { return handle_next_ime_count_; }
-  int handle_previous_ime_count() const { return handle_previous_ime_count_; }
-  int handle_switch_ime_count() const { return handle_switch_ime_count_; }
-
- private:
-  int handle_next_ime_count_;
-  int handle_previous_ime_count_;
-  int handle_switch_ime_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyImeControlDelegate);
-};
-
-class DummyKeyboardBrightnessControlDelegate
-    : public KeyboardBrightnessControlDelegate {
- public:
-  DummyKeyboardBrightnessControlDelegate()
-      : handle_keyboard_brightness_down_count_(0),
-        handle_keyboard_brightness_up_count_(0) {}
-  ~DummyKeyboardBrightnessControlDelegate() override {}
-
-  void HandleKeyboardBrightnessDown(
-      const ui::Accelerator& accelerator) override {
-    ++handle_keyboard_brightness_down_count_;
-    last_accelerator_ = accelerator;
-  }
-
-  void HandleKeyboardBrightnessUp(const ui::Accelerator& accelerator) override {
-    ++handle_keyboard_brightness_up_count_;
-    last_accelerator_ = accelerator;
-  }
-
-  int handle_keyboard_brightness_down_count() const {
-    return handle_keyboard_brightness_down_count_;
-  }
-
-  int handle_keyboard_brightness_up_count() const {
-    return handle_keyboard_brightness_up_count_;
-  }
-
-  const ui::Accelerator& last_accelerator() const { return last_accelerator_; }
-
- private:
-  int handle_keyboard_brightness_down_count_;
-  int handle_keyboard_brightness_up_count_;
-  ui::Accelerator last_accelerator_;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyKeyboardBrightnessControlDelegate);
-};
-
-bool TestTarget::AcceleratorPressed(const ui::Accelerator& accelerator) {
-  if (accelerator.IsRepeat())
-    ++accelerator_repeat_count_;
-  else
-    ++accelerator_pressed_count_;
-  return true;
-}
-
-bool TestTarget::CanHandleAccelerators() const {
-  return true;
-}
-
-void ProcessAccelerator(ui::KeyboardCode key_code, int flags) {
-  const ui::Accelerator accelerator(key_code, flags);
-  if (!WmShell::Get()->accelerator_controller()->IsRegistered(accelerator))
-    return;
-
-  mus::AcceleratorControllerRegistrarTestApi().ProcessAccelerator(accelerator);
-}
-
-}  // namespace
-
-class AcceleratorControllerTest : public mus::WmTestBase {
- public:
-  AcceleratorControllerTest() {}
-  ~AcceleratorControllerTest() override {}
-
- protected:
-  static AcceleratorController* GetController();
-
-  static bool ProcessInController(const ui::Accelerator& accelerator) {
-    if (accelerator.type() == ui::ET_KEY_RELEASED) {
-      // If the |accelerator| should trigger on release, then we store the
-      // pressed version of it first in history then the released one to
-      // simulate what happens in reality.
-      ui::Accelerator pressed_accelerator = accelerator;
-      pressed_accelerator.set_type(ui::ET_KEY_PRESSED);
-      GetController()->accelerator_history()->StoreCurrentAccelerator(
-          pressed_accelerator);
-    }
-    GetController()->accelerator_history()->StoreCurrentAccelerator(
-        accelerator);
-    return GetController()->Process(accelerator);
-  }
-
-  static const ui::Accelerator& GetPreviousAccelerator() {
-    return GetController()->accelerator_history()->previous_accelerator();
-  }
-
-  static const ui::Accelerator& GetCurrentAccelerator() {
-    return GetController()->accelerator_history()->current_accelerator();
-  }
-
-  // Several functions to access ExitWarningHandler (as friend).
-  static void StubForTest(ExitWarningHandler* ewh) {
-    ewh->stub_timer_for_test_ = true;
-  }
-  static void Reset(ExitWarningHandler* ewh) {
-    ewh->state_ = ExitWarningHandler::IDLE;
-  }
-  static void SimulateTimerExpired(ExitWarningHandler* ewh) {
-    ewh->TimerAction();
-  }
-  static bool is_ui_shown(ExitWarningHandler* ewh) { return !!ewh->widget_; }
-  static bool is_idle(ExitWarningHandler* ewh) {
-    return ewh->state_ == ExitWarningHandler::IDLE;
-  }
-  static bool is_exiting(ExitWarningHandler* ewh) {
-    return ewh->state_ == ExitWarningHandler::EXITING;
-  }
-  // TODO: needs support for TestShelfDelegate: http://crbug.com/632208.
-  /*
-  ui::Window* CreatePanel() {
-    ui::Window* window = CreateTestWindow(
-        gfx::Rect(5, 5, 20, 20),
-        ui::wm::WINDOW_TYPE_PANEL);
-    test::TestShelfDelegate* shelf_delegate =
-        test::TestShelfDelegate::instance();
-    shelf_delegate->AddShelfItem(window);
-    PanelLayoutManager* manager =
-        PanelLayoutManager::Get(WmWindow::Get(window));
-    manager->Relayout();
-    return window;
-  }
-  */
-
-  void SetBrightnessControlDelegate(
-      std::unique_ptr<BrightnessControlDelegate> delegate) {
-    WmShell::Get()->brightness_control_delegate_ = std::move(delegate);
-  }
-
-  void SetKeyboardBrightnessControlDelegate(
-      std::unique_ptr<KeyboardBrightnessControlDelegate> delegate) {
-    WmShell::Get()->keyboard_brightness_control_delegate_ = std::move(delegate);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AcceleratorControllerTest);
-};
-
-AcceleratorController* AcceleratorControllerTest::GetController() {
-  return WmShell::Get()->accelerator_controller();
-}
-
-#if !defined(OS_WIN)
-// Double press of exit shortcut => exiting
-TEST_F(AcceleratorControllerTest, ExitWarningHandlerTestDoublePress) {
-  ui::Accelerator press(ui::VKEY_Q, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
-  ui::Accelerator release(press);
-  release.set_type(ui::ET_KEY_RELEASED);
-  ExitWarningHandler* ewh = GetController()->GetExitWarningHandlerForTest();
-  ASSERT_TRUE(ewh);
-  StubForTest(ewh);
-  EXPECT_TRUE(is_idle(ewh));
-  EXPECT_FALSE(is_ui_shown(ewh));
-  EXPECT_TRUE(ProcessInController(press));
-  EXPECT_FALSE(ProcessInController(release));
-  EXPECT_FALSE(is_idle(ewh));
-  EXPECT_TRUE(is_ui_shown(ewh));
-  EXPECT_TRUE(ProcessInController(press));  // second press before timer.
-  EXPECT_FALSE(ProcessInController(release));
-  SimulateTimerExpired(ewh);
-  EXPECT_TRUE(is_exiting(ewh));
-  EXPECT_FALSE(is_ui_shown(ewh));
-  Reset(ewh);
-}
-
-// Single press of exit shortcut before timer => idle
-TEST_F(AcceleratorControllerTest, ExitWarningHandlerTestSinglePress) {
-  ui::Accelerator press(ui::VKEY_Q, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
-  ui::Accelerator release(press);
-  release.set_type(ui::ET_KEY_RELEASED);
-  ExitWarningHandler* ewh = GetController()->GetExitWarningHandlerForTest();
-  ASSERT_TRUE(ewh);
-  StubForTest(ewh);
-  EXPECT_TRUE(is_idle(ewh));
-  EXPECT_FALSE(is_ui_shown(ewh));
-  EXPECT_TRUE(ProcessInController(press));
-  EXPECT_FALSE(ProcessInController(release));
-  EXPECT_FALSE(is_idle(ewh));
-  EXPECT_TRUE(is_ui_shown(ewh));
-  SimulateTimerExpired(ewh);
-  EXPECT_TRUE(is_idle(ewh));
-  EXPECT_FALSE(is_ui_shown(ewh));
-  Reset(ewh);
-}
-
-// Shutdown ash with exit warning bubble open should not crash.
-TEST_F(AcceleratorControllerTest, LingeringExitWarningBubble) {
-  ExitWarningHandler* ewh = GetController()->GetExitWarningHandlerForTest();
-  ASSERT_TRUE(ewh);
-  StubForTest(ewh);
-
-  // Trigger once to show the bubble.
-  ewh->HandleAccelerator();
-  EXPECT_FALSE(is_idle(ewh));
-  EXPECT_TRUE(is_ui_shown(ewh));
-
-  // Exit ash and there should be no crash
-}
-#endif  // !defined(OS_WIN)
-
-TEST_F(AcceleratorControllerTest, Register) {
-  TestTarget target;
-  const ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_NONE);
-  const ui::Accelerator accelerator_b(ui::VKEY_B, ui::EF_NONE);
-  const ui::Accelerator accelerator_c(ui::VKEY_C, ui::EF_NONE);
-  const ui::Accelerator accelerator_d(ui::VKEY_D, ui::EF_NONE);
-
-  GetController()->Register(
-      {accelerator_a, accelerator_b, accelerator_c, accelerator_d}, &target);
-
-  // The registered accelerators are processed.
-  EXPECT_TRUE(ProcessInController(accelerator_a));
-  EXPECT_TRUE(ProcessInController(accelerator_b));
-  EXPECT_TRUE(ProcessInController(accelerator_c));
-  EXPECT_TRUE(ProcessInController(accelerator_d));
-  EXPECT_EQ(4, target.accelerator_pressed_count());
-}
-
-TEST_F(AcceleratorControllerTest, RegisterMultipleTarget) {
-  const ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_NONE);
-  TestTarget target1;
-  GetController()->Register({accelerator_a}, &target1);
-
-  TestTarget target2;
-  GetController()->Register({accelerator_a}, &target2);
-
-  // If multiple targets are registered with the same accelerator, the target
-  // registered later processes the accelerator.
-  EXPECT_TRUE(ProcessInController(accelerator_a));
-  EXPECT_EQ(0, target1.accelerator_pressed_count());
-  EXPECT_EQ(1, target2.accelerator_pressed_count());
-}
-
-TEST_F(AcceleratorControllerTest, Unregister) {
-  TestTarget target;
-  const ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_NONE);
-  const ui::Accelerator accelerator_b(ui::VKEY_B, ui::EF_NONE);
-  GetController()->Register({accelerator_a, accelerator_b}, &target);
-
-  // Unregistering a different accelerator does not affect the other
-  // accelerator.
-  GetController()->Unregister(accelerator_b, &target);
-  EXPECT_TRUE(ProcessInController(accelerator_a));
-  EXPECT_EQ(1, target.accelerator_pressed_count());
-
-  // The unregistered accelerator is no longer processed.
-  target.reset();
-  GetController()->Unregister(accelerator_a, &target);
-  EXPECT_FALSE(ProcessInController(accelerator_a));
-  EXPECT_EQ(0, target.accelerator_pressed_count());
-}
-
-TEST_F(AcceleratorControllerTest, UnregisterAll) {
-  TestTarget target1;
-  const ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_NONE);
-  const ui::Accelerator accelerator_b(ui::VKEY_B, ui::EF_NONE);
-  GetController()->Register({accelerator_a, accelerator_b}, &target1);
-  const ui::Accelerator accelerator_c(ui::VKEY_C, ui::EF_NONE);
-  TestTarget target2;
-  GetController()->Register({accelerator_c}, &target2);
-  GetController()->UnregisterAll(&target1);
-
-  // All the accelerators registered for |target1| are no longer processed.
-  EXPECT_FALSE(ProcessInController(accelerator_a));
-  EXPECT_FALSE(ProcessInController(accelerator_b));
-  EXPECT_EQ(0, target1.accelerator_pressed_count());
-
-  // UnregisterAll with a different target does not affect the other target.
-  EXPECT_TRUE(ProcessInController(accelerator_c));
-  EXPECT_EQ(1, target2.accelerator_pressed_count());
-}
-
-TEST_F(AcceleratorControllerTest, Process) {
-  const ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_NONE);
-  TestTarget target1;
-  GetController()->Register({accelerator_a}, &target1);
-
-  // The registered accelerator is processed.
-  EXPECT_TRUE(ProcessInController(accelerator_a));
-  EXPECT_EQ(1, target1.accelerator_pressed_count());
-
-  // The non-registered accelerator is not processed.
-  const ui::Accelerator accelerator_b(ui::VKEY_B, ui::EF_NONE);
-  EXPECT_FALSE(ProcessInController(accelerator_b));
-}
-
-TEST_F(AcceleratorControllerTest, IsRegistered) {
-  const ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_NONE);
-  const ui::Accelerator accelerator_shift_a(ui::VKEY_A, ui::EF_SHIFT_DOWN);
-  TestTarget target;
-  GetController()->Register({accelerator_a}, &target);
-  EXPECT_TRUE(GetController()->IsRegistered(accelerator_a));
-  EXPECT_FALSE(GetController()->IsRegistered(accelerator_shift_a));
-  GetController()->UnregisterAll(&target);
-  EXPECT_FALSE(GetController()->IsRegistered(accelerator_a));
-}
-
-TEST_F(AcceleratorControllerTest, WindowSnap) {
-  aura::Window* aura_window = CreateTestWindow(gfx::Rect(5, 5, 20, 20));
-  WmWindow* window = WmWindow::Get(aura_window);
-  wm::WindowState* window_state = window->GetWindowState();
-
-  window_state->Activate();
-
-  {
-    GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-    gfx::Rect expected_bounds =
-        wm::GetDefaultLeftSnappedWindowBoundsInParent(window);
-    EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString());
-  }
-  {
-    GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-    gfx::Rect expected_bounds =
-        wm::GetDefaultRightSnappedWindowBoundsInParent(window);
-    EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString());
-  }
-  {
-    gfx::Rect normal_bounds = window_state->GetRestoreBoundsInParent();
-
-    GetController()->PerformActionIfEnabled(TOGGLE_MAXIMIZED);
-    EXPECT_TRUE(window_state->IsMaximized());
-    EXPECT_NE(normal_bounds.ToString(), window->GetBounds().ToString());
-
-    GetController()->PerformActionIfEnabled(TOGGLE_MAXIMIZED);
-    EXPECT_FALSE(window_state->IsMaximized());
-    // Window gets restored to its restore bounds since side-maximized state
-    // is treated as a "maximized" state.
-    EXPECT_EQ(normal_bounds.ToString(), window->GetBounds().ToString());
-
-    GetController()->PerformActionIfEnabled(TOGGLE_MAXIMIZED);
-    GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-    EXPECT_FALSE(window_state->IsMaximized());
-
-    GetController()->PerformActionIfEnabled(TOGGLE_MAXIMIZED);
-    GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-    EXPECT_FALSE(window_state->IsMaximized());
-
-    GetController()->PerformActionIfEnabled(TOGGLE_MAXIMIZED);
-    EXPECT_TRUE(window_state->IsMaximized());
-    GetController()->PerformActionIfEnabled(WINDOW_MINIMIZE);
-    EXPECT_FALSE(window_state->IsMaximized());
-    EXPECT_TRUE(window_state->IsMinimized());
-    window_state->Restore();
-    window_state->Activate();
-  }
-  {
-    GetController()->PerformActionIfEnabled(WINDOW_MINIMIZE);
-    EXPECT_TRUE(window_state->IsMinimized());
-  }
-}
-
-// Tests that when window docking is disabled, only snapping windows works.
-TEST_F(AcceleratorControllerTest, WindowSnapWithoutDocking) {
-  ASSERT_FALSE(ash::switches::DockedWindowsEnabled());
-  WmWindow* window = WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20)));
-  wm::WindowState* window_state = window->GetWindowState();
-  window_state->Activate();
-
-  // Snap right.
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  gfx::Rect normal_bounds = window_state->GetRestoreBoundsInParent();
-  gfx::Rect expected_bounds =
-      wm::GetDefaultRightSnappedWindowBoundsInParent(window);
-  EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString());
-  EXPECT_TRUE(window_state->IsSnapped());
-  // Snap right again ->> becomes normal.
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_TRUE(window_state->IsNormalStateType());
-  EXPECT_FALSE(window_state->IsDocked());
-  EXPECT_EQ(normal_bounds.ToString(), window->GetBounds().ToString());
-  // Snap right.
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_TRUE(window_state->IsSnapped());
-  EXPECT_FALSE(window_state->IsDocked());
-  // Snap left.
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  EXPECT_TRUE(window_state->IsSnapped());
-  EXPECT_FALSE(window_state->IsDocked());
-  expected_bounds = wm::GetDefaultLeftSnappedWindowBoundsInParent(window);
-  EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString());
-  // Snap left again ->> becomes normal.
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  EXPECT_TRUE(window_state->IsNormalStateType());
-  EXPECT_FALSE(window_state->IsDocked());
-  EXPECT_EQ(normal_bounds.ToString(), window->GetBounds().ToString());
-}
-
-// Test class used for testing docked windows.
-class EnabledDockedWindowsAcceleratorControllerTest
-    : public AcceleratorControllerTest {
- public:
-  EnabledDockedWindowsAcceleratorControllerTest() = default;
-  ~EnabledDockedWindowsAcceleratorControllerTest() override = default;
-
-  void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        ash::switches::kAshEnableDockedWindows);
-    AcceleratorControllerTest::SetUp();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(EnabledDockedWindowsAcceleratorControllerTest);
-};
-
-TEST_F(EnabledDockedWindowsAcceleratorControllerTest,
-       WindowSnapLeftDockLeftRestore) {
-  CreateTestWindow(gfx::Rect(5, 5, 20, 20));
-  WmWindow* window1 = WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20)));
-  wm::WindowState* window1_state = window1->GetWindowState();
-  window1_state->Activate();
-
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  gfx::Rect normal_bounds = window1_state->GetRestoreBoundsInParent();
-  gfx::Rect expected_bounds =
-      wm::GetDefaultLeftSnappedWindowBoundsInParent(window1);
-  EXPECT_EQ(expected_bounds.ToString(), window1->GetBounds().ToString());
-  EXPECT_TRUE(window1_state->IsSnapped());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  EXPECT_FALSE(window1_state->IsNormalOrSnapped());
-  EXPECT_TRUE(window1_state->IsDocked());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  EXPECT_FALSE(window1_state->IsDocked());
-  EXPECT_EQ(normal_bounds.ToString(), window1->GetBounds().ToString());
-}
-
-TEST_F(EnabledDockedWindowsAcceleratorControllerTest,
-       WindowSnapRightDockRightRestore) {
-  CreateTestWindow(gfx::Rect(5, 5, 20, 20));
-  WmWindow* window1 = WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20)));
-
-  wm::WindowState* window1_state = window1->GetWindowState();
-  window1_state->Activate();
-
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  gfx::Rect normal_bounds = window1_state->GetRestoreBoundsInParent();
-  gfx::Rect expected_bounds =
-      wm::GetDefaultRightSnappedWindowBoundsInParent(window1);
-  EXPECT_EQ(expected_bounds.ToString(), window1->GetBounds().ToString());
-  EXPECT_TRUE(window1_state->IsSnapped());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_FALSE(window1_state->IsNormalOrSnapped());
-  EXPECT_TRUE(window1_state->IsDocked());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_FALSE(window1_state->IsDocked());
-  EXPECT_EQ(normal_bounds.ToString(), window1->GetBounds().ToString());
-}
-
-TEST_F(EnabledDockedWindowsAcceleratorControllerTest,
-       WindowSnapLeftDockLeftSnapRight) {
-  CreateTestWindow(gfx::Rect(5, 5, 20, 20));
-  WmWindow* window1 = WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20)));
-
-  wm::WindowState* window1_state = window1->GetWindowState();
-  window1_state->Activate();
-
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  gfx::Rect expected_bounds =
-      wm::GetDefaultLeftSnappedWindowBoundsInParent(window1);
-  gfx::Rect expected_bounds2 =
-      wm::GetDefaultRightSnappedWindowBoundsInParent(window1);
-  EXPECT_EQ(expected_bounds.ToString(), window1->GetBounds().ToString());
-  EXPECT_TRUE(window1_state->IsSnapped());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  EXPECT_FALSE(window1_state->IsNormalOrSnapped());
-  EXPECT_TRUE(window1_state->IsDocked());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_FALSE(window1_state->IsDocked());
-  EXPECT_TRUE(window1_state->IsSnapped());
-  EXPECT_EQ(expected_bounds2.ToString(), window1->GetBounds().ToString());
-}
-
-TEST_F(EnabledDockedWindowsAcceleratorControllerTest,
-       WindowDockLeftMinimizeWindowWithRestore) {
-  WindowOwner window_owner(
-      WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20))));
-  WindowOwner window1_owner(
-      WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20))));
-  WmWindow* window1 = window1_owner.window();
-
-  wm::WindowState* window1_state = window1->GetWindowState();
-  window1_state->Activate();
-
-  WindowOwner window2_owner(
-      WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20))));
-  WmWindow* window2 = window2_owner.window();
-
-  wm::WindowState* window2_state = window2->GetWindowState();
-
-  WindowOwner window3_owner(
-      WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20))));
-  WmWindow* window3 = window3_owner.window();
-
-  wm::WindowState* window3_state = window3->GetWindowState();
-  window3_state->Activate();
-
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  gfx::Rect window3_docked_bounds = window3->GetBounds();
-
-  window2_state->Activate();
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  window1_state->Activate();
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-
-  EXPECT_TRUE(window3_state->IsDocked());
-  EXPECT_TRUE(window2_state->IsDocked());
-  EXPECT_TRUE(window1_state->IsDocked());
-  EXPECT_TRUE(window3_state->IsMinimized());
-
-  window1_state->Activate();
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  window2_state->Activate();
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  window3_state->Unminimize();
-  EXPECT_FALSE(window1_state->IsDocked());
-  EXPECT_FALSE(window2_state->IsDocked());
-  EXPECT_TRUE(window3_state->IsDocked());
-  EXPECT_EQ(window3_docked_bounds.ToString(), window3->GetBounds().ToString());
-}
-
-// TODO: Needs CreatePanel(): http://crbug.com/632209.
-/*
-TEST_F(EnabledDockedWindowsAcceleratorControllerTest,
-       WindowPanelDockLeftDockRightRestore) {
-  WmWndow* window0 =
-      WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20)));
-
-  std::unique_ptr<aura::Window> window(CreatePanel());
-  wm::WindowState* window_state = wm::GetWindowState(window.get());
-  window_state->Activate();
-
-  gfx::Rect window_restore_bounds2 = window->bounds();
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_LEFT);
-  gfx::Rect expected_bounds = wm::GetDefaultLeftSnappedWindowBoundsInParent(
-      WmWindow::Get(window.get()));
-  gfx::Rect window_restore_bounds = window_state->GetRestoreBoundsInScreen();
-  EXPECT_NE(expected_bounds.ToString(), window->bounds().ToString());
-  EXPECT_FALSE(window_state->IsSnapped());
-  EXPECT_FALSE(window_state->IsNormalOrSnapped());
-  EXPECT_TRUE(window_state->IsDocked());
-  window_state->Restore();
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_TRUE(window_state->IsDocked());
-  GetController()->PerformActionIfEnabled(WINDOW_CYCLE_SNAP_DOCK_RIGHT);
-  EXPECT_FALSE(window_state->IsDocked());
-  EXPECT_EQ(window_restore_bounds.ToString(),
-            window_restore_bounds2.ToString());
-  EXPECT_EQ(window_restore_bounds.ToString(), window->bounds().ToString());
-}
-*/
-
-TEST_F(EnabledDockedWindowsAcceleratorControllerTest, CenterWindowAccelerator) {
-  WindowOwner window_owner(
-      WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20))));
-  WmWindow* window = window_owner.window();
-  wm::WindowState* window_state = window->GetWindowState();
-  window_state->Activate();
-
-  // Center the window using accelerator.
-  GetController()->PerformActionIfEnabled(WINDOW_POSITION_CENTER);
-  gfx::Rect work_area = window->GetDisplayNearestWindow().work_area();
-  gfx::Rect bounds = window->GetBoundsInScreen();
-  EXPECT_NEAR(bounds.x() - work_area.x(), work_area.right() - bounds.right(),
-              1);
-  EXPECT_NEAR(bounds.y() - work_area.y(), work_area.bottom() - bounds.bottom(),
-              1);
-
-  // Add the window to docked container and try to center it.
-  window->SetBounds(gfx::Rect(0, 0, 20, 20));
-  const wm::WMEvent event(wm::WM_EVENT_DOCK);
-  window->GetWindowState()->OnWMEvent(&event);
-  EXPECT_EQ(kShellWindowId_DockedContainer,
-            window->GetParent()->GetShellWindowId());
-
-  gfx::Rect docked_bounds = window->GetBoundsInScreen();
-  GetController()->PerformActionIfEnabled(WINDOW_POSITION_CENTER);
-  // It should not get centered and should remain docked.
-  EXPECT_EQ(kShellWindowId_DockedContainer,
-            window->GetParent()->GetShellWindowId());
-  EXPECT_EQ(docked_bounds.ToString(), window->GetBoundsInScreen().ToString());
-}
-
-// This is commented out for two reasons:
-// . http://crbug.com/630683: ash doesn't see all key events.
-// . http://crbug.com/615033: EventGenerator doesn't work with ash. That can be
-//   worked around for the test, but no point until we decide on the first one.
-/*
-TEST_F(AcceleratorControllerTest, AutoRepeat) {
-  ui::Accelerator accelerator_a(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-  accelerator_a.set_type(ui::ET_KEY_PRESSED);
-  TestTarget target_a;
-  GetController()->Register(accelerator_a, &target_a);
-  ui::Accelerator accelerator_b(ui::VKEY_B, ui::EF_CONTROL_DOWN);
-  accelerator_b.set_type(ui::ET_KEY_PRESSED);
-  TestTarget target_b;
-  GetController()->Register(accelerator_b, &target_b);
-
-  ui::test::EventGenerator& generator = GetEventGenerator();
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-  generator.ReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-
-  EXPECT_EQ(1, target_a.accelerator_pressed_count());
-  EXPECT_EQ(0, target_a.accelerator_repeat_count());
-
-  // Long press should generate one
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN | ui::EF_IS_REPEAT);
-  EXPECT_EQ(2, target_a.accelerator_pressed_count());
-  EXPECT_EQ(1, target_a.accelerator_repeat_count());
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN | ui::EF_IS_REPEAT);
-  EXPECT_EQ(2, target_a.accelerator_pressed_count());
-  EXPECT_EQ(2, target_a.accelerator_repeat_count());
-  generator.ReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-  EXPECT_EQ(2, target_a.accelerator_pressed_count());
-  EXPECT_EQ(2, target_a.accelerator_repeat_count());
-
-  // Long press was intercepted by another key press.
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN | ui::EF_IS_REPEAT);
-  generator.PressKey(ui::VKEY_B, ui::EF_CONTROL_DOWN);
-  generator.ReleaseKey(ui::VKEY_B, ui::EF_CONTROL_DOWN);
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-  generator.PressKey(ui::VKEY_A, ui::EF_CONTROL_DOWN | ui::EF_IS_REPEAT);
-  generator.ReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
-
-  EXPECT_EQ(1, target_b.accelerator_pressed_count());
-  EXPECT_EQ(0, target_b.accelerator_repeat_count());
-  EXPECT_EQ(4, target_a.accelerator_pressed_count());
-  EXPECT_EQ(4, target_a.accelerator_repeat_count());
-}
-*/
-
-// TODO: update once http://crbug.com/630683 is resolved.
-/*
-TEST_F(AcceleratorControllerTest, Previous) {
-  ui::test::EventGenerator& generator = GetEventGenerator();
-  generator.PressKey(ui::VKEY_VOLUME_MUTE, ui::EF_NONE);
-  generator.ReleaseKey(ui::VKEY_VOLUME_MUTE, ui::EF_NONE);
-
-  EXPECT_EQ(ui::VKEY_VOLUME_MUTE, GetPreviousAccelerator().key_code());
-  EXPECT_EQ(ui::EF_NONE, GetPreviousAccelerator().modifiers());
-
-  generator.PressKey(ui::VKEY_TAB, ui::EF_CONTROL_DOWN);
-  generator.ReleaseKey(ui::VKEY_TAB, ui::EF_CONTROL_DOWN);
-
-  EXPECT_EQ(ui::VKEY_TAB, GetPreviousAccelerator().key_code());
-  EXPECT_EQ(ui::EF_CONTROL_DOWN, GetPreviousAccelerator().modifiers());
-}
-*/
-
-TEST_F(AcceleratorControllerTest, DontRepeatToggleFullscreen) {
-  const AcceleratorData accelerators[] = {
-      {true, ui::VKEY_J, ui::EF_ALT_DOWN, TOGGLE_FULLSCREEN},
-      {true, ui::VKEY_K, ui::EF_ALT_DOWN, TOGGLE_FULLSCREEN},
-  };
-  GetController()->RegisterAccelerators(accelerators, arraysize(accelerators));
-
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
-  params.bounds = gfx::Rect(5, 5, 20, 20);
-  views::Widget* widget = new views::Widget;
-  WmWindow::Get(GetPrimaryRootWindow())
-      ->GetRootWindowController()
-      ->ConfigureWidgetInitParamsForContainer(
-          widget, kShellWindowId_DefaultContainer, &params);
-  widget->Init(params);
-  widget->GetNativeView()->SetProperty(aura::client::kResizeBehaviorKey,
-                                       ui::mojom::kResizeBehaviorCanMaximize);
-  widget->Show();
-  widget->Activate();
-
-  wm::WindowState* window_state =
-      WmLookup::Get()->GetWindowForWidget(widget)->GetWindowState();
-
-  // Toggling not suppressed.
-  ProcessAccelerator(ui::VKEY_J, ui::EF_ALT_DOWN);
-  EXPECT_TRUE(window_state->IsFullscreen());
-
-  // The same accelerator - toggling suppressed.
-  ProcessAccelerator(ui::VKEY_J, ui::EF_ALT_DOWN | ui::EF_IS_REPEAT);
-  EXPECT_TRUE(window_state->IsFullscreen());
-
-  // Different accelerator.
-  ProcessAccelerator(ui::VKEY_K, ui::EF_ALT_DOWN);
-  EXPECT_FALSE(window_state->IsFullscreen());
-}
-
-TEST_F(AcceleratorControllerTest, GlobalAccelerators) {
-  // CycleBackward
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)));
-  // CycleForward
-  EXPECT_TRUE(
-      ProcessInController(ui::Accelerator(ui::VKEY_TAB, ui::EF_ALT_DOWN)));
-  // CycleLinear
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE)));
-
-  // The "Take Screenshot", "Take Partial Screenshot", volume, brightness, and
-  // keyboard brightness accelerators are only defined on ChromeOS.
-  // TODO: needs ScreenShotDelegate converted: http://crbug.com/612331.
-  /*
-  {
-    test::TestScreenshotDelegate* delegate = GetScreenshotDelegate();
-    delegate->set_can_take_screenshot(false);
-    EXPECT_TRUE(ProcessInController(
-        ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
-    EXPECT_TRUE(
-        ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
-    EXPECT_TRUE(ProcessInController(ui::Accelerator(
-        ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
-
-    delegate->set_can_take_screenshot(true);
-    EXPECT_EQ(0, delegate->handle_take_screenshot_count());
-    EXPECT_TRUE(ProcessInController(
-        ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
-    EXPECT_EQ(1, delegate->handle_take_screenshot_count());
-    EXPECT_TRUE(
-        ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
-    EXPECT_EQ(2, delegate->handle_take_screenshot_count());
-    EXPECT_TRUE(ProcessInController(ui::Accelerator(
-        ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
-    EXPECT_EQ(2, delegate->handle_take_screenshot_count());
-  }
-  */
-  const ui::Accelerator volume_mute(ui::VKEY_VOLUME_MUTE, ui::EF_NONE);
-  const ui::Accelerator volume_down(ui::VKEY_VOLUME_DOWN, ui::EF_NONE);
-  const ui::Accelerator volume_up(ui::VKEY_VOLUME_UP, ui::EF_NONE);
-  {
-    base::UserActionTester user_action_tester;
-    ui::AcceleratorHistory* history = GetController()->accelerator_history();
-
-    EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
-    EXPECT_TRUE(ProcessInController(volume_mute));
-    EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
-    EXPECT_EQ(volume_mute, history->current_accelerator());
-
-    EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
-    EXPECT_TRUE(ProcessInController(volume_down));
-    EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
-    EXPECT_EQ(volume_down, history->current_accelerator());
-
-    EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
-    EXPECT_TRUE(ProcessInController(volume_up));
-    EXPECT_EQ(volume_up, history->current_accelerator());
-    EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
-  }
-  // Brightness
-  // ui::VKEY_BRIGHTNESS_DOWN/UP are not defined on Windows.
-  const ui::Accelerator brightness_down(ui::VKEY_BRIGHTNESS_DOWN, ui::EF_NONE);
-  const ui::Accelerator brightness_up(ui::VKEY_BRIGHTNESS_UP, ui::EF_NONE);
-  {
-    DummyBrightnessControlDelegate* delegate =
-        new DummyBrightnessControlDelegate;
-    SetBrightnessControlDelegate(
-        std::unique_ptr<BrightnessControlDelegate>(delegate));
-    EXPECT_EQ(0, delegate->handle_brightness_down_count());
-    EXPECT_TRUE(ProcessInController(brightness_down));
-    EXPECT_EQ(1, delegate->handle_brightness_down_count());
-    EXPECT_EQ(brightness_down, delegate->last_accelerator());
-    EXPECT_EQ(0, delegate->handle_brightness_up_count());
-    EXPECT_TRUE(ProcessInController(brightness_up));
-    EXPECT_EQ(1, delegate->handle_brightness_up_count());
-    EXPECT_EQ(brightness_up, delegate->last_accelerator());
-  }
-
-  // Keyboard brightness
-  const ui::Accelerator alt_brightness_down(ui::VKEY_BRIGHTNESS_DOWN,
-                                            ui::EF_ALT_DOWN);
-  const ui::Accelerator alt_brightness_up(ui::VKEY_BRIGHTNESS_UP,
-                                          ui::EF_ALT_DOWN);
-  {
-    EXPECT_TRUE(ProcessInController(alt_brightness_down));
-    EXPECT_TRUE(ProcessInController(alt_brightness_up));
-    DummyKeyboardBrightnessControlDelegate* delegate =
-        new DummyKeyboardBrightnessControlDelegate;
-    SetKeyboardBrightnessControlDelegate(
-        std::unique_ptr<KeyboardBrightnessControlDelegate>(delegate));
-    EXPECT_EQ(0, delegate->handle_keyboard_brightness_down_count());
-    EXPECT_TRUE(ProcessInController(alt_brightness_down));
-    EXPECT_EQ(1, delegate->handle_keyboard_brightness_down_count());
-    EXPECT_EQ(alt_brightness_down, delegate->last_accelerator());
-    EXPECT_EQ(0, delegate->handle_keyboard_brightness_up_count());
-    EXPECT_TRUE(ProcessInController(alt_brightness_up));
-    EXPECT_EQ(1, delegate->handle_keyboard_brightness_up_count());
-    EXPECT_EQ(alt_brightness_up, delegate->last_accelerator());
-  }
-
-  // Exit
-  ExitWarningHandler* ewh = GetController()->GetExitWarningHandlerForTest();
-  ASSERT_TRUE(ewh);
-  StubForTest(ewh);
-  EXPECT_TRUE(is_idle(ewh));
-  EXPECT_FALSE(is_ui_shown(ewh));
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_Q, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
-  EXPECT_FALSE(is_idle(ewh));
-  EXPECT_TRUE(is_ui_shown(ewh));
-  SimulateTimerExpired(ewh);
-  EXPECT_TRUE(is_idle(ewh));
-  EXPECT_FALSE(is_ui_shown(ewh));
-  Reset(ewh);
-
-  // New tab
-  EXPECT_TRUE(
-      ProcessInController(ui::Accelerator(ui::VKEY_T, ui::EF_CONTROL_DOWN)));
-
-  // New incognito window
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
-
-  // New window
-  EXPECT_TRUE(
-      ProcessInController(ui::Accelerator(ui::VKEY_N, ui::EF_CONTROL_DOWN)));
-
-  // Restore tab
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
-
-  // Show task manager
-  EXPECT_TRUE(
-      ProcessInController(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN)));
-
-  // Open file manager
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_M, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)));
-
-  // Lock screen
-  // TODO(derat): Reenable this once user sessions work in mash.
-  EXPECT_FALSE(
-      ProcessInController(ui::Accelerator(ui::VKEY_L, ui::EF_COMMAND_DOWN)));
-}
-
-// TODO: fails in mash, http://crbug.com/632180.
-TEST_F(AcceleratorControllerTest, DISABLED_GlobalAcceleratorsToggleAppList) {
-  AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate();
-  EXPECT_FALSE(WmShell::Get()->GetAppListTargetVisibility());
-
-  // The press event should not open the AppList, the release should instead.
-  EXPECT_FALSE(
-      ProcessInController(ui::Accelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  EXPECT_EQ(ui::VKEY_LWIN, GetCurrentAccelerator().key_code());
-
-  EXPECT_FALSE(WmShell::Get()->GetAppListTargetVisibility());
-
-  EXPECT_TRUE(
-      ProcessInController(ReleaseAccelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  EXPECT_TRUE(WmShell::Get()->GetAppListTargetVisibility());
-
-  EXPECT_EQ(ui::VKEY_LWIN, GetPreviousAccelerator().key_code());
-
-  // When spoken feedback is on, the AppList should not toggle.
-  delegate->ToggleSpokenFeedback(A11Y_NOTIFICATION_NONE);
-  EXPECT_FALSE(
-      ProcessInController(ui::Accelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  EXPECT_FALSE(
-      ProcessInController(ReleaseAccelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  delegate->ToggleSpokenFeedback(A11Y_NOTIFICATION_NONE);
-  EXPECT_TRUE(WmShell::Get()->GetAppListTargetVisibility());
-
-  EXPECT_FALSE(
-      ProcessInController(ui::Accelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  EXPECT_TRUE(
-      ProcessInController(ReleaseAccelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  EXPECT_FALSE(WmShell::Get()->GetAppListTargetVisibility());
-
-  // When spoken feedback is on, the AppList should not toggle.
-  delegate->ToggleSpokenFeedback(A11Y_NOTIFICATION_NONE);
-  EXPECT_FALSE(
-      ProcessInController(ui::Accelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  EXPECT_FALSE(
-      ProcessInController(ReleaseAccelerator(ui::VKEY_LWIN, ui::EF_NONE)));
-  delegate->ToggleSpokenFeedback(A11Y_NOTIFICATION_NONE);
-  EXPECT_FALSE(WmShell::Get()->GetAppListTargetVisibility());
-
-  // The press of VKEY_BROWSER_SEARCH should toggle the AppList
-  EXPECT_TRUE(ProcessInController(
-      ui::Accelerator(ui::VKEY_BROWSER_SEARCH, ui::EF_NONE)));
-  EXPECT_TRUE(WmShell::Get()->GetAppListTargetVisibility());
-  EXPECT_FALSE(ProcessInController(
-      ReleaseAccelerator(ui::VKEY_BROWSER_SEARCH, ui::EF_NONE)));
-  EXPECT_TRUE(WmShell::Get()->GetAppListTargetVisibility());
-}
-
-TEST_F(AcceleratorControllerTest, ImeGlobalAccelerators) {
-  // Test IME shortcuts.
-  ui::Accelerator control_space_down(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
-  control_space_down.set_type(ui::ET_KEY_PRESSED);
-  ui::Accelerator control_space_up(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
-  control_space_up.set_type(ui::ET_KEY_RELEASED);
-  const ui::Accelerator convert(ui::VKEY_CONVERT, ui::EF_NONE);
-  const ui::Accelerator non_convert(ui::VKEY_NONCONVERT, ui::EF_NONE);
-  const ui::Accelerator wide_half_1(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE);
-  const ui::Accelerator wide_half_2(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE);
-  const ui::Accelerator hangul(ui::VKEY_HANGUL, ui::EF_NONE);
-  EXPECT_FALSE(ProcessInController(control_space_down));
-  EXPECT_FALSE(ProcessInController(control_space_up));
-  EXPECT_FALSE(ProcessInController(convert));
-  EXPECT_FALSE(ProcessInController(non_convert));
-  EXPECT_FALSE(ProcessInController(wide_half_1));
-  EXPECT_FALSE(ProcessInController(wide_half_2));
-  EXPECT_FALSE(ProcessInController(hangul));
-  DummyImeControlDelegate* delegate = new DummyImeControlDelegate;
-  GetController()->SetImeControlDelegate(
-      std::unique_ptr<ImeControlDelegate>(delegate));
-  EXPECT_EQ(0, delegate->handle_previous_ime_count());
-  EXPECT_TRUE(ProcessInController(control_space_down));
-  EXPECT_EQ(1, delegate->handle_previous_ime_count());
-  EXPECT_TRUE(ProcessInController(control_space_up));
-  EXPECT_EQ(1, delegate->handle_previous_ime_count());
-  EXPECT_EQ(0, delegate->handle_switch_ime_count());
-  EXPECT_TRUE(ProcessInController(convert));
-  EXPECT_EQ(1, delegate->handle_switch_ime_count());
-  EXPECT_TRUE(ProcessInController(non_convert));
-  EXPECT_EQ(2, delegate->handle_switch_ime_count());
-  EXPECT_TRUE(ProcessInController(wide_half_1));
-  EXPECT_EQ(3, delegate->handle_switch_ime_count());
-  EXPECT_TRUE(ProcessInController(wide_half_2));
-  EXPECT_EQ(4, delegate->handle_switch_ime_count());
-  EXPECT_TRUE(ProcessInController(hangul));
-  EXPECT_EQ(5, delegate->handle_switch_ime_count());
-}
-
-// TODO(nona|mazda): Remove this when crbug.com/139556 in a better way.
-TEST_F(AcceleratorControllerTest, ImeGlobalAcceleratorsWorkaround139556) {
-  // The workaround for crbug.com/139556 depends on the fact that we don't
-  // use Shift+Alt+Enter/Space with ET_KEY_PRESSED as an accelerator. Test it.
-  const ui::Accelerator shift_alt_return_press(
-      ui::VKEY_RETURN, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
-  EXPECT_FALSE(ProcessInController(shift_alt_return_press));
-  const ui::Accelerator shift_alt_space_press(
-      ui::VKEY_SPACE, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
-  EXPECT_FALSE(ProcessInController(shift_alt_space_press));
-}
-
-TEST_F(AcceleratorControllerTest, PreferredReservedAccelerators) {
-  // Power key is reserved on chromeos.
-  EXPECT_TRUE(GetController()->IsReserved(
-      ui::Accelerator(ui::VKEY_POWER, ui::EF_NONE)));
-  EXPECT_FALSE(GetController()->IsPreferred(
-      ui::Accelerator(ui::VKEY_POWER, ui::EF_NONE)));
-  // ALT+Tab are not reserved but preferred.
-  EXPECT_FALSE(GetController()->IsReserved(
-      ui::Accelerator(ui::VKEY_TAB, ui::EF_ALT_DOWN)));
-  EXPECT_FALSE(GetController()->IsReserved(
-      ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)));
-  EXPECT_TRUE(GetController()->IsPreferred(
-      ui::Accelerator(ui::VKEY_TAB, ui::EF_ALT_DOWN)));
-  EXPECT_TRUE(GetController()->IsPreferred(
-      ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)));
-
-  // Others are not reserved nor preferred
-  EXPECT_FALSE(GetController()->IsReserved(
-      ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
-  EXPECT_FALSE(GetController()->IsPreferred(
-      ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
-  EXPECT_FALSE(
-      GetController()->IsReserved(ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE)));
-  EXPECT_FALSE(
-      GetController()->IsPreferred(ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE)));
-  EXPECT_FALSE(
-      GetController()->IsReserved(ui::Accelerator(ui::VKEY_A, ui::EF_NONE)));
-  EXPECT_FALSE(
-      GetController()->IsPreferred(ui::Accelerator(ui::VKEY_A, ui::EF_NONE)));
-}
-
-/*
-namespace {
-
-class PreferredReservedAcceleratorsTest : public test::AshTestBase {
- public:
-  PreferredReservedAcceleratorsTest() {}
-  ~PreferredReservedAcceleratorsTest() override {}
-
-  // test::AshTestBase:
-  void SetUp() override {
-    AshTestBase::SetUp();
-    Shell::GetInstance()->lock_state_controller()->set_animator_for_test(
-        new test::TestSessionStateAnimator);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PreferredReservedAcceleratorsTest);
-};
-
-}  // namespace
-
-// TODO: needs LockStateController ported: http://crbug.com/632189.
-TEST_F(PreferredReservedAcceleratorsTest, AcceleratorsWithFullscreen) {
-  WmWindow* w1 = WmWindow::Get(CreateTestWindow(gfx::Rect()));
-  WmWindow* w2 = WmWindow::Get(CreateTestWindow(gfx::Rect()));
-  wm::ActivateWindow(w1);
-
-  wm::WMEvent fullscreen(wm::WM_EVENT_FULLSCREEN);
-  wm::WindowState* w1_state = w1->GetWindowState();
-  w1_state->OnWMEvent(&fullscreen);
-  ASSERT_TRUE(w1_state->IsFullscreen());
-
-  ui::test::EventGenerator& generator = GetEventGenerator();
-  // Power key (reserved) should always be handled.
-  LockStateController::TestApi test_api(
-      Shell::GetInstance()->lock_state_controller());
-  EXPECT_FALSE(test_api.is_animating_lock());
-  generator.PressKey(ui::VKEY_POWER, ui::EF_NONE);
-  EXPECT_TRUE(test_api.is_animating_lock());
-
-  // A fullscreen window can consume ALT-TAB (preferred).
-  ASSERT_EQ(w1, wm::GetActiveWindow());
-  generator.PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
-  ASSERT_EQ(w1, wm::GetActiveWindow());
-  ASSERT_NE(w2, wm::GetActiveWindow());
-
-  // ALT-TAB is non repeatable. Press A to cancel the
-  // repeat record.
-  generator.PressKey(ui::VKEY_A, ui::EF_NONE);
-  generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE);
-
-  // A normal window shouldn't consume preferred accelerator.
-  wm::WMEvent normal(wm::WM_EVENT_NORMAL);
-  w1_state->OnWMEvent(&normal);
-  ASSERT_FALSE(w1_state->IsFullscreen());
-
-  EXPECT_EQ(w1, wm::GetActiveWindow());
-  generator.PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
-  ASSERT_NE(w1, wm::GetActiveWindow());
-  ASSERT_EQ(w2, wm::GetActiveWindow());
-}
-
-// TODO: needs LockStateController ported: http://crbug.com/632189.
-TEST_F(PreferredReservedAcceleratorsTest, AcceleratorsWithPinned) {
-  aura::Window* w1 = CreateTestWindowInShellWithId(0);
-  aura::Window* w2 = CreateTestWindowInShellWithId(1);
-  wm::ActivateWindow(w1);
-
-  {
-    wm::WMEvent pin_event(wm::WM_EVENT_PIN);
-    wm::WindowState* w1_state = wm::GetWindowState(w1);
-    w1_state->OnWMEvent(&pin_event);
-    ASSERT_TRUE(w1_state->IsPinned());
-  }
-
-  ui::test::EventGenerator& generator = GetEventGenerator();
-  // Power key (reserved) should always be handled.
-  LockStateController::TestApi test_api(
-      Shell::GetInstance()->lock_state_controller());
-  EXPECT_FALSE(test_api.is_animating_lock());
-  generator.PressKey(ui::VKEY_POWER, ui::EF_NONE);
-  EXPECT_TRUE(test_api.is_animating_lock());
-
-  // A pinned window can consume ALT-TAB (preferred), but no side effect.
-  ASSERT_EQ(w1, wm::GetActiveWindow());
-  generator.PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
-  generator.ReleaseKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
-  ASSERT_EQ(w1, wm::GetActiveWindow());
-  ASSERT_NE(w2, wm::GetActiveWindow());
-}
-*/
-
-TEST_F(AcceleratorControllerTest, DisallowedAtModalWindow) {
-  std::set<AcceleratorAction> all_actions;
-  for (size_t i = 0; i < kAcceleratorDataLength; ++i)
-    all_actions.insert(kAcceleratorData[i].action);
-  std::set<AcceleratorAction> all_debug_actions;
-  for (size_t i = 0; i < kDebugAcceleratorDataLength; ++i)
-    all_debug_actions.insert(kDebugAcceleratorData[i].action);
-  std::set<AcceleratorAction> all_dev_actions;
-  for (size_t i = 0; i < kDeveloperAcceleratorDataLength; ++i)
-    all_dev_actions.insert(kDeveloperAcceleratorData[i].action);
-
-  std::set<AcceleratorAction> actionsAllowedAtModalWindow;
-  for (size_t k = 0; k < kActionsAllowedAtModalWindowLength; ++k)
-    actionsAllowedAtModalWindow.insert(kActionsAllowedAtModalWindow[k]);
-  for (const auto& action : actionsAllowedAtModalWindow) {
-    EXPECT_TRUE(all_actions.find(action) != all_actions.end() ||
-                all_debug_actions.find(action) != all_debug_actions.end() ||
-                all_dev_actions.find(action) != all_dev_actions.end())
-        << " action from kActionsAllowedAtModalWindow"
-        << " not found in kAcceleratorData, kDebugAcceleratorData or"
-        << " kDeveloperAcceleratorData action: " << action;
-  }
-  WmWindow* window = WmWindow::Get(CreateTestWindow(gfx::Rect(5, 5, 20, 20)));
-  window->Activate();
-  WmShell::Get()->SimulateModalWindowOpenForTesting(true);
-  for (const auto& action : all_actions) {
-    if (actionsAllowedAtModalWindow.find(action) ==
-        actionsAllowedAtModalWindow.end()) {
-      EXPECT_TRUE(GetController()->PerformActionIfEnabled(action))
-          << " for action (disallowed at modal window): " << action;
-    }
-  }
-  //  Testing of top row (F5-F10) accelerators that should still work
-  //  when a modal window is open
-  //
-  // Screenshot
-  // TODO: needs ScreenShotDelegate converted: http://crbug.com/612331.
-  /*
-    {
-      test::TestScreenshotDelegate* delegate = GetScreenshotDelegate();
-      delegate->set_can_take_screenshot(false);
-      EXPECT_TRUE(ProcessInController(
-          ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
-      EXPECT_TRUE(
-          ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
-      EXPECT_TRUE(ProcessInController(ui::Accelerator(
-          ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN |
-    ui::EF_CONTROL_DOWN)));
-      delegate->set_can_take_screenshot(true);
-      EXPECT_EQ(0, delegate->handle_take_screenshot_count());
-      EXPECT_TRUE(ProcessInController(
-          ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN)));
-      EXPECT_EQ(1, delegate->handle_take_screenshot_count());
-      EXPECT_TRUE(
-          ProcessInController(ui::Accelerator(ui::VKEY_PRINT, ui::EF_NONE)));
-      EXPECT_EQ(2, delegate->handle_take_screenshot_count());
-      EXPECT_TRUE(ProcessInController(ui::Accelerator(
-          ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN |
-    ui::EF_CONTROL_DOWN)));
-      EXPECT_EQ(2, delegate->handle_take_screenshot_count());
-    }
-  */
-  // Brightness
-  const ui::Accelerator brightness_down(ui::VKEY_BRIGHTNESS_DOWN, ui::EF_NONE);
-  const ui::Accelerator brightness_up(ui::VKEY_BRIGHTNESS_UP, ui::EF_NONE);
-  {
-    DummyBrightnessControlDelegate* delegate =
-        new DummyBrightnessControlDelegate;
-    SetBrightnessControlDelegate(
-        std::unique_ptr<BrightnessControlDelegate>(delegate));
-    EXPECT_EQ(0, delegate->handle_brightness_down_count());
-    EXPECT_TRUE(ProcessInController(brightness_down));
-    EXPECT_EQ(1, delegate->handle_brightness_down_count());
-    EXPECT_EQ(brightness_down, delegate->last_accelerator());
-    EXPECT_EQ(0, delegate->handle_brightness_up_count());
-    EXPECT_TRUE(ProcessInController(brightness_up));
-    EXPECT_EQ(1, delegate->handle_brightness_up_count());
-    EXPECT_EQ(brightness_up, delegate->last_accelerator());
-  }
-  // Volume
-  const ui::Accelerator volume_mute(ui::VKEY_VOLUME_MUTE, ui::EF_NONE);
-  const ui::Accelerator volume_down(ui::VKEY_VOLUME_DOWN, ui::EF_NONE);
-  const ui::Accelerator volume_up(ui::VKEY_VOLUME_UP, ui::EF_NONE);
-  {
-    base::UserActionTester user_action_tester;
-    ui::AcceleratorHistory* history = GetController()->accelerator_history();
-
-    EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
-    EXPECT_TRUE(ProcessInController(volume_mute));
-    EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeMute_F8"));
-    EXPECT_EQ(volume_mute, history->current_accelerator());
-
-    EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
-    EXPECT_TRUE(ProcessInController(volume_down));
-    EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeDown_F9"));
-    EXPECT_EQ(volume_down, history->current_accelerator());
-
-    EXPECT_EQ(0, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
-    EXPECT_TRUE(ProcessInController(volume_up));
-    EXPECT_EQ(volume_up, history->current_accelerator());
-    EXPECT_EQ(1, user_action_tester.GetActionCount("Accel_VolumeUp_F10"));
-  }
-}
-
-// TODO: reenable. Disabled because shelf asynchronously created:
-// http://crbug.com/632192.
-TEST_F(AcceleratorControllerTest, DISABLED_DisallowedWithNoWindow) {
-  AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate();
-
-  for (size_t i = 0; i < kActionsNeedingWindowLength; ++i) {
-    delegate->TriggerAccessibilityAlert(A11Y_ALERT_NONE);
-    EXPECT_TRUE(
-        GetController()->PerformActionIfEnabled(kActionsNeedingWindow[i]));
-    EXPECT_EQ(delegate->GetLastAccessibilityAlert(), A11Y_ALERT_WINDOW_NEEDED);
-  }
-
-  // Make sure we don't alert if we do have a window.
-  for (size_t i = 0; i < kActionsNeedingWindowLength; ++i) {
-    aura::Window* aura_window = CreateTestWindow(gfx::Rect(5, 5, 20, 20));
-    WmWindow::Get(aura_window)->Activate();
-    delegate->TriggerAccessibilityAlert(A11Y_ALERT_NONE);
-    GetController()->PerformActionIfEnabled(kActionsNeedingWindow[i]);
-    EXPECT_NE(delegate->GetLastAccessibilityAlert(), A11Y_ALERT_WINDOW_NEEDED);
-    delete aura_window;
-  }
-
-  // Don't alert if we have a minimized window either.
-  for (size_t i = 0; i < kActionsNeedingWindowLength; ++i) {
-    aura::Window* aura_window = CreateTestWindow(gfx::Rect(5, 5, 20, 20));
-    WmWindow::Get(aura_window)->Activate();
-    GetController()->PerformActionIfEnabled(WINDOW_MINIMIZE);
-    delegate->TriggerAccessibilityAlert(A11Y_ALERT_NONE);
-    GetController()->PerformActionIfEnabled(kActionsNeedingWindow[i]);
-    EXPECT_NE(delegate->GetLastAccessibilityAlert(), A11Y_ALERT_WINDOW_NEEDED);
-    delete aura_window;
-  }
-}
-
-namespace {
-
-// defines a class to test the behavior of deprecated accelerators.
-class DeprecatedAcceleratorTester : public AcceleratorControllerTest {
- public:
-  DeprecatedAcceleratorTester() {}
-  ~DeprecatedAcceleratorTester() override {}
-
-  // TODO: this override should be removed and put in WmTestBase.
-  // http://crbug.com/632200.
-  void UnblockUserSession() {}
-
-  void SetUp() override {
-    AcceleratorControllerTest::SetUp();
-
-    // For testing the deprecated and new IME shortcuts.
-    DummyImeControlDelegate* delegate = new DummyImeControlDelegate;
-    GetController()->SetImeControlDelegate(
-        std::unique_ptr<ImeControlDelegate>(delegate));
-  }
-
-  ui::Accelerator CreateAccelerator(const AcceleratorData& data) const {
-    ui::Accelerator result(data.keycode, data.modifiers);
-    result.set_type(data.trigger_on_press ? ui::ET_KEY_PRESSED
-                                          : ui::ET_KEY_RELEASED);
-    return result;
-  }
-
-  void ResetStateIfNeeded() {
-    if (WmShell::Get()->GetSessionStateDelegate()->IsScreenLocked() ||
-        WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked()) {
-      UnblockUserSession();
-    }
-  }
-
-  bool ContainsDeprecatedAcceleratorNotification(const char* const id) const {
-    return nullptr != message_center()->FindVisibleNotificationById(id);
-  }
-
-  bool IsMessageCenterEmpty() const {
-    return message_center()->GetVisibleNotifications().empty();
-  }
-
-  void RemoveAllNotifications() const {
-    message_center()->RemoveAllNotifications(
-        false /* by_user */, message_center::MessageCenter::RemoveType::ALL);
-  }
-
-  message_center::MessageCenter* message_center() const {
-    return message_center::MessageCenter::Get();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DeprecatedAcceleratorTester);
-};
-
-}  // namespace
-
-// TODO: disabled because of UnblockUserSession() not working:
-// http://crbug.com/632201.
-TEST_F(DeprecatedAcceleratorTester,
-       DISABLED_TestDeprecatedAcceleratorsBehavior) {
-  for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) {
-    const AcceleratorData& entry = kDeprecatedAccelerators[i];
-
-    auto itr = GetController()->actions_with_deprecations_.find(entry.action);
-    ASSERT_TRUE(itr != GetController()->actions_with_deprecations_.end());
-    const DeprecatedAcceleratorData* data = itr->second;
-
-    EXPECT_TRUE(IsMessageCenterEmpty());
-    ui::Accelerator deprecated_accelerator = CreateAccelerator(entry);
-    if (data->deprecated_enabled)
-      EXPECT_TRUE(ProcessInController(deprecated_accelerator));
-    else
-      EXPECT_FALSE(ProcessInController(deprecated_accelerator));
-
-    // We expect to see a notification in the message center.
-    EXPECT_TRUE(
-        ContainsDeprecatedAcceleratorNotification(data->uma_histogram_name));
-    RemoveAllNotifications();
-
-    // If the action is LOCK_SCREEN, we must reset the state by unlocking the
-    // screen before we proceed testing the rest of accelerators.
-    ResetStateIfNeeded();
-  }
-}
-
-// TODO: disabled because of UnblockUserSession() not working:
-// http://crbug.com/632201.
-TEST_F(DeprecatedAcceleratorTester, DISABLED_TestNewAccelerators) {
-  // Add below the new accelerators that replaced the deprecated ones (if any).
-  const AcceleratorData kNewAccelerators[] = {
-      {true, ui::VKEY_L, ui::EF_COMMAND_DOWN, LOCK_SCREEN},
-      {true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, NEXT_IME},
-      {true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN, SHOW_TASK_MANAGER},
-  };
-
-  EXPECT_TRUE(IsMessageCenterEmpty());
-
-  for (auto data : kNewAccelerators) {
-    EXPECT_TRUE(ProcessInController(CreateAccelerator(data)));
-
-    // Expect no notifications from the new accelerators.
-    EXPECT_TRUE(IsMessageCenterEmpty());
-
-    // If the action is LOCK_SCREEN, we must reset the state by unlocking the
-    // screen before we proceed testing the rest of accelerators.
-    ResetStateIfNeeded();
-  }
-}
-
-}  // namespace ash
diff --git a/ash/mus/bridge/wm_shell_mus.cc b/ash/mus/bridge/wm_shell_mus.cc
index f63f414..814fc5f 100644
--- a/ash/mus/bridge/wm_shell_mus.cc
+++ b/ash/mus/bridge/wm_shell_mus.cc
@@ -117,12 +117,14 @@
     WmWindow* primary_root_window,
     std::unique_ptr<ShellDelegate> shell_delegate,
     WindowManager* window_manager,
-    views::PointerWatcherEventRouter* pointer_watcher_event_router)
+    views::PointerWatcherEventRouter* pointer_watcher_event_router,
+    bool create_session_state_delegate_stub)
     : WmShell(std::move(shell_delegate)),
       window_manager_(window_manager),
       primary_root_window_(primary_root_window),
-      pointer_watcher_event_router_(pointer_watcher_event_router),
-      session_state_delegate_(new SessionStateDelegateStub) {
+      pointer_watcher_event_router_(pointer_watcher_event_router) {
+  if (create_session_state_delegate_stub)
+    session_state_delegate_ = base::MakeUnique<SessionStateDelegateStub>();
   DCHECK(primary_root_window_);
   WmShell::Set(this);
 
@@ -370,7 +372,9 @@
 }
 
 SessionStateDelegate* WmShellMus::GetSessionStateDelegate() {
-  return session_state_delegate_.get();
+  return session_state_delegate_
+             ? session_state_delegate_.get()
+             : Shell::GetInstance()->session_state_delegate();
 }
 
 void WmShellMus::AddDisplayObserver(WmDisplayObserver* observer) {
diff --git a/ash/mus/bridge/wm_shell_mus.h b/ash/mus/bridge/wm_shell_mus.h
index 6894a323..e94d2881 100644
--- a/ash/mus/bridge/wm_shell_mus.h
+++ b/ash/mus/bridge/wm_shell_mus.h
@@ -36,10 +36,13 @@
 // WmShell implementation for mus.
 class WmShellMus : public WmShell {
  public:
+  // If |create_session_state_delegate_stub| is true SessionStateDelegateStub is
+  // created. If false, the SessionStateDelegate from Shell is used.
   WmShellMus(WmWindow* primary_root_window,
              std::unique_ptr<ShellDelegate> shell_delegate,
              WindowManager* window_manager,
-             views::PointerWatcherEventRouter* pointer_watcher_event_router);
+             views::PointerWatcherEventRouter* pointer_watcher_event_router,
+             bool create_session_state_delegate_stub);
   ~WmShellMus() override;
 
   static WmShellMus* Get();
diff --git a/ash/mus/non_client_frame_controller.cc b/ash/mus/non_client_frame_controller.cc
index 1cad4f3..c83c4ac 100644
--- a/ash/mus/non_client_frame_controller.cc
+++ b/ash/mus/non_client_frame_controller.cc
@@ -279,6 +279,7 @@
       widget_, window_manager_client_, ShouldRemoveStandardFrame(*properties),
       ShouldEnableImmersive(*properties));
   window_ = native_widget->GetNativeView();
+  window_->SetProperty(aura::client::kTopLevelWindowInWM, true);
   window_->SetProperty(kNonClientFrameControllerKey, this);
   window_->SetProperty(kWidgetCreationTypeKey, WidgetCreationType::FOR_CLIENT);
   window_->AddObserver(this);
diff --git a/ash/mus/test/wm_test_helper.cc b/ash/mus/test/wm_test_helper.cc
index dc94727..d3839cfe 100644
--- a/ash/mus/test/wm_test_helper.cc
+++ b/ash/mus/test/wm_test_helper.cc
@@ -84,6 +84,9 @@
 }
 
 void WmTestHelper::Init() {
+  // MaterialDesignController may have already been initialized. To cover that
+  // case explicitly uninitialize before initializing.
+  ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
 
   views_delegate_ = base::MakeUnique<views::TestViewsDelegate>();
diff --git a/ash/mus/test/wm_test_helper.h b/ash/mus/test/wm_test_helper.h
index 8ba7e04..6b929f2 100644
--- a/ash/mus/test/wm_test_helper.h
+++ b/ash/mus/test/wm_test_helper.h
@@ -20,10 +20,6 @@
 class SequencedWorkerPoolOwner;
 }
 
-namespace ui {
-class WindowTreeClientPrivate;
-}
-
 namespace views {
 class ViewsDelegate;
 }
diff --git a/ash/mus/top_level_window_factory.cc b/ash/mus/top_level_window_factory.cc
index 1eb88d9..aab339d 100644
--- a/ash/mus/top_level_window_factory.cc
+++ b/ash/mus/top_level_window_factory.cc
@@ -20,6 +20,7 @@
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
 #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/mus/property_utils.h"
 #include "ui/aura/mus/window_tree_client.h"
@@ -171,6 +172,7 @@
 
   aura::Window* window = new aura::Window(nullptr);
   aura::SetWindowType(window, window_type);
+  window->SetProperty(aura::client::kTopLevelWindowInWM, true);
   ApplyProperties(window, property_converter, *properties);
   window->Init(ui::LAYER_TEXTURED);
   window->SetBounds(bounds);
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc
index 27315be..26879415 100644
--- a/ash/mus/window_manager.cc
+++ b/ash/mus/window_manager.cc
@@ -195,7 +195,8 @@
       WmWindow::Get(window_tree_host->window()),
       shell_delegate_for_test_ ? std::move(shell_delegate_for_test_)
                                : base::MakeUnique<ShellDelegateMus>(connector_),
-      this, pointer_watcher_event_router_.get());
+      this, pointer_watcher_event_router_.get(),
+      create_session_state_delegate_stub_for_test_);
   init_params.primary_window_tree_host = window_tree_host.release();
   init_params.wm_shell = wm_shell;
   init_params.blocking_pool = blocking_pool_.get();
diff --git a/ash/mus/window_manager.h b/ash/mus/window_manager.h
index 945bb5b..8565d645 100644
--- a/ash/mus/window_manager.h
+++ b/ash/mus/window_manager.h
@@ -45,6 +45,10 @@
 class ScreenMus;
 class ShellDelegate;
 
+namespace test {
+class AshTestHelper;
+}
+
 namespace mus {
 
 class AcceleratorHandler;
@@ -102,6 +106,7 @@
       std::unique_ptr<aura::WindowTreeHostMus> window_tree_host);
 
  private:
+  friend class ash::test::AshTestHelper;
   friend class WmTestHelper;
 
   using RootWindowControllers = std::set<std::unique_ptr<RootWindowController>>;
@@ -194,6 +199,9 @@
   // Only set in tests. If non-null this is used as the shell delegate.
   std::unique_ptr<ShellDelegate> shell_delegate_for_test_;
 
+  // See WmShellMus's constructor for details. Tests may set to false.
+  bool create_session_state_delegate_stub_for_test_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(WindowManager);
 };
 
diff --git a/ash/mus/window_manager_application.h b/ash/mus/window_manager_application.h
index f659698..757e24b 100644
--- a/ash/mus/window_manager_application.h
+++ b/ash/mus/window_manager_application.h
@@ -37,6 +37,9 @@
 }
 
 namespace ash {
+namespace test {
+class AshTestHelper;
+}
 namespace mus {
 
 class NetworkConnectDelegateMus;
@@ -51,6 +54,7 @@
   WindowManager* window_manager() { return window_manager_.get(); }
 
  private:
+  friend class ash::test::AshTestHelper;
   friend class WmTestBase;
   friend class WmTestHelper;
 
diff --git a/ash/mus/window_manager_unittest.cc b/ash/mus/window_manager_unittest.cc
index 4c2c0cd..45fc419f 100644
--- a/ash/mus/window_manager_unittest.cc
+++ b/ash/mus/window_manager_unittest.cc
@@ -66,7 +66,29 @@
   WindowManagerTest() : service_manager::test::ServiceTest("mash_unittests") {}
   ~WindowManagerTest() override {}
 
+  // service_manager::test::ServiceTest:
+  void SetUp() override {
+    service_manager::test::ServiceTest::SetUp();
+
+    // This test connects to the real mus. This results in
+    // aura::WindowTreeClient resetting the context_factory on Env. As all
+    // tests share the same Env (see mash_test_suite) we need to restore the
+    // context_factory when done.
+    aura::Env* env = aura::Env::GetInstance();
+    initial_context_factory_ = env->context_factory();
+    initial_context_factory_private_ = env->context_factory_private();
+  }
+
+  void TearDown() override {
+    aura::Env* env = aura::Env::GetInstance();
+    env->set_context_factory(initial_context_factory_);
+    env->set_context_factory_private(initial_context_factory_private_);
+  }
+
  private:
+  ui::ContextFactory* initial_context_factory_ = nullptr;
+  ui::ContextFactoryPrivate* initial_context_factory_private_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(WindowManagerTest);
 };
 
diff --git a/ash/resources/BUILD.gn b/ash/resources/BUILD.gn
index 57aeab68..4d8819e 100644
--- a/ash/resources/BUILD.gn
+++ b/ash/resources/BUILD.gn
@@ -11,6 +11,7 @@
 
 grit("resources") {
   source = "ash_resources.grd"
+  use_qualified_include = true
   outputs = [
     "grit/ash_resources.h",
     "ash_resources_100_percent.pak",
diff --git a/ash/system/chromeos/screen_layout_observer.cc b/ash/system/chromeos/screen_layout_observer.cc
index d3daf31..d018d414 100644
--- a/ash/system/chromeos/screen_layout_observer.cc
+++ b/ash/system/chromeos/screen_layout_observer.cc
@@ -17,11 +17,11 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/wm_shell.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
+#include "ash/resources/grit/ash_resources.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ash/test/BUILD.gn b/ash/test/BUILD.gn
index 7fd7919..baf92d4 100644
--- a/ash/test/BUILD.gn
+++ b/ash/test/BUILD.gn
@@ -80,8 +80,6 @@
     "ash_test_environment.h",
     "ash_test_helper.cc",
     "ash_test_helper.h",
-    "ash_test_suite.cc",
-    "ash_test_suite.h",
     "ash_test_views_delegate.cc",
     "ash_test_views_delegate.h",
     "child_modal_window.cc",
@@ -141,6 +139,7 @@
   ]
   deps = [
     "//ash/common/test:test_support",
+    "//ash/mus:lib",
     "//ash/public/cpp:ash_public_cpp",
     "//ash/public/interfaces",
     "//ash/resources",
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index c3dde23..3da727a 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -63,9 +63,9 @@
       const gfx::Point& point_in_screen) const override {
     display::Screen* screen = display::Screen::GetScreen();
     display::Display display = screen->GetDisplayNearestPoint(point_in_screen);
-    return Shell::GetInstance()
-        ->window_tree_host_manager()
+    return WmShell::Get()
         ->GetRootWindowForDisplayId(display.id())
+        ->aura_window()
         ->GetHost();
   }
 
@@ -134,7 +134,9 @@
   // Move the mouse cursor to far away so that native events doesn't
   // interfere test expectations.
   Shell::GetPrimaryRootWindow()->MoveCursorTo(gfx::Point(-1000, -1000));
-  Shell::GetInstance()->cursor_manager()->EnableMouseEvents();
+  // TODO: mash needs to support CursorManager. http://crbug.com/637853.
+  if (!WmShell::Get()->IsRunningInMash())
+    Shell::GetInstance()->cursor_manager()->EnableMouseEvents();
 
   // Changing GestureConfiguration shouldn't make tests fail. These values
   // prevent unexpected events from being generated during tests. Such as
@@ -196,8 +198,13 @@
 
 // static
 void AshTestBase::UpdateDisplay(const std::string& display_specs) {
-  display::test::DisplayManagerTestApi(Shell::GetInstance()->display_manager())
-      .UpdateDisplay(display_specs);
+  if (WmShell::Get()->IsRunningInMash()) {
+    ash_test_helper_->UpdateDisplayForMash(display_specs);
+  } else {
+    display::test::DisplayManagerTestApi(
+        Shell::GetInstance()->display_manager())
+        .UpdateDisplay(display_specs);
+  }
 }
 
 aura::Window* AshTestBase::CurrentContext() {
@@ -264,9 +271,8 @@
   } else {
     display::Display display =
         display::Screen::GetScreen()->GetDisplayMatching(bounds);
-    aura::Window* root = Shell::GetInstance()
-                             ->window_tree_host_manager()
-                             ->GetRootWindowForDisplayId(display.id());
+    aura::Window* root =
+        WmShell::Get()->GetRootWindowForDisplayId(display.id())->aura_window();
     gfx::Point origin = bounds.origin();
     ::wm::ConvertPointFromScreen(root, &origin);
     window->SetBounds(gfx::Rect(origin, bounds.size()));
@@ -388,5 +394,9 @@
       display_manager()->GetSecondaryDisplay().id());
 }
 
+display::Display AshTestBase::GetSecondaryDisplay() {
+  return ash_test_helper_->GetSecondaryDisplay();
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index c819fef..41b0e0b1 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -24,6 +24,7 @@
 }  // namespace aura
 
 namespace display {
+class Display;
 class DisplayManager;
 
 namespace test {
@@ -168,6 +169,8 @@
   // Swap the primary display with the secondary.
   void SwapPrimaryDisplay();
 
+  display::Display GetSecondaryDisplay();
+
  private:
   friend class ash::AshTestImplAura;
 
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index df2ebb66..1508abf 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -9,6 +9,10 @@
 #include "ash/common/test/test_system_tray_delegate.h"
 #include "ash/common/test/wm_shell_test_api.h"
 #include "ash/common/wm_shell.h"
+#include "ash/common/wm_window.h"
+#include "ash/mus/screen_mus.h"
+#include "ash/mus/window_manager.h"
+#include "ash/mus/window_manager_application.h"
 #include "ash/shell.h"
 #include "ash/shell_init_params.h"
 #include "ash/system/chromeos/screen_layout_observer.h"
@@ -19,20 +23,25 @@
 #include "ash/test/test_shell_delegate.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/strings/string_split.h"
+#include "base/test/sequenced_worker_pool_owner.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
 #include "ui/aura/env.h"
 #include "ui/aura/input_state_lookup.h"
+#include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/test/env_test_helper.h"
 #include "ui/aura/test/event_generator_delegate_aura.h"
+#include "ui/aura/test/mus/window_tree_client_private.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/platform_window_defaults.h"
 #include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/display/test/display_manager_test_api.h"
 #include "ui/message_center/message_center.h"
@@ -40,8 +49,23 @@
 #include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/core/wm_state.h"
 
+using display::ManagedDisplayInfo;
+
 namespace ash {
 namespace test {
+namespace {
+
+bool IsMash() {
+  return aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS;
+}
+
+bool CompareByDisplayId(RootWindowController* root1,
+                        RootWindowController* root2) {
+  return root1->GetWindow()->GetDisplayNearestWindow().id() <
+         root2->GetWindow()->GetDisplayNearestWindow().id();
+}
+
+}  // namespace
 
 AshTestHelper::AshTestHelper(AshTestEnvironment* ash_test_environment)
     : ash_test_environment_(ash_test_environment),
@@ -57,7 +81,12 @@
 
 void AshTestHelper::SetUp(bool start_session) {
   display::ResetDisplayIdForTest();
-  wm_state_ = base::MakeUnique<::wm::WMState>();
+  const bool is_mash = IsMash();
+  if (is_mash)
+    aura::test::EnvTestHelper().SetAlwaysUseLastMouseLocation(true);
+  // WindowManager creates WMState for mash.
+  if (!is_mash)
+    wm_state_ = base::MakeUnique<::wm::WMState>();
   views_delegate_ = ash_test_environment_->CreateViewsDelegate();
 
   // Disable animations during tests.
@@ -65,38 +94,35 @@
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
   ui::InitializeInputMethodForTesting();
 
-  bool enable_pixel_output = false;
-  ui::ContextFactory* context_factory = nullptr;
-  ui::ContextFactoryPrivate* context_factory_private = nullptr;
-  ui::InitializeContextFactoryForTests(enable_pixel_output, &context_factory,
-                                       &context_factory_private);
-
   // Creates Shell and hook with Desktop.
   if (!test_shell_delegate_)
     test_shell_delegate_ = new TestShellDelegate;
 
-  // Creates MessageCenter since g_browser_process is not created in AshTestBase
-  // tests.
-  message_center::MessageCenter::Initialize();
+  if (!is_mash) {
+    // All of this initialization is done in WindowManagerApplication for mash.
 
-  // Create DBusThreadManager for testing.
-  if (!chromeos::DBusThreadManager::IsInitialized()) {
-    chromeos::DBusThreadManager::Initialize(
-        chromeos::DBusThreadManager::PROCESS_ASH);
-    dbus_thread_manager_initialized_ = true;
+    // Creates MessageCenter since g_browser_process is not created in
+    // AshTestBase tests.
+    message_center::MessageCenter::Initialize();
+
+    if (!chromeos::DBusThreadManager::IsInitialized()) {
+      chromeos::DBusThreadManager::Initialize(
+          chromeos::DBusThreadManager::PROCESS_ASH);
+      dbus_thread_manager_initialized_ = true;
+    }
+
+    if (!bluez::BluezDBusManager::IsInitialized()) {
+      bluez::BluezDBusManager::Initialize(
+          chromeos::DBusThreadManager::Get()->GetSystemBus(),
+          chromeos::DBusThreadManager::Get()->IsUsingFakes());
+      bluez_dbus_manager_initialized_ = true;
+    }
+
+    // Create CrasAudioHandler for testing since g_browser_process is not
+    // created in AshTestBase tests.
+    chromeos::CrasAudioHandler::InitializeForTesting();
   }
 
-  if (!bluez::BluezDBusManager::IsInitialized()) {
-    bluez::BluezDBusManager::Initialize(
-        chromeos::DBusThreadManager::Get()->GetSystemBus(),
-        chromeos::DBusThreadManager::Get()->IsUsingFakes());
-    bluez_dbus_manager_initialized_ = true;
-  }
-
-  // Create CrasAudioHandler for testing since g_browser_process is not
-  // created in AshTestBase tests.
-  chromeos::CrasAudioHandler::InitializeForTesting();
-
   ash_test_environment_->SetUp();
   // Reset the global state for the cursor manager. This includes the
   // last cursor visibility state, etc.
@@ -107,14 +133,13 @@
   ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
 
-  ShellInitParams init_params;
-  init_params.delegate = test_shell_delegate_;
-  init_params.context_factory = context_factory;
-  init_params.context_factory_private = context_factory_private;
-  init_params.blocking_pool = ash_test_environment_->GetBlockingPool();
-  Shell::CreateInstance(init_params);
-  aura::test::EnvTestHelper(aura::Env::GetInstance())
-      .SetInputStateLookup(std::unique_ptr<aura::InputStateLookup>());
+  if (is_mash)
+    CreateMashWindowManager();
+  else
+    CreateShell();
+
+  aura::test::EnvTestHelper().SetInputStateLookup(
+      std::unique_ptr<aura::InputStateLookup>());
 
   Shell* shell = Shell::GetInstance();
   if (start_session) {
@@ -122,22 +147,35 @@
     GetTestSessionStateDelegate()->SetHasActiveUser(true);
   }
 
-  // Tests that change the display configuration generally don't care about the
-  // notifications and the popup UI can interfere with things like cursors.
-  shell->screen_layout_observer()->set_show_notifications_for_testing(false);
+  if (!is_mash) {
+    // ScreenLayoutObserver is specific to classic-ash.
+    // Tests that change the display configuration generally don't care about
+    // the notifications and the popup UI can interfere with things like
+    // cursors.
+    shell->screen_layout_observer()->set_show_notifications_for_testing(false);
 
-  display::test::DisplayManagerTestApi(Shell::GetInstance()->display_manager())
-      .DisableChangeDisplayUponHostResize();
-  ShellTestApi(shell).DisableDisplayAnimator();
+    // DisplayManager is specific to classic-ash.
+    display::test::DisplayManagerTestApi(
+        Shell::GetInstance()->display_manager())
+        .DisableChangeDisplayUponHostResize();
+    ShellTestApi(shell).DisableDisplayAnimator();
 
-  test_screenshot_delegate_ = new TestScreenshotDelegate();
-  shell->accelerator_controller_delegate()->SetScreenshotDelegate(
-      std::unique_ptr<ScreenshotDelegate>(test_screenshot_delegate_));
+    // TODO: disabled for mash as AcceleratorControllerDelegateAura isn't
+    // created in mash http://crbug.com/632111.
+    test_screenshot_delegate_ = new TestScreenshotDelegate();
+    shell->accelerator_controller_delegate()->SetScreenshotDelegate(
+        std::unique_ptr<ScreenshotDelegate>(test_screenshot_delegate_));
+  }
 }
 
 void AshTestHelper::TearDown() {
-  // Tear down the shell.
-  Shell::DeleteInstance();
+  window_manager_app_.reset();
+
+  const bool is_mash = IsMash();
+
+  // WindowManger owns the Shell in mash.
+  if (!is_mash)
+    Shell::DeleteInstance();
 
   // Suspend the tear down until all resources are returned via
   // MojoCompositorFrameSinkClient::ReclaimResources()
@@ -146,15 +184,19 @@
 
   test_screenshot_delegate_ = NULL;
 
-  // Remove global message center state.
-  message_center::MessageCenter::Shutdown();
+  if (!is_mash) {
+    // Remove global message center state.
+    message_center::MessageCenter::Shutdown();
 
-  chromeos::CrasAudioHandler::Shutdown();
+    chromeos::CrasAudioHandler::Shutdown();
+  }
+
   if (bluez_dbus_manager_initialized_) {
     device::BluetoothAdapterFactory::Shutdown();
     bluez::BluezDBusManager::Shutdown();
     bluez_dbus_manager_initialized_ = false;
   }
+
   if (dbus_thread_manager_initialized_) {
     chromeos::DBusThreadManager::Shutdown();
     dbus_thread_manager_initialized_ = false;
@@ -168,7 +210,8 @@
   views_delegate_.reset();
   wm_state_.reset();
 
-  CHECK(!::wm::CaptureController::Get());
+  // WindowManager owns the CaptureController for mash.
+  CHECK(is_mash || !::wm::CaptureController::Get());
 }
 
 void AshTestHelper::RunAllPendingInMessageLoop() {
@@ -191,5 +234,133 @@
   return root_window;
 }
 
+void AshTestHelper::UpdateDisplayForMash(const std::string& display_spec) {
+  CHECK(IsMash());
+  const std::vector<std::string> parts = base::SplitString(
+      display_spec, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  std::vector<RootWindowController*> root_window_controllers =
+      GetRootsOrderedByDisplayId();
+  int next_x = 0;
+  for (size_t i = 0,
+              end = std::min(parts.size(), root_window_controllers.size());
+       i < end; ++i) {
+    UpdateDisplay(root_window_controllers[i], parts[i], &next_x);
+  }
+  for (size_t i = root_window_controllers.size(); i < parts.size(); ++i) {
+    root_window_controllers.push_back(
+        CreateRootWindowController(parts[i], &next_x));
+  }
+  const bool in_shutdown = false;
+  while (root_window_controllers.size() > parts.size()) {
+    window_manager_app_->window_manager()->DestroyRootWindowController(
+        root_window_controllers.back(), in_shutdown);
+    root_window_controllers.pop_back();
+  }
+}
+
+display::Display AshTestHelper::GetSecondaryDisplay() {
+  if (!IsMash())
+    return Shell::GetInstance()->display_manager()->GetSecondaryDisplay();
+
+  std::vector<RootWindowController*> roots = GetRootsOrderedByDisplayId();
+  CHECK_LE(2U, roots.size());
+  return roots.size() < 2 ? display::Display()
+                          : roots[1]->GetWindow()->GetDisplayNearestWindow();
+}
+
+void AshTestHelper::CreateMashWindowManager() {
+  CHECK(IsMash());
+  window_manager_app_ = base::MakeUnique<mus::WindowManagerApplication>();
+
+  window_manager_app_->window_manager_.reset(new mus::WindowManager(nullptr));
+  window_manager_app_->window_manager()->shell_delegate_for_test_.reset(
+      test_shell_delegate_);
+  window_manager_app_->window_manager()
+      ->create_session_state_delegate_stub_for_test_ = false;
+
+  window_tree_client_setup_.InitForWindowManager(
+      window_manager_app_->window_manager_.get(),
+      window_manager_app_->window_manager_.get());
+  aura::test::EnvTestHelper().SetWindowTreeClient(
+      window_tree_client_setup_.window_tree_client());
+  window_manager_app_->InitWindowManager(
+      window_tree_client_setup_.OwnWindowTreeClient(),
+      ash_test_environment_->GetBlockingPool());
+
+  aura::WindowTreeClient* window_tree_client =
+      window_manager_app_->window_manager()->window_tree_client();
+  window_tree_client_private_ =
+      base::MakeUnique<aura::WindowTreeClientPrivate>(window_tree_client);
+  int next_x = 0;
+  CreateRootWindowController("800x600", &next_x);
+}
+
+void AshTestHelper::CreateShell() {
+  CHECK(!IsMash());
+  ui::ContextFactory* context_factory = nullptr;
+  ui::ContextFactoryPrivate* context_factory_private = nullptr;
+  bool enable_pixel_output = false;
+  ui::InitializeContextFactoryForTests(enable_pixel_output, &context_factory,
+                                       &context_factory_private);
+  ShellInitParams init_params;
+  init_params.delegate = test_shell_delegate_;
+  init_params.context_factory = context_factory;
+  init_params.context_factory_private = context_factory_private;
+  init_params.blocking_pool = ash_test_environment_->GetBlockingPool();
+  Shell::CreateInstance(init_params);
+}
+
+RootWindowController* AshTestHelper::CreateRootWindowController(
+    const std::string& display_spec,
+    int* next_x) {
+  ManagedDisplayInfo display_info =
+      ManagedDisplayInfo::CreateFromSpec(display_spec);
+  gfx::Rect bounds = display_info.bounds_in_native();
+  bounds.set_x(*next_x);
+  *next_x += bounds.size().width();
+  display::Display display(next_display_id_++, bounds);
+  display.set_device_scale_factor(display_info.device_scale_factor());
+  gfx::Rect work_area(bounds.size());
+  // Offset the height slightly to give a different work area. -20 is arbitrary,
+  // it could be anything.
+  work_area.set_height(std::max(0, work_area.height() - 20));
+  display.set_work_area(work_area);
+  window_tree_client_private_->CallWmNewDisplayAdded(display);
+  return GetRootsOrderedByDisplayId().back();
+}
+
+void AshTestHelper::UpdateDisplay(RootWindowController* root_window_controller,
+                                  const std::string& display_spec,
+                                  int* next_x) {
+  ManagedDisplayInfo display_info =
+      ManagedDisplayInfo::CreateFromSpec(display_spec);
+  gfx::Rect bounds = display_info.bounds_in_native();
+  bounds.set_x(*next_x);
+  *next_x += bounds.size().width();
+  display::Display updated_display =
+      root_window_controller->GetWindow()->GetDisplayNearestWindow();
+  gfx::Insets work_area_insets = updated_display.GetWorkAreaInsets();
+  updated_display.set_bounds(bounds);
+  updated_display.UpdateWorkAreaFromInsets(work_area_insets);
+  updated_display.set_device_scale_factor(display_info.device_scale_factor());
+  root_window_controller->GetWindow()->SetBounds(gfx::Rect(bounds.size()));
+  ScreenMus* screen = window_manager_app_->window_manager()->screen_.get();
+  const bool is_primary =
+      screen->display_list().FindDisplayById(updated_display.id()) ==
+      screen->display_list().GetPrimaryDisplayIterator();
+  screen->display_list().UpdateDisplay(
+      updated_display, is_primary ? display::DisplayList::Type::PRIMARY
+                                  : display::DisplayList::Type::NOT_PRIMARY);
+}
+
+std::vector<RootWindowController*> AshTestHelper::GetRootsOrderedByDisplayId() {
+  std::set<RootWindowController*> roots =
+      window_manager_app_->window_manager()->GetRootWindowControllers();
+  std::vector<RootWindowController*> ordered_roots;
+  ordered_roots.insert(ordered_roots.begin(), roots.begin(), roots.end());
+  std::sort(ordered_roots.begin(), ordered_roots.end(), &CompareByDisplayId);
+  return ordered_roots;
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index 448beff..64e16eb3 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -5,15 +5,24 @@
 #ifndef ASH_TEST_ASH_TEST_HELPER_H_
 #define ASH_TEST_ASH_TEST_HELPER_H_
 
+#include <stdint.h>
+
 #include <memory>
+#include <vector>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "ui/aura/test/mus/test_window_tree_client_setup.h"
 
 namespace aura {
 class Window;
+class WindowTreeClientPrivate;
 }  // namespace aura
 
+namespace display {
+class Display;
+}
+
 namespace ui {
 class ScopedAnimationDurationScaleMode;
 }  // namespace ui
@@ -23,6 +32,13 @@
 }
 
 namespace ash {
+
+class RootWindowController;
+
+namespace mus {
+class WindowManagerApplication;
+}
+
 namespace test {
 
 class AshTestEnvironment;
@@ -65,7 +81,31 @@
 
   AshTestEnvironment* ash_test_environment() { return ash_test_environment_; }
 
+  // Version of DisplayManagerTestApi::UpdateDisplay() for mash.
+  void UpdateDisplayForMash(const std::string& display_spec);
+
+  display::Display GetSecondaryDisplay();
+
  private:
+  // Called when running in mash to create the WindowManager.
+  void CreateMashWindowManager();
+
+  // Called when running in ash to create Shell.
+  void CreateShell();
+
+  // Creates a new RootWindowController based on |display_spec|. The origin is
+  // set to |next_x| and on exit |next_x| is set to the origin + the width.
+  RootWindowController* CreateRootWindowController(
+      const std::string& display_spec,
+      int* next_x);
+
+  // Updates an existing display based on |display_spec|.
+  void UpdateDisplay(RootWindowController* root_window_controller,
+                     const std::string& display_spec,
+                     int* next_x);
+
+  std::vector<RootWindowController*> GetRootsOrderedByDisplayId();
+
   AshTestEnvironment* ash_test_environment_;  // Not owned.
   TestShellDelegate* test_shell_delegate_;  // Owned by ash::Shell.
   std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
@@ -81,6 +121,12 @@
   // Check if Bluez DBus Manager was initialized here.
   bool bluez_dbus_manager_initialized_;
 
+  aura::TestWindowTreeClientSetup window_tree_client_setup_;
+  std::unique_ptr<mus::WindowManagerApplication> window_manager_app_;
+  std::unique_ptr<aura::WindowTreeClientPrivate> window_tree_client_private_;
+  // Id for the next Display created by CreateRootWindowController().
+  int64_t next_display_id_ = 1;
+
   DISALLOW_COPY_AND_ASSIGN(AshTestHelper);
 };
 
diff --git a/ash/wm/resize_shadow.cc b/ash/wm/resize_shadow.cc
index e91b0aa..14bd0f6e 100644
--- a/ash/wm/resize_shadow.cc
+++ b/ash/wm/resize_shadow.cc
@@ -4,8 +4,8 @@
 
 #include "ash/wm/resize_shadow.h"
 
+#include "ash/resources/grit/ash_resources.h"
 #include "base/time/time.h"
-#include "grit/ash_resources.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/build/config/linux/gtk/gtk.gni b/build/config/linux/gtk/gtk.gni
index b3fd973d..ae4746e4 100644
--- a/build/config/linux/gtk/gtk.gni
+++ b/build/config/linux/gtk/gtk.gni
@@ -8,5 +8,5 @@
 
 declare_args() {
   # Whether to compile agains GTKv3 instead of GTKv2.
-  use_gtk3 = false
+  use_gtk3 = true
 }
diff --git a/build/config/mac/plist_util.py b/build/config/mac/plist_util.py
index e2a8d6e1..0928fa13 100644
--- a/build/config/mac/plist_util.py
+++ b/build/config/mac/plist_util.py
@@ -141,7 +141,7 @@
 
   Creates a new dictionary representing a Property List (.plist) files by
   merging the two dictionary |plist1| and |plist2| recursively (only for
-  dictionary values).
+  dictionary values). List value will be concatenated.
 
   Args:
     plist1: a dictionary representing a Property List (.plist) file
@@ -150,7 +150,8 @@
   Returns:
     A new dictionary representing a Property List (.plist) file by merging
     |plist1| with |plist2|. If any value is a dictionary, they are merged
-    recursively, otherwise |plist2| value is used.
+    recursively, otherwise |plist2| value is used. If values are list, they
+    are concatenated.
   """
   if not isinstance(plist1, dict) or not isinstance(plist2, dict):
     if plist2 is not None:
@@ -165,6 +166,8 @@
       value = plist1[key]
     if isinstance(value, dict):
       value = MergePList(plist1.get(key, None), plist2.get(key, None))
+    if isinstance(value, list):
+      value = plist1.get(key, []) + plist2.get(key, [])
     result[key] = value
   return result
 
diff --git a/cc/input/scroll_state.cc b/cc/input/scroll_state.cc
index 5a2a7dd..7d0becde 100644
--- a/cc/input/scroll_state.cc
+++ b/cc/input/scroll_state.cc
@@ -28,9 +28,11 @@
 
 void ScrollState::DistributeToScrollChainDescendant() {
   if (!scroll_chain_.empty()) {
-    const ScrollNode* next = scroll_chain_.front();
+    ScrollNode* next = scroll_chain_.front();
     scroll_chain_.pop_front();
-    layer_tree_impl_->LayerById(next->owning_layer_id)->DistributeScroll(this);
+
+    ScrollTree& scroll_tree = layer_tree_impl_->property_trees()->scroll_tree;
+    scroll_tree.DistributeScroll(next, this);
   }
 }
 
diff --git a/cc/input/scroll_state.h b/cc/input/scroll_state.h
index 86bc658..6df0b74 100644
--- a/cc/input/scroll_state.h
+++ b/cc/input/scroll_state.h
@@ -61,11 +61,10 @@
     data_.is_direct_manipulation = is_direct_manipulation;
   }
 
-  void set_scroll_chain_and_layer_tree(
-      const std::list<const ScrollNode*>& scroll_chain,
-      LayerTreeImpl* layer_tree_impl) {
+  void set_scroll_chain_and_layer_tree(std::list<ScrollNode*>* scroll_chain,
+                                       LayerTreeImpl* layer_tree_impl) {
     layer_tree_impl_ = layer_tree_impl;
-    scroll_chain_ = scroll_chain;
+    scroll_chain_ = *scroll_chain;
   }
 
   void set_current_native_scrolling_node(ScrollNode* scroll_node) {
@@ -99,7 +98,7 @@
  private:
   ScrollStateData data_;
   LayerTreeImpl* layer_tree_impl_;
-  std::list<const ScrollNode*> scroll_chain_;
+  std::list<ScrollNode*> scroll_chain_;
 };
 
 }  // namespace cc
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 4074061..891057f 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -133,12 +133,6 @@
   SetNeedsPushProperties();
 }
 
-void LayerImpl::DistributeScroll(ScrollState* scroll_state) {
-  ScrollTree& scroll_tree = GetScrollTree();
-  ScrollNode* scroll_node = scroll_tree.Node(scroll_tree_index());
-  scroll_tree.DistributeScroll(scroll_node, scroll_state);
-}
-
 void LayerImpl::SetTransformTreeIndex(int index) {
   transform_tree_index_ = index;
 }
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 5fff96cb..1a39e1b5 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -59,7 +59,6 @@
 class ScrollbarLayerImplBase;
 class SimpleEnclosedRegion;
 class Tile;
-class ScrollState;
 
 struct AppendQuadsData;
 
@@ -90,8 +89,6 @@
                             const PropertyAnimationState& state);
   bool IsActive() const;
 
-  void DistributeScroll(ScrollState* scroll_state);
-
   void set_property_tree_sequence_number(int sequence_number) {}
 
   void SetTransformTreeIndex(int index);
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index f9e953f..4dbc94fc 100644
--- a/cc/surfaces/BUILD.gn
+++ b/cc/surfaces/BUILD.gn
@@ -8,6 +8,7 @@
   sources = [
     "frame_sink_id.cc",
     "frame_sink_id.h",
+    "frame_sink_id_allocator.h",
     "local_surface_id.cc",
     "local_surface_id.h",
     "surface_id.cc",
diff --git a/cc/surfaces/frame_sink_id_allocator.h b/cc/surfaces/frame_sink_id_allocator.h
new file mode 100644
index 0000000..48bf1aa
--- /dev/null
+++ b/cc/surfaces/frame_sink_id_allocator.h
@@ -0,0 +1,32 @@
+// 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 CC_SURFACES_FRAME_SINK_ID_ALLOCATOR_H_
+#define CC_SURFACES_FRAME_SINK_ID_ALLOCATOR_H_
+
+#include "cc/surfaces/frame_sink_id.h"
+
+namespace cc {
+
+// This class generates FrameSinkId with a fixed client_id and an
+// incrementally-increasing sink_id.
+class FrameSinkIdAllocator {
+ public:
+  constexpr explicit FrameSinkIdAllocator(uint32_t client_id)
+      : client_id_(client_id), next_sink_id_(1u) {}
+
+  FrameSinkId NextFrameSinkId() {
+    return FrameSinkId(client_id_, next_sink_id_++);
+  }
+
+ private:
+  const uint32_t client_id_;
+  uint32_t next_sink_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameSinkIdAllocator);
+};
+
+}  // namespace cc
+
+#endif  // CC_SURFACES_FRAME_SINK_ID_ALLOCATOR_H_
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 1759689..50b04fb 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3010,7 +3010,7 @@
 
 void LayerTreeHostImpl::ApplyScroll(ScrollNode* scroll_node,
                                     ScrollState* scroll_state) {
-  DCHECK(scroll_state);
+  DCHECK(scroll_node && scroll_state);
   gfx::Point viewport_point(scroll_state->position_x(),
                             scroll_state->position_y());
   const gfx::Vector2dF delta(scroll_state->delta_x(), scroll_state->delta_y());
@@ -3088,7 +3088,7 @@
   // is not the case here. We eventually want to have the same behaviour on both
   // sides but it may become a non issue if we get rid of scroll chaining (see
   // crbug.com/526462)
-  std::list<const ScrollNode*> current_scroll_chain;
+  std::list<ScrollNode*> current_scroll_chain;
   ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
   ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode();
   ScrollNode* viewport_scroll_node =
@@ -3115,7 +3115,7 @@
       current_scroll_chain.push_front(scroll_node);
     }
   }
-  scroll_state->set_scroll_chain_and_layer_tree(current_scroll_chain,
+  scroll_state->set_scroll_chain_and_layer_tree(&current_scroll_chain,
                                                 active_tree());
   scroll_state->DistributeToScrollChainDescendant();
 }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 9850577..19a09e4 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -1142,8 +1142,6 @@
 #if DCHECK_IS_ON()
 void ScrollTree::CopyCompleteTreeState(const ScrollTree& other) {
   currently_scrolling_node_id_ = other.currently_scrolling_node_id_;
-  layer_id_to_scrollbars_enabled_map_ =
-      other.layer_id_to_scrollbars_enabled_map_;
   layer_id_to_scroll_offset_map_ = other.layer_id_to_scroll_offset_map_;
   layer_id_to_synced_scroll_offset_map_ =
       other.layer_id_to_synced_scroll_offset_map_;
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 58d4f5f8..5257eadd 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -361,8 +361,6 @@
 
   void clear();
 
-  typedef std::unordered_map<int, bool> ScrollbarsEnabledMap;
-
   gfx::ScrollOffset MaxScrollOffset(int scroll_node_id) const;
   void OnScrollOffsetAnimated(int layer_id,
                               int scroll_tree_index,
@@ -435,7 +433,6 @@
       std::unordered_map<int, scoped_refptr<SyncedScrollOffset>>;
 
   int currently_scrolling_node_id_;
-  ScrollbarsEnabledMap layer_id_to_scrollbars_enabled_map_;
 
   // On the main thread we store the scroll offsets directly since the main
   // thread only needs to keep track of the current main thread state. The impl
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index a45f50c..e3af3bb7 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -43,6 +43,7 @@
     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.NFC"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
     <uses-permission android:name="android.permission.READ_SYNC_STATS"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
@@ -54,8 +55,6 @@
     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
     {% set enable_webvr = enable_webvr|default(0) %}
     {% if enable_webvr == "true" %}
-    <!-- Required to read the paired viewer's distortion parameters. -->
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <!-- Indicates use of Android's VR-mode, available only on Android N+. -->
     <uses-feature android:name="android.software.vr.mode" android:required="false"/>
     <!-- Indicates use of VR features that are available only on Daydream-ready devices. -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
index 9ba6f52..d1fd3ad8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -520,7 +520,7 @@
         return sManager;
     }
 
-    private static int sNormalizationTimeoutMs = 5000;
+    private static int sNormalizationTimeoutSeconds = 5;
 
     private final long mPersonalDataManagerAndroid;
     private final List<PersonalDataManagerObserver> mDataObservers =
@@ -814,7 +814,8 @@
      * Normalizes the address of the profile associated with the {@code guid} if the rules
      * associated with the {@code regionCode} are done loading. Otherwise sets up the callback to
      * start normalizing the address when the rules are loaded. The normalized profile will be sent
-     * to the {@code delegate}.
+     * to the {@code delegate}. If the profile is not normalized in the specified
+     * {@code sNormalizationTimeoutSeconds}, the {@code delegate} will be notified.
      *
      * @param guid The GUID of the profile to normalize.
      * @param regionCode The region code indicating which rules to use for normalization.
@@ -823,7 +824,8 @@
     public void normalizeAddress(
             String guid, String regionCode, NormalizedAddressRequestDelegate delegate) {
         ThreadUtils.assertOnUiThread();
-        nativeStartAddressNormalization(mPersonalDataManagerAndroid, guid, regionCode, delegate);
+        nativeStartAddressNormalization(mPersonalDataManagerAndroid, guid, regionCode,
+                sNormalizationTimeoutSeconds, delegate);
     }
 
     /**
@@ -881,16 +883,9 @@
         nativeSetPaymentsIntegrationEnabled(enable);
     }
 
-    /**
-     * @return The timeout value for normalization.
-     */
-    public static int getNormalizationTimeoutMS() {
-        return sNormalizationTimeoutMs;
-    }
-
     @VisibleForTesting
     public static void setNormalizationTimeoutForTesting(int timeout) {
-        sNormalizationTimeoutMs = timeout;
+        sNormalizationTimeoutSeconds = timeout;
     }
 
     private native long nativeInit();
@@ -955,7 +950,8 @@
     private native void nativeLoadRulesForRegion(
             long nativePersonalDataManagerAndroid, String regionCode);
     private native void nativeStartAddressNormalization(long nativePersonalDataManagerAndroid,
-            String guid, String regionCode, NormalizedAddressRequestDelegate delegate);
+            String guid, String regionCode, int timeoutSeconds,
+            NormalizedAddressRequestDelegate delegate);
     private static native boolean nativeHasProfiles(long nativePersonalDataManagerAndroid);
     private static native boolean nativeHasCreditCards(long nativePersonalDataManagerAndroid);
     private static native boolean nativeIsAutofillEnabled();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
index 734ad2ca1..c535e1b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -449,9 +449,16 @@
         if (mInGesture || mContentViewScrolling) return;
 
         // Update content viewport size only when the browser controls are not animating.
-        int contentOffset = (int) mRendererTopContentOffset;
-        if (contentOffset != 0 && contentOffset != getTopControlsHeight()) return;
-        viewCore.setTopControlsHeight(getTopControlsHeight(), contentOffset > 0);
+        int topContentOffset = (int) mRendererTopContentOffset;
+        int bottomControlOffset = (int) mRendererBottomControlOffset;
+        if ((topContentOffset != 0 && topContentOffset != getTopControlsHeight())
+                && bottomControlOffset != 0 && bottomControlOffset != getBottomControlsHeight()) {
+            return;
+        }
+        boolean controlsResizeView =
+                topContentOffset > 0 || bottomControlOffset < getBottomControlsHeight();
+        viewCore.setTopControlsHeight(getTopControlsHeight(), controlsResizeView);
+        viewCore.setBottomControlsHeight(getBottomControlsHeight());
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
index ef0826e..85da3ba7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.payments;
 
 import android.content.Context;
-import android.os.Handler;
 import android.text.TextUtils;
 import android.util.JsonWriter;
 
@@ -126,20 +125,7 @@
         mCallback.onInstrumentDetailsLoadingWithoutUI();
 
         // Wait for the billing address normalization before sending the instrument details.
-        if (mIsWaitingForBillingNormalization) {
-            // If the normalization is not completed yet, Start a timer to cancel it if it takes too
-            // long.
-            new Handler().postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    onAddressNormalized(null);
-                }
-            }, PersonalDataManager.getInstance().getNormalizationTimeoutMS());
-
-            return;
-        } else {
-            sendIntrumentDetails();
-        }
+        if (!mIsWaitingForBillingNormalization) sendInstrumentDetails();
     }
 
     @Override
@@ -151,7 +137,7 @@
         if (profile != null) mBillingAddress = profile;
 
         // Wait for the full card details before sending the instrument details.
-        if (!mIsWaitingForFullCardDetails) sendIntrumentDetails();
+        if (!mIsWaitingForFullCardDetails) sendInstrumentDetails();
     }
 
     @Override
@@ -163,7 +149,7 @@
      * Stringify the card details and send the resulting string and the method name to the
      * registered callback.
      */
-    private void sendIntrumentDetails() {
+    private void sendInstrumentDetails() {
         StringWriter stringWriter = new StringWriter();
         JsonWriter json = new JsonWriter(stringWriter);
         try {
@@ -318,7 +304,7 @@
                         mCard.getNumber().toString(), true)
                     == null) {
                 mHasValidNumberAndName = false;
-                editMessageResId = R.string.payments_card_number_invalid;
+                editMessageResId = R.string.payments_card_number_invalid_validation_message;
                 editTitleResId = R.string.payments_add_valid_card_number;
                 invalidFieldsCount++;
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 85f3c349..328686f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -1103,7 +1103,6 @@
         assert mPaymentMethodsSection.getSelectedItem() instanceof AutofillPaymentInstrument;
 
         mUI.showProcessingMessage();
-        mPaymentResponseHelper.onInstrumentsDetailsLoading();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java
index 20863093..1b6a86ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.payments;
 
-import android.os.Handler;
-
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate;
@@ -90,23 +88,6 @@
     }
 
     /**
-     * Called when the intrument details have started loading. Starts a timeout to stop the shipping
-     * address normalization if it takes too long.
-     */
-    public void onInstrumentsDetailsLoading() {
-        if (mIsWaitingForShippingNormalization) {
-            // If the normalization is not completed yet, start a timer to cancel it if it takes too
-            // long.
-            new Handler().postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    onAddressNormalized(null);
-                }
-            }, PersonalDataManager.getInstance().getNormalizationTimeoutMS());
-        }
-    }
-
-    /**
      * Called after the payment instrument's details were received.
      *
      * @param methodName          The method name of the payment instrument.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
index e2799f6..99beafd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -337,7 +337,6 @@
      * Adds layout change listeners to the views that the bottom sheet depends on. Namely the
      * heights of the root view and control container are important as they are used in many of the
      * calculations in this class.
-     * @param activity An activity for loading native pages.
      * @param root The container of the bottom sheet.
      * @param controlContainer The container for the toolbar.
      */
@@ -394,6 +393,8 @@
 
     @Override
     public int loadUrl(LoadUrlParams params) {
+        for (BottomSheetObserver o : mObservers) o.onLoadUrl(params.getUrl());
+
         // Native page URLs in this context do not need to communicate with the tab.
         if (NativePageFactory.isNativePageUrl(params.getUrl(), isIncognito())) {
             return TabLoadStatus.PAGE_LOAD_FAILED;
@@ -448,13 +449,22 @@
     /**
      * A notification that the sheet is exiting the peek state into one that shows content.
      */
-    private void onExitPeekState() {
+    private void onSheetOpened() {
         if (mSuggestionsContent == null) {
             mSuggestionsContent = new SuggestionsBottomSheetContent(
                     mTabModelSelector.getCurrentTab().getActivity(), this, mTabModelSelector);
         }
 
         showContent(mSuggestionsContent);
+
+        for (BottomSheetObserver o : mObservers) o.onSheetOpened();
+    }
+
+    /**
+     * A notification that the sheet has returned to the peeking state.
+     */
+    private void onSheetClosed() {
+        for (BottomSheetObserver o : mObservers) o.onSheetClosed();
     }
 
     /**
@@ -599,7 +609,10 @@
     private void setSheetOffsetFromBottom(float offset) {
         if (MathUtils.areFloatsEqual(getSheetOffsetFromBottom(), getMinOffset())
                 && offset > getMinOffset()) {
-            onExitPeekState();
+            onSheetOpened();
+        } else if (MathUtils.areFloatsEqual(offset, getMinOffset())
+                && getSheetOffsetFromBottom() > getMinOffset()) {
+            onSheetClosed();
         }
 
         setTranslationY(mContainerHeight - offset);
@@ -607,27 +620,47 @@
     }
 
     /**
+     * This is the same as {@link #setSheetOffsetFromBottom(float)} but exclusively for testing.
+     * @param offset The offset to set the sheet to.
+     */
+    @VisibleForTesting
+    public void setSheetOffsetFromBottomForTesting(float offset) {
+        setSheetOffsetFromBottom(offset);
+    }
+
+    /**
      * @return The ratio of the height of the screen that the peeking state is.
      */
-    private float getPeekRatio() {
+    @VisibleForTesting
+    public float getPeekRatio() {
         return mStateRatios[0];
     }
 
     /**
      * @return The ratio of the height of the screen that the half expanded state is.
      */
-    private float getHalfRatio() {
+    @VisibleForTesting
+    public float getHalfRatio() {
         return mStateRatios[1];
     }
 
     /**
      * @return The ratio of the height of the screen that the fully expanded state is.
      */
-    private float getFullRatio() {
+    @VisibleForTesting
+    public float getFullRatio() {
         return mStateRatios[2];
     }
 
     /**
+     * @return The height of the container that the bottom sheet exists in.
+     */
+    @VisibleForTesting
+    public float getSheetContainerHeight() {
+        return mContainerHeight;
+    }
+
+    /**
      * Sends a notification if the sheet is transitioning from the peeking to half expanded state.
      * This method only sends events when the sheet is between the peeking and half states.
      */
@@ -643,9 +676,9 @@
         // If the ratio is close enough to zero, just set it to zero.
         if (MathUtils.areFloatsEqual(peekHalfRatio, 0f)) peekHalfRatio = 0f;
 
-        for (BottomSheetObserver o : mObservers) {
-            if (mLastPeekToHalfRatioSent < 1f || peekHalfRatio < 1f) {
-                mLastPeekToHalfRatioSent = peekHalfRatio;
+        if (mLastPeekToHalfRatioSent < 1f || peekHalfRatio < 1f) {
+            mLastPeekToHalfRatioSent = peekHalfRatio;
+            for (BottomSheetObserver o : mObservers) {
                 o.onTransitionPeekToHalf(peekHalfRatio);
             }
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java
index 37aa70e..6e4dfad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheetObserver.java
@@ -9,6 +9,23 @@
  */
 public interface BottomSheetObserver {
     /**
+     * A notification that the sheet has been opened, meaning the sheet is any height greater
+     * than its peeking state.
+     */
+    void onSheetOpened();
+
+    /**
+     * A notification that the sheet has closed, meaning the sheet has reached its peeking state.
+     */
+    void onSheetClosed();
+
+    /**
+     * A notification that the sheet has begun loading a URL.
+     * @param url The URL being loaded.
+     */
+    void onLoadUrl(String url);
+
+    /**
      * An event for when the sheet is transitioning from the peeking state to the half expanded
      * state. Once the sheet is outside the peek-half range, this event will no longer be
      * called.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
index 186a413..9135e60 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
@@ -151,4 +151,13 @@
     public void onTransitionPeekToHalf(float transitionFraction) {
         setViewAlpha(transitionFraction);
     }
+
+    @Override
+    public void onSheetOpened() {}
+
+    @Override
+    public void onSheetClosed() {}
+
+    @Override
+    public void onLoadUrl(String url) {}
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index df2ac1dc..83abfcf 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1512,6 +1512,7 @@
   "javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebappUrlBarTest.java",
   "javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java",
+  "javatests/src/org/chromium/chrome/browser/widget/BottomSheetObserverTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/DualControlLayoutTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/RoundedIconGeneratorTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/BottomSheetObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/BottomSheetObserverTest.java
new file mode 100644
index 0000000..5ac7212
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/BottomSheetObserverTest.java
@@ -0,0 +1,200 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.widget;
+
+import android.support.test.filters.MediumTest;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.chrome.test.BottomSheetTestCaseBase;
+
+import java.util.concurrent.TimeoutException;
+
+/** This class tests the functionality of the {@link BottomSheetObserver}. */
+public class BottomSheetObserverTest extends BottomSheetTestCaseBase {
+    /** A handle to the sheet's observer. */
+    private TestBottomSheetObserver mObserver;
+
+    /** An observer used to record events that occur with respect to the bottom sheet. */
+    private static class TestBottomSheetObserver implements BottomSheetObserver {
+        /** A {@link CallbackHelper} that can wait for the bottom sheet to be closed. */
+        private final CallbackHelper mClosedCallbackHelper = new CallbackHelper();
+
+        /** A {@link CallbackHelper} that can wait for the bottom sheet to be opened. */
+        private final CallbackHelper mOpenedCallbackHelper = new CallbackHelper();
+
+        /** A {@link CallbackHelper} that can wait for the onTransitionPeekToHalf event. */
+        private final CallbackHelper mPeekToHalfCallbackHelper = new CallbackHelper();
+
+        /** The last value that the onTransitionPeekToHalf event sent. */
+        private float mLastPeekToHalfValue;
+
+        @Override
+        public void onTransitionPeekToHalf(float fraction) {
+            mLastPeekToHalfValue = fraction;
+            mPeekToHalfCallbackHelper.notifyCalled();
+        }
+
+        @Override
+        public void onSheetOpened() {
+            mOpenedCallbackHelper.notifyCalled();
+        }
+
+        @Override
+        public void onSheetClosed() {
+            mClosedCallbackHelper.notifyCalled();
+        }
+
+        @Override
+        public void onLoadUrl(String url) {}
+
+        public CallbackHelper getClosedCallbackHelper() {
+            return mClosedCallbackHelper;
+        }
+
+        public CallbackHelper getOpenedCallbackHelper() {
+            return mOpenedCallbackHelper;
+        }
+
+        public CallbackHelper getPeekToHalfCallbackHelper() {
+            return mPeekToHalfCallbackHelper;
+        }
+
+        public float getLastPeekToHalfValue() {
+            return mLastPeekToHalfValue;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mObserver = new TestBottomSheetObserver();
+        mBottomSheet.addObserver(mObserver);
+    }
+
+    /**
+     * Test that the onSheetClosed event is triggered if the sheet is closed without animation.
+     */
+    @MediumTest
+    public void testCloseEventCalledNoAnimation() throws InterruptedException, TimeoutException {
+        setSheetState(BottomSheet.SHEET_STATE_FULL, false);
+
+        CallbackHelper closedCallbackHelper = mObserver.getClosedCallbackHelper();
+
+        int initialOpenedCount = mObserver.getOpenedCallbackHelper().getCallCount();
+
+        int closedCallbackCount = closedCallbackHelper.getCallCount();
+        setSheetState(BottomSheet.SHEET_STATE_PEEK, false);
+        closedCallbackHelper.waitForCallback(closedCallbackCount, 1);
+
+        assertEquals(initialOpenedCount, mObserver.getOpenedCallbackHelper().getCallCount());
+    }
+
+    /**
+     * Test that the onSheetClosed event is triggered if the sheet is closed with animation.
+     */
+    @MediumTest
+    public void testCloseEventCalledWithAnimation() throws InterruptedException, TimeoutException {
+        setSheetState(BottomSheet.SHEET_STATE_FULL, false);
+
+        CallbackHelper closedCallbackHelper = mObserver.getClosedCallbackHelper();
+
+        int initialOpenedCount = mObserver.getOpenedCallbackHelper().getCallCount();
+
+        int closedCallbackCount = closedCallbackHelper.getCallCount();
+        setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
+        closedCallbackHelper.waitForCallback(closedCallbackCount, 1);
+
+        assertEquals(initialOpenedCount, mObserver.getOpenedCallbackHelper().getCallCount());
+    }
+
+    /**
+     * Test that the onSheetOpened event is triggered if the sheet is opened without animation.
+     */
+    @MediumTest
+    public void testOpenedEventCalledNoAnimation() throws InterruptedException, TimeoutException {
+        setSheetState(BottomSheet.SHEET_STATE_PEEK, false);
+
+        CallbackHelper openedCallbackHelper = mObserver.getOpenedCallbackHelper();
+
+        int initialClosedCount = mObserver.getClosedCallbackHelper().getCallCount();
+
+        int openedCallbackCount = openedCallbackHelper.getCallCount();
+        setSheetState(BottomSheet.SHEET_STATE_FULL, false);
+        openedCallbackHelper.waitForCallback(openedCallbackCount, 1);
+
+        assertEquals(initialClosedCount, mObserver.getClosedCallbackHelper().getCallCount());
+    }
+
+    /**
+     * Test that the onSheetOpened event is triggered if the sheet is opened with animation.
+     */
+    @MediumTest
+    public void testOpenedEventCalledWithAnimation() throws InterruptedException, TimeoutException {
+        setSheetState(BottomSheet.SHEET_STATE_PEEK, false);
+
+        CallbackHelper openedCallbackHelper = mObserver.getOpenedCallbackHelper();
+
+        int initialClosedCount = mObserver.getClosedCallbackHelper().getCallCount();
+
+        int openedCallbackCount = openedCallbackHelper.getCallCount();
+        setSheetState(BottomSheet.SHEET_STATE_FULL, true);
+        openedCallbackHelper.waitForCallback(openedCallbackCount, 1);
+
+        assertEquals(initialClosedCount, mObserver.getClosedCallbackHelper().getCallCount());
+    }
+
+    /**
+     * Test the onTransitionPeekToHalf event.
+     */
+    @MediumTest
+    public void testPeekToHalfTransition() throws InterruptedException, TimeoutException {
+        CallbackHelper callbackHelper = mObserver.getPeekToHalfCallbackHelper();
+
+        float peekHeight = mBottomSheet.getPeekRatio() * mBottomSheet.getSheetContainerHeight();
+        float halfHeight = mBottomSheet.getHalfRatio() * mBottomSheet.getSheetContainerHeight();
+        float fullHeight = mBottomSheet.getFullRatio() * mBottomSheet.getSheetContainerHeight();
+
+        float midPeekHalf = (peekHeight + halfHeight) / 2f;
+        float midHalfFull = (halfHeight + fullHeight) / 2f;
+
+        // When in the peeking state, the transition value should be 0.
+        int callbackCount = callbackHelper.getCallCount();
+        setSheetOffsetFromBottom(peekHeight);
+        callbackHelper.waitForCallback(callbackCount, 1);
+        assertEquals(0f, mObserver.getLastPeekToHalfValue(), MathUtils.EPSILON);
+
+        // When in between peek and half states, the transition value should be 0.5.
+        callbackCount = callbackHelper.getCallCount();
+        setSheetOffsetFromBottom(midPeekHalf);
+        callbackHelper.waitForCallback(callbackCount, 1);
+        assertEquals(0.5f, mObserver.getLastPeekToHalfValue(), MathUtils.EPSILON);
+
+        // After jumping to the full state (skipping the half state), the event should have
+        // triggered once more with a max value of 1.
+        callbackCount = callbackHelper.getCallCount();
+        setSheetOffsetFromBottom(fullHeight);
+        callbackHelper.waitForCallback(callbackCount, 1);
+        assertEquals(1f, mObserver.getLastPeekToHalfValue(), MathUtils.EPSILON);
+
+        // Moving from full to somewhere between half and full should not trigger the event.
+        callbackCount = callbackHelper.getCallCount();
+        setSheetOffsetFromBottom(midHalfFull);
+        assertEquals(callbackCount, callbackHelper.getCallCount());
+
+        // Reset the sheet to be between peek and half states.
+        callbackCount = callbackHelper.getCallCount();
+        setSheetOffsetFromBottom(midPeekHalf);
+        callbackHelper.waitForCallback(callbackCount, 1);
+        assertEquals(0.5f, mObserver.getLastPeekToHalfValue(), MathUtils.EPSILON);
+
+        // At the half state the event should send 1.
+        callbackCount = callbackHelper.getCallCount();
+        setSheetOffsetFromBottom(halfHeight);
+        callbackHelper.waitForCallback(callbackCount, 1);
+        assertEquals(1f, mObserver.getLastPeekToHalfValue(), MathUtils.EPSILON);
+    }
+}
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 1e40170..e55154c 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -11,12 +11,13 @@
 
     <uses-sdk
         android:minSdkVersion="16"
-        android:targetSdkVersion="23" />
+        android:targetSdkVersion="25" />
 
     <application
         android:icon="@mipmap/app_icon"
         android:label="{{ short_name }}"
-        android:allowBackup="false">
+        android:allowBackup="false"
+        android:resizeableActivity="true">
         <activity android:name="org.chromium.webapk.shell_apk.MainActivity"
                   android:theme="@android:style/Theme.Translucent.NoTitleBar"
                   android:excludeFromRecents="true">
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc
index ba0a9b9..b8d8e78 100644
--- a/chrome/app/chrome_crash_reporter_client_win.cc
+++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -190,9 +190,6 @@
       {"postmessage_dst_url", kLargeSize},
       {"postmessage_script_info", kLargeSize},
 
-      // Temporary for https://crbug.com/616149.
-      {"existing_extension_pref_value_type", crash_keys::kSmallSize},
-
       // Temporary for https://crbug.com/668633.
       {"swdh_set_hosted_version_worker_pid", crash_keys::kSmallSize},
       {"swdh_set_hosted_version_host_pid", crash_keys::kSmallSize},
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1509877..d0b2cc30 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3584,9 +3584,6 @@
       <message name="IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE" desc="Titlebar of the extension or app permissions prompt. Shows the user the permissions a particular extension or app has.">
         Current Permissions for "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"
       </message>
-      <message name="IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE" desc="Titlebar of the app launch prompt. Asks the user if they want to launch a particular app.">
-        Try "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"?
-      </message>
       <message name="IDS_EXTENSION_REMOTE_INSTALL_PROMPT_TITLE" desc="Titlebar of the extension or app installation prompt. Asks the user if they want to enable a particular extension or app that was installed remotely.">
         Enable "<ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph>"?
       </message>
@@ -3671,9 +3668,6 @@
       <message name="IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO" desc="Second line in the content area of the extension or app re-enable prompt. Note that the exact wording is important. This should mean that the extension _can now_ access the listed privileges, but not necessarily that it will or needs to. This message appeared because the user must approve new permissions of the extension or app.">
         It can now:
       </message>
-      <message name="IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO" desc="Header for the permissions area of the bundled extension or app installation prompt. Note that the exact wording is important. This means that the extensions or apps _can_ access the listed privileges, but not necessarily that it will or needs to.">
-        They can:
-      </message>
       <message name="IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO" desc="Second line in the content area of the extension or app permissions prompt. Note that the exact wording is important. This should mean that the extension _wants to_ access the listed privileges, but not necessarily that it will or needs to. This message appeared because the user must approve new permissions of the extension or app.">
         It could:
       </message>
@@ -4669,9 +4663,6 @@
       <message name="IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_THEME" desc="Text for the install button on the extension install prompt, for a theme.">
         Add theme
       </message>
-      <message name="IDS_EXTENSION_PROMPT_LAUNCH_BUTTON" desc="Text for the launch button on the extension install prompt">
-        Launch app
-      </message>
       <message name="IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON" desc="Text for the uninstall button on the extension uninstall prompt">
         Remove
       </message>
@@ -10495,7 +10486,7 @@
         Google may use your browsing history to personalize Search, ads, and other Google services
       </message>
       <message name="IDS_SYNC_CONFIRMATION_SYNC_SETTINGS_LINK_BODY" desc="Label of the section containing the link to go to the sync setting page.">
-        Control how this works in <ph name="BEGIN_LINK">&lt;a id="settingsLink" href="#"&gt;</ph>Settings<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
+        Control how this works in <ph name="BEGIN_LINK">&lt;a id="settingsLink" href="chrome://settings"&gt;</ph>Settings<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
       </message>
       <message name="IDS_SYNC_CONFIRMATION_CONFIRM_BUTTON_LABEL" desc="Label of the confirmation button in the sync confirmation dialog of the tab modal signin flow">
         Ok, got it
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d81af4e..a8f622a6 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -803,6 +803,8 @@
     "page_load_metrics/observers/service_worker_page_load_metrics_observer.h",
     "page_load_metrics/observers/subresource_filter_metrics_observer.cc",
     "page_load_metrics/observers/subresource_filter_metrics_observer.h",
+    "page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc",
+    "page_load_metrics/observers/tab_restore_page_load_metrics_observer.h",
     "page_load_metrics/observers/ukm_page_load_metrics_observer.cc",
     "page_load_metrics/observers/ukm_page_load_metrics_observer.h",
     "page_load_metrics/page_load_metrics_embedder_interface.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c2ae2bb..c9d5066b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -535,7 +535,7 @@
 #if defined(OS_ANDROID)
 const FeatureEntry::FeatureParam
     kContentSuggestionsNotificationsFeatureVariationAlways[] = {
-        {kContentSuggestionsNotificationsAlwaysNotifyParam, "true"}};
+        {params::ntp_snippets::kNotificationsAlwaysNotifyParam, "true"}};
 
 const FeatureEntry::FeatureVariation
     kContentSuggestionsNotificationsFeatureVariations[] = {
@@ -1152,8 +1152,9 @@
                                app_list::switches::kDisableSyncAppList)},
 #endif  // ENABLE_APP_LIST
     {"lcd-text-aa", IDS_FLAGS_LCD_TEXT_NAME, IDS_FLAGS_LCD_TEXT_DESCRIPTION,
-     kOsDesktop, ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLCDText,
-                                           switches::kDisableLCDText)},
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLCDText,
+                               switches::kDisableLCDText)},
     {"enable-offer-store-unmasked-wallet-cards",
      IDS_FLAGS_OFFER_STORE_UNMASKED_WALLET_CARDS,
      IDS_FLAGS_OFFER_STORE_UNMASKED_WALLET_CARDS_DESCRIPTION, kOsAll,
@@ -1187,8 +1188,9 @@
     {"cross-origin-media-playback-requires-user-gesture",
      IDS_FLAGS_CROSS_ORIGIN_MEDIA_PLAYBACK_REQUIRES_USER_GESTURE_NAME,
      IDS_FLAGS_CROSS_ORIGIN_MEDIA_PLAYBACK_REQUIRES_USER_GESTURE_DESCRIPTION,
-     kOsDesktop, FEATURE_VALUE_TYPE(
-                     features::kCrossOriginMediaPlaybackRequiresUserGesture)},
+     kOsDesktop,
+     FEATURE_VALUE_TYPE(
+         features::kCrossOriginMediaPlaybackRequiresUserGesture)},
 #endif  // !defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
@@ -1545,8 +1547,9 @@
     {"enable-data-reduction-proxy-savings-promo",
      IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_SAVINGS_PROMO_NAME,
      IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_SAVINGS_PROMO_DESCRIPTION,
-     kOsAndroid, SINGLE_VALUE_TYPE(data_reduction_proxy::switches::
-                                       kEnableDataReductionProxySavingsPromo)},
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(data_reduction_proxy::switches::
+                           kEnableDataReductionProxySavingsPromo)},
 #endif  // OS_ANDROID
     {"allow-insecure-localhost", IDS_ALLOW_INSECURE_LOCALHOST,
      IDS_ALLOW_INSECURE_LOCALHOST_DESCRIPTION, kOsAll,
@@ -1916,7 +1919,7 @@
      IDS_FLAGS_ENABLE_NTP_SUGGESTIONS_NOTIFICATIONS_NAME,
      IDS_FLAGS_ENABLE_NTP_SUGGESTIONS_NOTIFICATIONS_DESCRIPTION, kOsAndroid,
      FEATURE_WITH_VARIATIONS_VALUE_TYPE(
-         kContentSuggestionsNotificationsFeature,
+         params::ntp_snippets::kNotificationsFeature,
          kContentSuggestionsNotificationsFeatureVariations,
          ntp_snippets::kStudyName)},
     {"ntp-condensed-layout", IDS_FLAGS_NTP_CONDENSED_LAYOUT_NAME,
@@ -2190,10 +2193,11 @@
     {"enable-expanded-autofill-credit-card-popup",
      IDS_FLAGS_ENABLE_EXPANDED_AUTOFILL_CREDIT_CARD_POPUP_LAYOUT,
      IDS_FLAGS_ENABLE_EXPANDED_AUTOFILL_CREDIT_CARD_POPUP_LAYOUT_DESCRIPTION,
-     kOsAndroid, FEATURE_WITH_VARIATIONS_VALUE_TYPE(
-                     autofill::kAutofillCreditCardPopupLayout,
-                     kAutofillCreditCardPopupLayoutFeatureVariations,
-                     "AutofillCreditCardPopupLayout")},
+     kOsAndroid,
+     FEATURE_WITH_VARIATIONS_VALUE_TYPE(
+         autofill::kAutofillCreditCardPopupLayout,
+         kAutofillCreditCardPopupLayoutFeatureVariations,
+         "AutofillCreditCardPopupLayout")},
     {"native-android-history-manager", IDS_NATIVE_ANDROID_HISTORY_MANAGER,
      IDS_NATIVE_ANDROID_HISTORY_MANAGER_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(features::kNativeAndroidHistoryManager)},
@@ -2201,10 +2205,11 @@
     {"enable-autofill-credit-card-last-used-date-display",
      IDS_FLAGS_ENABLE_AUTOFILL_CREDIT_CARD_LAST_USED_DATE_DISPLAY,
      IDS_FLAGS_ENABLE_AUTOFILL_CREDIT_CARD_LAST_USED_DATE_DISPLAY_DESCRIPTION,
-     kOsAll, FEATURE_WITH_VARIATIONS_VALUE_TYPE(
-                 autofill::kAutofillCreditCardLastUsedDateDisplay,
-                 kAutofillCreditCardLastUsedDateFeatureVariations,
-                 "AutofillCreditCardLastUsedDate")},
+     kOsAll,
+     FEATURE_WITH_VARIATIONS_VALUE_TYPE(
+         autofill::kAutofillCreditCardLastUsedDateDisplay,
+         kAutofillCreditCardLastUsedDateFeatureVariations,
+         "AutofillCreditCardLastUsedDate")},
 #if defined(OS_WIN)
     {"windows10-custom-titlebar", IDS_FLAGS_WINDOWS10_CUSTOM_TITLEBAR_NAME,
      IDS_FLAGS_WINDOWS10_CUSTOM_TITLEBAR_DESCRIPTION, kOsWin,
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc
index 9d0bff1..866e583 100644
--- a/chrome/browser/android/banners/app_banner_manager_android.cc
+++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -57,6 +57,7 @@
 AppBannerManagerAndroid::AppBannerManagerAndroid(
     content::WebContents* web_contents)
     : AppBannerManager(web_contents) {
+  can_install_webapk_ = ChromeWebApkHost::CanInstallWebApk();
   CreateJavaBannerManager();
 }
 
@@ -106,14 +107,14 @@
   native_app_data_.Reset(japp_data);
   app_title_ = ConvertJavaStringToUTF16(env, japp_title);
   native_app_package_ = ConvertJavaStringToUTF8(env, japp_package);
-  icon_url_ = GURL(ConvertJavaStringToUTF8(env, jicon_url));
+  primary_icon_url_ = GURL(ConvertJavaStringToUTF8(env, jicon_url));
 
   if (!CheckIfShouldShowBanner())
     return false;
 
   return ManifestIconDownloader::Download(
-      web_contents(), icon_url_, GetIdealIconSizeInPx(),
-      GetMinimumIconSizeInPx(),
+      web_contents(), primary_icon_url_, GetIdealPrimaryIconSizeInPx(),
+      GetMinimumPrimaryIconSizeInPx(),
       base::Bind(&AppBannerManager::OnAppIconFetched, GetWeakPtr()));
 }
 
@@ -126,6 +127,10 @@
   AppBannerManager::RequestAppBanner(validated_url, is_debug_mode);
 }
 
+int AppBannerManagerAndroid::GetIdealBadgeIconSizeInPx() {
+  return ShortcutHelper::GetIdealBadgeIconSizeInPx();
+}
+
 std::string AppBannerManagerAndroid::GetAppIdentifier() {
   return native_app_data_.is_null() ? AppBannerManager::GetAppIdentifier()
                                     : native_app_package_;
@@ -136,11 +141,11 @@
                                     : "play";
 }
 
-int AppBannerManagerAndroid::GetIdealIconSizeInPx() {
+int AppBannerManagerAndroid::GetIdealPrimaryIconSizeInPx() {
   return ShortcutHelper::GetIdealHomescreenIconSizeInPx();
 }
 
-int AppBannerManagerAndroid::GetMinimumIconSizeInPx() {
+int AppBannerManagerAndroid::GetMinimumPrimaryIconSizeInPx() {
   return ShortcutHelper::GetMinimumHomescreenIconSizeInPx();
 }
 
@@ -158,6 +163,19 @@
                                            manifest_url);
 }
 
+InstallableParams AppBannerManagerAndroid::ParamsToPerformInstallableCheck() {
+  InstallableParams params =
+      AppBannerManager::ParamsToPerformInstallableCheck();
+
+  if (can_install_webapk_) {
+    params.ideal_badge_icon_size_in_px = GetIdealBadgeIconSizeInPx();
+    params.minimum_badge_icon_size_in_px = GetIdealBadgeIconSizeInPx();
+    params.fetch_valid_badge_icon = true;
+  }
+
+  return params;
+}
+
 void AppBannerManagerAndroid::PerformInstallableCheck() {
   // Check if the manifest prefers that we show a native app banner. If so, call
   // to Java to verify the details.
@@ -172,7 +190,7 @@
     Stop();
   }
 
-  if (ChromeWebApkHost::CanInstallWebApk()) {
+  if (can_install_webapk_) {
     if (!AreWebManifestUrlsWebApkCompatible(manifest_)) {
       ReportStatus(web_contents(), URL_NOT_SUPPORTED_FOR_WEBAPK);
       Stop();
@@ -184,6 +202,18 @@
   AppBannerManager::PerformInstallableCheck();
 }
 
+void AppBannerManagerAndroid::OnDidPerformInstallableCheck(
+    const InstallableData& data) {
+  if (data.badge_icon && !data.badge_icon->drawsNothing()) {
+    DCHECK(!data.badge_icon_url.is_empty());
+
+    badge_icon_url_ = data.badge_icon_url;
+    badge_icon_.reset(new SkBitmap(*data.badge_icon));
+  }
+
+  AppBannerManager::OnDidPerformInstallableCheck(data);
+}
+
 void AppBannerManagerAndroid::OnAppIconFetched(const SkBitmap& bitmap) {
   if (bitmap.drawsNothing()) {
     ReportStatus(web_contents(), NO_ICON_AVAILABLE);
@@ -193,7 +223,7 @@
   if (!is_active())
     return;
 
-  icon_.reset(new SkBitmap(bitmap));
+  primary_icon_.reset(new SkBitmap(bitmap));
   SendBannerPromptRequest();
 }
 
@@ -208,10 +238,11 @@
   DCHECK(contents);
 
   if (native_app_data_.is_null()) {
+    // TODO(zpeng): Add badge to WebAPK installation flow.
     if (AppBannerInfoBarDelegateAndroid::Create(
             contents, GetWeakPtr(), app_title_,
-            CreateShortcutInfo(manifest_url_, manifest_, icon_url_),
-            std::move(icon_), event_request_id(),
+            CreateShortcutInfo(manifest_url_, manifest_, primary_icon_url_),
+            std::move(primary_icon_), event_request_id(),
             webapk::INSTALL_SOURCE_BANNER)) {
       RecordDidShowBanner("AppBanner.WebApp.Shown");
       TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED);
@@ -221,7 +252,7 @@
     }
   } else {
     if (AppBannerInfoBarDelegateAndroid::Create(
-            contents, app_title_, native_app_data_, std::move(icon_),
+            contents, app_title_, native_app_data_, std::move(primary_icon_),
             native_app_package_, referrer_, event_request_id())) {
       RecordDidShowBanner("AppBanner.NativeApp.Shown");
       TrackDisplayEvent(DISPLAY_EVENT_NATIVE_APP_BANNER_CREATED);
@@ -264,7 +295,7 @@
   ScopedJavaLocalRef<jstring> jreferrer(ConvertUTF8ToJavaString(env, referrer));
   Java_AppBannerManager_fetchAppDetails(env, java_banner_manager_, jurl,
                                         jpackage, jreferrer,
-                                        GetIdealIconSizeInPx());
+                                        GetIdealPrimaryIconSizeInPx());
   return true;
 }
 
diff --git a/chrome/browser/android/banners/app_banner_manager_android.h b/chrome/browser/android/banners/app_banner_manager_android.h
index 4e0ea6a8..92f8ce0 100644
--- a/chrome/browser/android/banners/app_banner_manager_android.h
+++ b/chrome/browser/android/banners/app_banner_manager_android.h
@@ -65,15 +65,20 @@
   static bool Register(JNIEnv* env);
 
  protected:
+  // Return the ideal badge icon size.
+  int GetIdealBadgeIconSizeInPx();
+
   // AppBannerManager overrides.
   std::string GetAppIdentifier() override;
   std::string GetBannerType() override;
-  int GetIdealIconSizeInPx() override;
-  int GetMinimumIconSizeInPx() override;
+  int GetIdealPrimaryIconSizeInPx() override;
+  int GetMinimumPrimaryIconSizeInPx() override;
   bool IsWebAppInstalled(content::BrowserContext* browser_context,
                          const GURL& start_url,
                          const GURL& manifest_url) override;
+  InstallableParams ParamsToPerformInstallableCheck() override;
   void PerformInstallableCheck() override;
+  void OnDidPerformInstallableCheck(const InstallableData& result) override;
   void OnAppIconFetched(const SkBitmap& bitmap) override;
   void ResetCurrentPageData() override;
   void ShowBanner() override;
@@ -101,6 +106,12 @@
                           const GURL& url,
                           const std::string& id);
 
+  // The URL of the badge icon.
+  GURL badge_icon_url_;
+
+  // The badge icon object.
+  std::unique_ptr<SkBitmap> badge_icon_;
+
   // The Java-side AppBannerManager.
   base::android::ScopedJavaGlobalRef<jobject> java_banner_manager_;
 
@@ -110,6 +121,9 @@
   // App package name for a native app banner.
   std::string native_app_package_;
 
+  // Whether WebAPKs can be installed.
+  bool can_install_webapk_;
+
   DISALLOW_COPY_AND_ASSIGN(AppBannerManagerAndroid);
 };
 
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
index 4b2c0825..fb7dc10 100644
--- a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
+++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
@@ -22,6 +22,9 @@
 #include "ui/gfx/image/image_skia.h"
 
 using base::android::JavaParamRef;
+using params::ntp_snippets::kNotificationsFeature;
+using params::ntp_snippets::kNotificationsIgnoredLimitParam;
+using params::ntp_snippets::kNotificationsIgnoredDefaultLimit;
 
 namespace ntp_snippets {
 
@@ -32,9 +35,8 @@
   int current =
       prefs->GetInteger(prefs::kContentSuggestionsConsecutiveIgnoredPrefName);
   int limit = variations::GetVariationParamByFeatureAsInt(
-      kContentSuggestionsNotificationsFeature,
-      kContentSuggestionsNotificationsIgnoredLimitParam,
-      kContentSuggestionsNotificationsIgnoredDefaultLimit);
+      kNotificationsFeature, kNotificationsIgnoredLimitParam,
+      kNotificationsIgnoredDefaultLimit);
   return current >= limit;
 }
 
diff --git a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
index 0425296a9..8d53c9b 100644
--- a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
+++ b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
@@ -29,6 +29,12 @@
 using ntp_snippets::ContentSuggestionsNotificationHelper;
 using ntp_snippets::ContentSuggestionsService;
 using ntp_snippets::KnownCategories;
+using params::ntp_snippets::kNotificationsAlwaysNotifyParam;
+using params::ntp_snippets::kNotificationsDailyLimit;
+using params::ntp_snippets::kNotificationsDefaultDailyLimit;
+using params::ntp_snippets::kNotificationsFeature;
+using params::ntp_snippets::kNotificationsKeepWhenFrontmostParam;
+using params::ntp_snippets::kNotificationsUseSnippetAsTextParam;
 
 namespace {
 
@@ -70,9 +76,8 @@
 bool HaveQuotaForToday(PrefService* prefs) {
   int today = DayAsYYYYMMDD();
   int limit = variations::GetVariationParamByFeatureAsInt(
-      kContentSuggestionsNotificationsFeature,
-      kContentSuggestionsNotificationsDailyLimit,
-      kContentSuggestionsNotificationsDefaultDailyLimit);
+      kNotificationsFeature, kNotificationsDailyLimit,
+      kNotificationsDefaultDailyLimit);
   int sent =
       prefs->GetInteger(prefs::kContentSuggestionsNotificationsSentDay) == today
           ? prefs->GetInteger(prefs::kContentSuggestionsNotificationsSentCount)
@@ -125,8 +130,7 @@
                                 ? suggestion->notification_extra()->deadline
                                 : base::Time::Max();
     bool use_snippet = variations::GetVariationParamByFeatureAsBool(
-        kContentSuggestionsNotificationsFeature,
-        kContentSuggestionsNotificationsUseSnippetAsTextParam, false);
+        kNotificationsFeature, kNotificationsUseSnippetAsTextParam, false);
     service_->FetchSuggestionImage(
         suggestion->id(),
         base::Bind(&NotifyingObserver::ImageFetched,
@@ -179,8 +183,7 @@
     const auto& suggestions = service_->GetSuggestionsForCategory(category);
     // TODO(sfiera): replace with AlwaysNotifyAboutContentSuggestions().
     if (variations::GetVariationParamByFeatureAsBool(
-             kContentSuggestionsNotificationsFeature,
-             kContentSuggestionsNotificationsAlwaysNotifyParam, false)) {
+            kNotificationsFeature, kNotificationsAlwaysNotifyParam, false)) {
       if (category.IsKnownCategory(KnownCategories::ARTICLES) &&
           !suggestions.empty()) {
         return &suggestions[0];
@@ -198,8 +201,7 @@
 
   void AppStatusChanged(base::android::ApplicationState state) {
     if (variations::GetVariationParamByFeatureAsBool(
-            kContentSuggestionsNotificationsFeature,
-            kContentSuggestionsNotificationsKeepNotificationWhenFrontmostParam,
+            kNotificationsFeature, kNotificationsKeepWhenFrontmostParam,
             false)) {
       return;
     }
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 15d33758..f3c87d17 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -710,6 +710,7 @@
     const JavaParamRef<jobject>& unused_obj,
     const JavaParamRef<jstring>& jguid,
     const JavaParamRef<jstring>& jregion_code,
+    jint jtimeout_seconds,
     const JavaParamRef<jobject>& jdelegate) {
   const std::string region_code = ConvertJavaStringToUTF8(env, jregion_code);
   const std::string guid = ConvertJavaStringToUTF8(env, jguid);
@@ -723,7 +724,7 @@
 
   // Start the normalization.
   address_normalizer_.StartAddressNormalization(*profile, region_code,
-                                                requester);
+                                                jtimeout_seconds, requester);
 }
 
 jboolean PersonalDataManagerAndroid::HasProfiles(
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.h b/chrome/browser/autofill/android/personal_data_manager_android.h
index 10c7b12..15013b1 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.h
+++ b/chrome/browser/autofill/android/personal_data_manager_android.h
@@ -292,13 +292,15 @@
   // Normalizes the address of the profile associated with the |jguid|
   // synchronously if the |jregion_code| rules have finished loading. Otherwise
   // sets up the task to start the address normalization when the rules have
-  // finished loading. In either case, sends the normalized profile to the
-  // |jdelegate|.
+  // finished loading. Also defines a time limit for the normalization, in which
+  // case the the |jdelegate| will be notified. If the rules are loaded before
+  // the timeout, |jdelegate| will receive the normalized profile.
   void StartAddressNormalization(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& unused_obj,
       const base::android::JavaParamRef<jstring>& jguid,
       const base::android::JavaParamRef<jstring>& jregion_code,
+      jint jtimeout_seconds,
       const base::android::JavaParamRef<jobject>& jdelegate);
 
   // Checks whether the Autofill PersonalDataManager has profiles.
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 00baa31..156fa026 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -36,19 +36,6 @@
   return InstallableParams();
 }
 
-// Returns an InstallableParams object that requests all checks necessary for
-// a web app banner.
-InstallableParams ParamsToPerformInstallableCheck(int ideal_icon_size_in_px,
-                                                  int minimum_icon_size_in_px) {
-  InstallableParams params;
-  params.ideal_primary_icon_size_in_px = ideal_icon_size_in_px;
-  params.minimum_primary_icon_size_in_px = minimum_icon_size_in_px;
-  params.check_installable = true;
-  params.fetch_valid_primary_icon = true;
-
-  return params;
-}
-
 }  // anonymous namespace
 
 namespace banners {
@@ -199,11 +186,11 @@
   return std::string();
 }
 
-int AppBannerManager::GetIdealIconSizeInPx() {
+int AppBannerManager::GetIdealPrimaryIconSizeInPx() {
   return InstallableManager::GetMinimumIconSizeInPx();
 }
 
-int AppBannerManager::GetMinimumIconSizeInPx() {
+int AppBannerManager::GetMinimumPrimaryIconSizeInPx() {
   return InstallableManager::GetMinimumIconSizeInPx();
 }
 
@@ -244,13 +231,22 @@
   PerformInstallableCheck();
 }
 
+InstallableParams AppBannerManager::ParamsToPerformInstallableCheck() {
+  InstallableParams params;
+  params.ideal_primary_icon_size_in_px = GetIdealPrimaryIconSizeInPx();
+  params.minimum_primary_icon_size_in_px = GetMinimumPrimaryIconSizeInPx();
+  params.check_installable = true;
+  params.fetch_valid_primary_icon = true;
+
+  return params;
+}
+
 void AppBannerManager::PerformInstallableCheck() {
   if (!CheckIfShouldShowBanner())
     return;
 
   // Fetch and verify the other required information.
-  manager_->GetData(ParamsToPerformInstallableCheck(GetIdealIconSizeInPx(),
-                                                    GetMinimumIconSizeInPx()),
+  manager_->GetData(ParamsToPerformInstallableCheck(),
                     base::Bind(&AppBannerManager::OnDidPerformInstallableCheck,
                                GetWeakPtr()));
 }
@@ -275,8 +271,8 @@
   DCHECK(!data.primary_icon_url.is_empty());
   DCHECK(data.primary_icon);
 
-  icon_url_ = data.primary_icon_url;
-  icon_.reset(new SkBitmap(*data.primary_icon));
+  primary_icon_url_ = data.primary_icon_url;
+  primary_icon_.reset(new SkBitmap(*data.primary_icon));
 
   SendBannerPromptRequest();
 }
@@ -524,8 +520,8 @@
 
   DCHECK(!manifest_url_.is_empty());
   DCHECK(!manifest_.IsEmpty());
-  DCHECK(!icon_url_.is_empty());
-  DCHECK(icon_.get());
+  DCHECK(!primary_icon_url_.is_empty());
+  DCHECK(primary_icon_.get());
 
   TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE);
   ShowBanner();
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index e5dab9f..e043913 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -120,9 +120,9 @@
   // |code|. Returns the empty string if |code| requires no parameter.
   std::string GetStatusParam(InstallableStatusCode code);
 
-  // Returns the ideal and minimum icon sizes required for being installable.
-  virtual int GetIdealIconSizeInPx();
-  virtual int GetMinimumIconSizeInPx();
+  // Returns the ideal and minimum primary icon size requirements.
+  virtual int GetIdealPrimaryIconSizeInPx();
+  virtual int GetMinimumPrimaryIconSizeInPx();
 
   // Returns a WeakPtr to this object. Exposed so subclasses/infobars may
   // may bind callbacks without needing their own WeakPtrFactory.
@@ -141,6 +141,10 @@
   // manifest.
   void OnDidGetManifest(const InstallableData& result);
 
+  // Returns an InstallableParams object that requests all checks necessary for
+  // a web app banner.
+  virtual InstallableParams ParamsToPerformInstallableCheck();
+
   // Run at the conclusion of OnDidGetManifest. For web app banners, this calls
   // back to the InstallableManager to continue checking criteria. For native
   // app banners, this checks whether native apps are preferred in the manifest,
@@ -150,7 +154,7 @@
 
   // Callback invoked by the InstallableManager once it has finished checking
   // all other installable properties.
-  void OnDidPerformInstallableCheck(const InstallableData& result);
+  virtual void OnDidPerformInstallableCheck(const InstallableData& result);
 
   // Records that a banner was shown. The |event_name| corresponds to the RAPPOR
   // metric being recorded.
@@ -208,11 +212,11 @@
   // The manifest object.
   content::Manifest manifest_;
 
-  // The URL of the icon.
-  GURL icon_url_;
+  // The URL of the primary icon.
+  GURL primary_icon_url_;
 
-  // The icon object.
-  std::unique_ptr<SkBitmap> icon_;
+  // The primary icon object.
+  std::unique_ptr<SkBitmap> primary_icon_;
 
   // The referrer string (if any) specified in the app URL. Used only for native
   // app banners.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index bdcf9a1..7486bd47 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -210,6 +210,8 @@
     "app_mode/startup_app_launcher.h",
     "arc/accessibility/arc_accessibility_helper_bridge.cc",
     "arc/accessibility/arc_accessibility_helper_bridge.h",
+    "arc/accessibility/ax_tree_source_arc.cc",
+    "arc/accessibility/ax_tree_source_arc.h",
     "arc/arc_auth_context.cc",
     "arc/arc_auth_context.h",
     "arc/arc_auth_notification.cc",
diff --git a/chrome/browser/chromeos/arc/accessibility/OWNERS b/chrome/browser/chromeos/arc/accessibility/OWNERS
new file mode 100644
index 0000000..f3097ed
--- /dev/null
+++ b/chrome/browser/chromeos/arc/accessibility/OWNERS
@@ -0,0 +1,2 @@
+dtseng@chromium.org
+yawano@chromium.org
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
index 6e3c1a4..cbe7c69 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -4,11 +4,72 @@
 
 #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
 
+#include "base/command_line.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
-#include "components/exo/wm_helper.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/surface.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+// This class keeps focus on a |ShellSurface| without interfering with default
+// focus management in |ShellSurface|. For example, touch causes the
+// |ShellSurface| to lose focus to its ancestor containing View.
+class FocusStealer : public views::View {
+ public:
+  explicit FocusStealer(int32_t id) : id_(id) {
+    SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+    set_owned_by_client();
+  }
+
+  // views::View overrides.
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
+    node_data->AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, id_);
+  }
+
+ private:
+  int32_t id_;
+  DISALLOW_COPY_AND_ASSIGN(FocusStealer);
+};
+
+exo::Surface* GetArcSurface(const aura::Window* window) {
+  if (!window)
+    return nullptr;
+
+  exo::Surface* arc_surface = exo::Surface::AsSurface(window);
+  if (!arc_surface)
+    arc_surface = exo::ShellSurface::GetMainSurface(window);
+  return arc_surface;
+}
+
+void DispatchFocusChange(arc::mojom::AccessibilityNodeInfoData* node_data) {
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  if (!accessibility_manager)
+    return;
+
+  exo::WMHelper* wmHelper = exo::WMHelper::GetInstance();
+  aura::Window* focused_window = wmHelper->GetFocusedWindow();
+  if (!focused_window)
+    return;
+
+  aura::Window* toplevel_window = focused_window->GetToplevelWindow();
+
+  gfx::Rect bounds_in_screen = gfx::ScaleToEnclosingRect(
+      node_data->boundsInScreen,
+      1.0f / toplevel_window->layer()->device_scale_factor());
+
+  accessibility_manager->OnViewFocusedInArc(bounds_in_screen);
+}
+
+}  // namespace
 
 namespace arc {
 
@@ -27,37 +88,75 @@
       arc_bridge_service()->accessibility_helper(), Init);
   DCHECK(instance);
   instance->Init(binding_.CreateInterfacePtrAndBind());
-}
-
-void ArcAccessibilityHelperBridge::OnAccessibilityEvent(
-    mojom::AccessibilityEventType event_type,
-    mojom::AccessibilityNodeInfoDataPtr event_source) {
-  if (event_type != mojom::AccessibilityEventType::VIEW_FOCUSED ||
-      event_source.is_null()) {
-    return;
-  }
 
   chromeos::AccessibilityManager* accessibility_manager =
       chromeos::AccessibilityManager::Get();
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableChromeVoxArcSupport)) {
+    instance->SetFilter(arc::mojom::AccessibilityFilterType::ALL);
+    if (!tree_source_) {
+      tree_source_.reset(new AXTreeSourceArc());
+      focus_stealer_.reset(new FocusStealer(tree_source_->tree_id()));
+      exo::WMHelper::GetInstance()->AddActivationObserver(this);
+    }
+  } else if (accessibility_manager &&
+             accessibility_manager->IsFocusHighlightEnabled()) {
+    instance->SetFilter(arc::mojom::AccessibilityFilterType::FOCUS);
+  }
+}
 
-  if (!accessibility_manager ||
-      !accessibility_manager->IsFocusHighlightEnabled()) {
+void ArcAccessibilityHelperBridge::OnAccessibilityEventDeprecated(
+    mojom::AccessibilityEventType event_type,
+    mojom::AccessibilityNodeInfoDataPtr event_source) {
+  if (event_type == arc::mojom::AccessibilityEventType::VIEW_FOCUSED)
+    DispatchFocusChange(event_source.get());
+}
+
+void ArcAccessibilityHelperBridge::OnAccessibilityEvent(
+    mojom::AccessibilityEventDataPtr event_data) {
+  if (tree_source_) {
+    tree_source_->NotifyAccessibilityEvent(event_data.get());
     return;
   }
 
-  exo::WMHelper* wmHelper = exo::WMHelper::GetInstance();
-
-  aura::Window* focused_window = wmHelper->GetFocusedWindow();
-  if (!focused_window)
+  if (event_data->eventType != arc::mojom::AccessibilityEventType::VIEW_FOCUSED)
     return;
 
-  aura::Window* toplevel_window = focused_window->GetToplevelWindow();
+  CHECK_EQ(1U, event_data.get()->nodeData.size());
+  DispatchFocusChange(event_data.get()->nodeData[0].get());
+}
 
-  gfx::Rect bounds_in_screen = gfx::ScaleToEnclosingRect(
-      event_source.get()->boundsInScreen,
-      1.0f / toplevel_window->layer()->device_scale_factor());
+void ArcAccessibilityHelperBridge::OnWindowActivated(
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
+  if (gained_active == lost_active || !tree_source_)
+    return;
 
-  accessibility_manager->OnViewFocusedInArc(bounds_in_screen);
+  exo::Surface* active_surface = GetArcSurface(gained_active);
+  exo::Surface* inactive_surface = GetArcSurface(lost_active);
+
+  // Detach the accessibility tree from an inactive ShellSurface so that any
+  // client walking the desktop tree gets non-duplicated linearization.
+  if (inactive_surface) {
+    views::Widget* widget = views::Widget::GetWidgetForNativeView(lost_active);
+    if (widget && widget->GetContentsView()) {
+      views::View* view = widget->GetContentsView();
+      view->RemoveChildView(focus_stealer_.get());
+      view->NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false);
+    }
+  }
+
+  if (!active_surface)
+    return;
+
+  views::Widget* widget = views::Widget::GetWidgetForNativeView(gained_active);
+  if (widget && widget->GetContentsView()) {
+    views::View* view = widget->GetContentsView();
+    if (!view->Contains(focus_stealer_.get()))
+      view->AddChildView(focus_stealer_.get());
+    focus_stealer_->RequestFocus();
+    view->NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false);
+  }
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
index ad4abbd..aeaa640 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
@@ -5,14 +5,24 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
 #define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
 
+#include <memory>
+
 #include "components/arc/arc_service.h"
 #include "components/arc/common/accessibility_helper.mojom.h"
 #include "components/arc/instance_holder.h"
+#include "components/exo/wm_helper.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+namespace views {
+
+class View;
+
+}  // namespace views
+
 namespace arc {
 
 class ArcBridgeService;
+class AXTreeSourceArc;
 
 // ArcAccessibilityHelperBridge is an instance to receive converted Android
 // accessibility events and info via mojo interface and dispatch them to chrome
@@ -20,7 +30,8 @@
 class ArcAccessibilityHelperBridge
     : public ArcService,
       public mojom::AccessibilityHelperHost,
-      public InstanceHolder<mojom::AccessibilityHelperInstance>::Observer {
+      public InstanceHolder<mojom::AccessibilityHelperInstance>::Observer,
+      public exo::WMHelper::ActivationObserver {
  public:
   explicit ArcAccessibilityHelperBridge(ArcBridgeService* bridge_service);
   ~ArcAccessibilityHelperBridge() override;
@@ -29,13 +40,22 @@
   void OnInstanceReady() override;
 
   // mojom::AccessibilityHelperHost overrides.
-  void OnAccessibilityEvent(
+  void OnAccessibilityEventDeprecated(
       mojom::AccessibilityEventType event_type,
       mojom::AccessibilityNodeInfoDataPtr event_source) override;
+  void OnAccessibilityEvent(
+      mojom::AccessibilityEventDataPtr event_data) override;
 
  private:
+  // exo::WMHelper::ActivationObserver overrides.
+  void OnWindowActivated(aura::Window* gained_active,
+                         aura::Window* lost_active) override;
+
   mojo::Binding<mojom::AccessibilityHelperHost> binding_;
 
+  std::unique_ptr<AXTreeSourceArc> tree_source_;
+  std::unique_ptr<views::View> focus_stealer_;
+
   DISALLOW_COPY_AND_ASSIGN(ArcAccessibilityHelperBridge);
 };
 
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
new file mode 100644
index 0000000..a5e06bb
--- /dev/null
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -0,0 +1,249 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+
+#include <string>
+
+#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
+#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
+#include "components/exo/wm_helper.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
+#include "ui/aura/window.h"
+
+namespace {
+
+ui::AXEvent ToAXEvent(arc::mojom::AccessibilityEventType arc_event_type) {
+  switch (arc_event_type) {
+    case arc::mojom::AccessibilityEventType::VIEW_FOCUSED:
+    case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED:
+      return ui::AX_EVENT_FOCUS;
+    case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUS_CLEARED:
+      return ui::AX_EVENT_BLUR;
+    case arc::mojom::AccessibilityEventType::VIEW_CLICKED:
+    case arc::mojom::AccessibilityEventType::VIEW_LONG_CLICKED:
+      return ui::AX_EVENT_CLICKED;
+    case arc::mojom::AccessibilityEventType::VIEW_TEXT_CHANGED:
+      return ui::AX_EVENT_TEXT_CHANGED;
+    case arc::mojom::AccessibilityEventType::VIEW_TEXT_SELECTION_CHANGED:
+      return ui::AX_EVENT_TEXT_SELECTION_CHANGED;
+    case arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED:
+    case arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED:
+    case arc::mojom::AccessibilityEventType::WINDOW_CONTENT_CHANGED:
+    case arc::mojom::AccessibilityEventType::WINDOWS_CHANGED:
+      return ui::AX_EVENT_LAYOUT_COMPLETE;
+    case arc::mojom::AccessibilityEventType::VIEW_HOVER_ENTER:
+      return ui::AX_EVENT_HOVER;
+    case arc::mojom::AccessibilityEventType::ANNOUNCEMENT:
+      return ui::AX_EVENT_ALERT;
+    case arc::mojom::AccessibilityEventType::VIEW_SELECTED:
+    case arc::mojom::AccessibilityEventType::VIEW_HOVER_EXIT:
+    case arc::mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_START:
+    case arc::mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_END:
+    case arc::mojom::AccessibilityEventType::VIEW_SCROLLED:
+    case arc::mojom::AccessibilityEventType::
+        VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY:
+    case arc::mojom::AccessibilityEventType::GESTURE_DETECTION_START:
+    case arc::mojom::AccessibilityEventType::GESTURE_DETECTION_END:
+    case arc::mojom::AccessibilityEventType::TOUCH_INTERACTION_START:
+    case arc::mojom::AccessibilityEventType::TOUCH_INTERACTION_END:
+    case arc::mojom::AccessibilityEventType::VIEW_CONTEXT_CLICKED:
+    case arc::mojom::AccessibilityEventType::ASSIST_READING_CONTEXT:
+      return ui::AX_EVENT_CHILDREN_CHANGED;
+    default:
+      return ui::AX_EVENT_CHILDREN_CHANGED;
+  }
+  return ui::AX_EVENT_CHILDREN_CHANGED;
+}
+
+const gfx::Rect GetBounds(arc::mojom::AccessibilityNodeInfoData* node) {
+  exo::WMHelper* wmHelper = exo::WMHelper::GetInstance();
+  aura::Window* focused_window = wmHelper->GetFocusedWindow();
+  gfx::Rect bounds_in_screen = node->boundsInScreen;
+  if (focused_window) {
+    aura::Window* toplevel_window = focused_window->GetToplevelWindow();
+    return gfx::ScaleToEnclosingRect(
+        bounds_in_screen,
+        1.0f / toplevel_window->layer()->device_scale_factor());
+  }
+  return bounds_in_screen;
+}
+
+bool GetStringProperty(arc::mojom::AccessibilityNodeInfoData* node,
+                       arc::mojom::AccessibilityStringProperty prop,
+                       std::string* out_value) {
+  if (!node->stringProperties)
+    return false;
+
+  auto it = node->stringProperties->find(prop);
+  if (it == node->stringProperties->end())
+    return false;
+
+  *out_value = it->second;
+  return true;
+}
+
+}  // namespace
+
+namespace arc {
+
+AXTreeSourceArc::AXTreeSourceArc()
+    : tree_id_(ui::AXTreeIDRegistry::GetInstance()->CreateID()),
+      current_tree_serializer_(new AXTreeArcSerializer(this)),
+      root_id_(-1),
+      focused_node_id_(-1) {}
+
+AXTreeSourceArc::~AXTreeSourceArc() {
+  Reset();
+}
+
+void AXTreeSourceArc::NotifyAccessibilityEvent(
+    mojom::AccessibilityEventData* event_data) {
+  tree_map_.clear();
+  parent_map_.clear();
+  root_id_ = -1;
+  focused_node_id_ = -1;
+  for (size_t i = 0; i < event_data->nodeData.size(); ++i) {
+    if (!event_data->nodeData[i]->intListProperties)
+      continue;
+    auto it = event_data->nodeData[i]->intListProperties->find(
+        arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS);
+    if (it != event_data->nodeData[i]->intListProperties->end()) {
+      for (size_t j = 0; j < it->second.size(); ++j)
+        parent_map_[it->second[j]] = event_data->nodeData[i]->id;
+    }
+  }
+
+  for (size_t i = 0; i < event_data->nodeData.size(); ++i) {
+    int32_t id = event_data->nodeData[i]->id;
+    tree_map_[id] = event_data->nodeData[i].get();
+    if (parent_map_.find(id) == parent_map_.end()) {
+      CHECK_EQ(-1, root_id_) << "Duplicated root";
+      root_id_ = id;
+    }
+  }
+
+  ExtensionMsg_AccessibilityEventParams params;
+  params.event_type = ToAXEvent(event_data->eventType);
+  if (params.event_type == ui::AX_EVENT_FOCUS)
+    focused_node_id_ = params.id;
+  params.tree_id = tree_id_;
+  params.id = event_data->sourceId;
+
+  current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId),
+                                             &params.update);
+
+  extensions::AutomationEventRouter* router =
+      extensions::AutomationEventRouter::GetInstance();
+  router->DispatchAccessibilityEvent(params);
+}
+
+bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const {
+  data->tree_id = tree_id_;
+  if (focused_node_id_ >= 0)
+    data->focus_id = focused_node_id_;
+  return true;
+}
+
+mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetRoot() const {
+  mojom::AccessibilityNodeInfoData* root = GetFromId(root_id_);
+  return root;
+}
+
+mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetFromId(int32_t id) const {
+  auto it = tree_map_.find(id);
+  if (it == tree_map_.end())
+    return nullptr;
+  return it->second;
+}
+
+int32_t AXTreeSourceArc::GetId(mojom::AccessibilityNodeInfoData* node) const {
+  if (!node)
+    return -1;
+  return node->id;
+}
+
+void AXTreeSourceArc::GetChildren(
+    mojom::AccessibilityNodeInfoData* node,
+    std::vector<mojom::AccessibilityNodeInfoData*>* out_children) const {
+  if (!node || !node->intListProperties)
+    return;
+
+  auto it = node->intListProperties->find(
+      arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS);
+  if (it == node->intListProperties->end())
+    return;
+
+  for (size_t i = 0; i < it->second.size(); ++i) {
+    out_children->push_back(GetFromId(it->second[i]));
+  }
+}
+
+mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetParent(
+    mojom::AccessibilityNodeInfoData* node) const {
+  if (!node)
+    return nullptr;
+  auto it = parent_map_.find(node->id);
+  if (it != parent_map_.end())
+    return GetFromId(it->second);
+  return nullptr;
+}
+
+bool AXTreeSourceArc::IsValid(mojom::AccessibilityNodeInfoData* node) const {
+  return node;
+}
+
+bool AXTreeSourceArc::IsEqual(mojom::AccessibilityNodeInfoData* node1,
+                              mojom::AccessibilityNodeInfoData* node2) const {
+  if (!node1 || !node2)
+    return false;
+  return node1->id == node2->id;
+}
+
+mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const {
+  return nullptr;
+}
+
+void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node,
+                                    ui::AXNodeData* out_data) const {
+  if (!node)
+    return;
+  out_data->id = node->id;
+  out_data->state = 0;
+
+  using AXStringProperty = arc::mojom::AccessibilityStringProperty;
+  std::string text;
+  if (GetStringProperty(node, AXStringProperty::TEXT, &text))
+    out_data->SetName(text);
+  else if (GetStringProperty(node, AXStringProperty::CONTENT_DESCRIPTION,
+                             &text))
+    out_data->SetName(text);
+
+  int32_t id = node->id;
+  if (id == root_id_)
+    out_data->role = ui::AX_ROLE_ROOT_WEB_AREA;
+  else if (!text.empty())
+    out_data->role = ui::AX_ROLE_STATIC_TEXT;
+  else
+    out_data->role = ui::AX_ROLE_DIV;
+
+  const gfx::Rect bounds_in_screen = GetBounds(node);
+  out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(),
+                             bounds_in_screen.width(),
+                             bounds_in_screen.height());
+}
+
+void AXTreeSourceArc::Reset() {
+  tree_map_.clear();
+  parent_map_.clear();
+  current_tree_serializer_.reset(new AXTreeArcSerializer(this));
+  root_id_ = -1;
+  focused_node_id_ = -1;
+  extensions::AutomationEventRouter* router =
+      extensions::AutomationEventRouter::GetInstance();
+  router->DispatchTreeDestroyedEvent(tree_id_, nullptr);
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h
new file mode 100644
index 0000000..2ebde4c0
--- /dev/null
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h
@@ -0,0 +1,77 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "components/arc/common/accessibility_helper.mojom.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/ax_tree_serializer.h"
+#include "ui/accessibility/ax_tree_source.h"
+#include "ui/views/view.h"
+
+namespace arc {
+
+using AXTreeArcSerializer =
+    ui::AXTreeSerializer<mojom::AccessibilityNodeInfoData*,
+                         ui::AXNodeData,
+                         ui::AXTreeData>;
+
+// This class represents the accessibility tree from the focused ARC window.
+class AXTreeSourceArc
+    : public ui::AXTreeSource<mojom::AccessibilityNodeInfoData*,
+                              ui::AXNodeData,
+                              ui::AXTreeData> {
+ public:
+  AXTreeSourceArc();
+  ~AXTreeSourceArc() override;
+
+  // Notify automation of an accessibility event.
+  void NotifyAccessibilityEvent(mojom::AccessibilityEventData* event_data);
+
+  int32_t tree_id() const { return tree_id_; }
+
+ private:
+  // AXTreeSource overrides.
+  bool GetTreeData(ui::AXTreeData* data) const override;
+  mojom::AccessibilityNodeInfoData* GetRoot() const override;
+  mojom::AccessibilityNodeInfoData* GetFromId(int32_t id) const override;
+  int32_t GetId(mojom::AccessibilityNodeInfoData* node) const override;
+  void GetChildren(mojom::AccessibilityNodeInfoData* node,
+                   std::vector<mojom::AccessibilityNodeInfoData*>* out_children)
+      const override;
+  mojom::AccessibilityNodeInfoData* GetParent(
+      mojom::AccessibilityNodeInfoData* node) const override;
+  bool IsValid(mojom::AccessibilityNodeInfoData* node) const override;
+  bool IsEqual(mojom::AccessibilityNodeInfoData* node1,
+               mojom::AccessibilityNodeInfoData* node2) const override;
+  mojom::AccessibilityNodeInfoData* GetNull() const override;
+  void SerializeNode(mojom::AccessibilityNodeInfoData* node,
+                     ui::AXNodeData* out_data) const override;
+
+  // Resets tree state.
+  void Reset();
+
+  // The id of this tree.
+  int32_t tree_id_;
+
+  // Maps an AccessibilityNodeInfo to its tree data.
+  std::map<int32_t, mojom::AccessibilityNodeInfoData*> tree_map_;
+  std::map<int32_t, int32_t> parent_map_;
+  std::unique_ptr<AXTreeArcSerializer> current_tree_serializer_;
+  int32_t root_id_;
+  int32_t focused_node_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(AXTreeSourceArc);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
index 008a1c4..7a7799b 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/command_line.h"
 #include "base/gtest_prod_util.h"
 #include "base/json/json_writer.h"
 #include "base/values.h"
@@ -14,6 +15,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_switches.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
@@ -483,9 +485,14 @@
 }
 
 void ArcSettingsServiceImpl::SyncSpokenFeedbackEnabled() const {
-  SendBoolPrefSettingsBroadcast(
-      prefs::kAccessibilitySpokenFeedbackEnabled,
-      "org.chromium.arc.intent_helper.SET_SPOKEN_FEEDBACK_ENABLED");
+  std::string setting =
+      "org.chromium.arc.intent_helper.SET_SPOKEN_FEEDBACK_ENABLED";
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableChromeVoxArcSupport))
+    setting = "org.chromium.arc.intent_helper.SET_ACCESSIBILITY_HELPER_ENABLED";
+
+  SendBoolPrefSettingsBroadcast(prefs::kAccessibilitySpokenFeedbackEnabled,
+                                setting);
 }
 
 void ArcSettingsServiceImpl::SyncTimeZone() const {
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
index 07f63cf..90111f1 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -38,6 +38,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/auth_service.h"
 #include "google_apis/drive/drive_api_url_generator.h"
+#include "google_apis/drive/drive_switches.h"
 #include "storage/common/fileapi/file_system_info.h"
 #include "storage/common/fileapi/file_system_util.h"
 #include "url/gurl.h"
@@ -100,7 +101,8 @@
     DriveApiUrlGenerator url_generator(
         (GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
         (GURL(google_apis::DriveApiUrlGenerator::
-                  kBaseThumbnailUrlForProduction)));
+                  kBaseThumbnailUrlForProduction)),
+        google_apis::GetTeamDrivesIntegrationSwitch());
     properties->thumbnail_url.reset(new std::string(
         url_generator.GetThumbnailUrl(entry_proto.resource_id(),
                                       500 /* width */, 500 /* height */,
@@ -1114,7 +1116,8 @@
   DriveApiUrlGenerator url_generator(
       (GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction)),
       (GURL(
-          google_apis::DriveApiUrlGenerator::kBaseThumbnailUrlForProduction)));
+          google_apis::DriveApiUrlGenerator::kBaseThumbnailUrlForProduction)),
+      google_apis::GetTeamDrivesIntegrationSwitch());
   download_url_ = url_generator.GenerateDownloadFileUrl(entry->resource_id());
 
   ProfileOAuth2TokenService* oauth2_token_service =
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index 4be5cd47..8444d612 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -216,7 +216,8 @@
 }
 
 // After a guest login, we should get the OTR default profile.
-IN_PROC_BROWSER_TEST_F(LoginGuestTest, GuestIsOTR) {
+// Test is flaky https://crbug.com/693106
+IN_PROC_BROWSER_TEST_F(LoginGuestTest, DISABLED_GuestIsOTR) {
   Profile* profile = browser()->profile();
   EXPECT_TRUE(profile->IsOffTheRecord());
   // Ensure there's extension service for this profile.
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index 51be0782..bfe6fe8 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -543,7 +543,8 @@
 }
 
 // Tests that ContinueSessionRestore could be called multiple times.
-IN_PROC_BROWSER_TEST_F(OAuth2Test, OverlappingContinueSessionRestore) {
+// TODO(xiyuan): Re-enable when the test is no longer flaky crbug.com/496325
+IN_PROC_BROWSER_TEST_F(OAuth2Test, DISABLED_OverlappingContinueSessionRestore) {
   SetupGaiaServerForUnexpiredAccount();
   SimulateNetworkOnline();
 
diff --git a/chrome/browser/extensions/api/automation/OWNERS b/chrome/browser/extensions/api/automation/OWNERS
index 344aea38..e6cc90e 100644
--- a/chrome/browser/extensions/api/automation/OWNERS
+++ b/chrome/browser/extensions/api/automation/OWNERS
@@ -1,2 +1,4 @@
 aboxhall@chromium.org
 dtseng@chromium.org
+
+# COMPONENT: UI>Accessibility
diff --git a/chrome/browser/extensions/api/automation_internal/OWNERS b/chrome/browser/extensions/api/automation_internal/OWNERS
index 344aea38..e6cc90e 100644
--- a/chrome/browser/extensions/api/automation_internal/OWNERS
+++ b/chrome/browser/extensions/api/automation_internal/OWNERS
@@ -1,2 +1,4 @@
 aboxhall@chromium.org
 dtseng@chromium.org
+
+# COMPONENT: UI>Accessibility
diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc
index d86ceaf..d153c396 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc
+++ b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <utility>
 
@@ -109,6 +110,7 @@
 void AutomationEventRouter::DispatchTreeDestroyedEvent(
     int tree_id,
     content::BrowserContext* browser_context) {
+  browser_context = browser_context ? browser_context : active_profile_;
   std::unique_ptr<base::ListValue> args(
       api::automation_internal::OnAccessibilityTreeDestroyed::Create(tree_id));
   std::unique_ptr<Event> event(new Event(
diff --git a/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
index 3d372df..1ebdf8a 100644
--- a/chrome/browser/extensions/api/notifications/notifications_apitest.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
@@ -6,6 +6,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
@@ -189,7 +190,7 @@
 }  // namespace
 
 // http://crbug.com/691913
-#if defined(OS_LINUX) && !defined(NDEBUG)
+#if (defined(OS_LINUX) || defined(OS_WIN)) && !defined(NDEBUG)
 #define MAYBE_TestBasicUsage DISABLED_TestBasicUsage
 #else
 #define MAYBE_TestBasicUsage TestBasicUsage
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index ff86a0a..50aa5d44 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -60,81 +60,6 @@
          type == ExtensionInstallPrompt::REPAIR_PROMPT;
 }
 
-static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
-    IDS_EXTENSION_INSTALL_PROMPT_TITLE,
-    IDS_EXTENSION_INSTALL_PROMPT_TITLE,
-    0,  // Deprecated.
-    IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
-    IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
-    0,  // External installs use different strings for extensions/apps/themes.
-    IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
-    IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE,
-    IDS_EXTENSION_REMOTE_INSTALL_PROMPT_TITLE,
-    IDS_EXTENSION_REPAIR_PROMPT_TITLE,
-    IDS_EXTENSION_DELEGATED_INSTALL_PROMPT_TITLE,
-    0,  // Deprecated.
-};
-static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    // The "OK" button in the post install permissions dialog allows revoking
-    // file/device access, and is only shown if such permissions exist; see
-    // ShouldDisplayRevokeButton().
-    ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-    ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
-};
-static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
-    0,  // Regular installs use different strings for extensions/apps/themes.
-    0,  // Inline installs as well.
-    IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
-    IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
-    IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
-    0,  // External installs use different strings for extensions/apps/themes.
-    0,  // Different strings depending on the files and devices retained.
-    IDS_EXTENSION_PROMPT_LAUNCH_BUTTON,
-    0,  // Remote installs use different strings for extensions/apps.
-    0,  // Repairs use different strings for extensions/apps.
-    IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
-    IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
-};
-static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
-    IDS_CANCEL,
-    IDS_CANCEL,
-    IDS_CANCEL,
-    IDS_CANCEL,
-    IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
-    IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
-    IDS_CLOSE,
-    IDS_CANCEL,
-    IDS_CANCEL,
-    IDS_CANCEL,
-    IDS_CANCEL,
-    IDS_CANCEL,
-};
-static const int
-    kPermissionsHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
-        IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_CAN_ACCESS,
-        IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_CAN_ACCESS,
-        IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
-        IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
-};
-
 // Returns bitmap for the default icon with size equal to the default icon's
 // pixel size under maximal supported scale factor.
 SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
@@ -192,31 +117,27 @@
 // This should match the PromptType enum.
 std::string ExtensionInstallPrompt::PromptTypeToString(PromptType type) {
   switch (type) {
-    case ExtensionInstallPrompt::INSTALL_PROMPT:
+    case INSTALL_PROMPT:
       return "INSTALL_PROMPT";
-    case ExtensionInstallPrompt::INLINE_INSTALL_PROMPT:
+    case INLINE_INSTALL_PROMPT:
       return "INLINE_INSTALL_PROMPT";
-    case ExtensionInstallPrompt::RE_ENABLE_PROMPT:
+    case RE_ENABLE_PROMPT:
       return "RE_ENABLE_PROMPT";
-    case ExtensionInstallPrompt::PERMISSIONS_PROMPT:
+    case PERMISSIONS_PROMPT:
       return "PERMISSIONS_PROMPT";
-    case ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT:
+    case EXTERNAL_INSTALL_PROMPT:
       return "EXTERNAL_INSTALL_PROMPT";
-    case ExtensionInstallPrompt::POST_INSTALL_PERMISSIONS_PROMPT:
+    case POST_INSTALL_PERMISSIONS_PROMPT:
       return "POST_INSTALL_PERMISSIONS_PROMPT";
-    case ExtensionInstallPrompt::REMOTE_INSTALL_PROMPT:
+    case REMOTE_INSTALL_PROMPT:
       return "REMOTE_INSTALL_PROMPT";
-    case ExtensionInstallPrompt::REPAIR_PROMPT:
+    case REPAIR_PROMPT:
       return "REPAIR_PROMPT";
-    case ExtensionInstallPrompt::DELEGATED_PERMISSIONS_PROMPT:
+    case DELEGATED_PERMISSIONS_PROMPT:
       return "DELEGATED_PERMISSIONS_PROMPT";
-    case ExtensionInstallPrompt::LAUNCH_PROMPT_DEPRECATED:
-    case ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT_DEPRECATED:
-    case ExtensionInstallPrompt::DELEGATED_BUNDLE_PERMISSIONS_PROMPT_DEPRECATED:
+    case UNSET_PROMPT_TYPE:
+    case NUM_PROMPT_TYPES:
       NOTREACHED();
-      // fall through:
-    case ExtensionInstallPrompt::UNSET_PROMPT_TYPE:
-    case ExtensionInstallPrompt::NUM_PROMPT_TYPES:
       break;
   }
   return "OTHER";
@@ -231,6 +152,8 @@
       rating_count_(0),
       show_user_count_(false),
       has_webstore_data_(false) {
+  DCHECK_NE(type_, UNSET_PROMPT_TYPE);
+  DCHECK_NE(type_, NUM_PROMPT_TYPES);
 }
 
 ExtensionInstallPrompt::Prompt::~Prompt() {
@@ -300,88 +223,186 @@
 }
 
 base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
-  int id = kTitleIds[type_];
-  if (type_ == DELEGATED_PERMISSIONS_PROMPT) {
-    return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name()),
-                                      base::UTF8ToUTF16(delegated_username_));
+  int id = -1;
+  switch (type_) {
+    case INSTALL_PROMPT:
+    case INLINE_INSTALL_PROMPT:
+      id = IDS_EXTENSION_INSTALL_PROMPT_TITLE;
+      break;
+    case RE_ENABLE_PROMPT:
+      id = IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE;
+      break;
+    case PERMISSIONS_PROMPT:
+      id = IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE;
+      break;
+    case EXTERNAL_INSTALL_PROMPT:
+      if (extension_->is_app())
+        id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_APP;
+      else if (extension_->is_theme())
+        id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_THEME;
+      else
+        id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_EXTENSION;
+      break;
+    case POST_INSTALL_PERMISSIONS_PROMPT:
+      id = IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE;
+      break;
+    case REMOTE_INSTALL_PROMPT:
+      id = IDS_EXTENSION_REMOTE_INSTALL_PROMPT_TITLE;
+      break;
+    case REPAIR_PROMPT:
+      id = IDS_EXTENSION_REPAIR_PROMPT_TITLE;
+      break;
+    case DELEGATED_PERMISSIONS_PROMPT:
+      // Special case: need to include the delegated username.
+      return l10n_util::GetStringFUTF16(
+          IDS_EXTENSION_DELEGATED_INSTALL_PROMPT_TITLE,
+          base::UTF8ToUTF16(extension_->name()),
+          base::UTF8ToUTF16(delegated_username_));
+    case UNSET_PROMPT_TYPE:
+    case NUM_PROMPT_TYPES:
+      NOTREACHED();
   }
-  if (type_ == EXTERNAL_INSTALL_PROMPT) {
-    if (extension_->is_app())
-      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_APP;
-    else if (extension_->is_theme())
-      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_THEME;
-    else
-      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_EXTENSION;
-  }
+
   return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name()));
 }
 
 int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
-  if (type_ == POST_INSTALL_PERMISSIONS_PROMPT && ShouldDisplayRevokeButton()) {
-    return kButtons[type_] | ui::DIALOG_BUTTON_OK;
+  // The "OK" button in the post install permissions dialog allows revoking
+  // file/device access, and is only shown if such permissions exist; see
+  // ShouldDisplayRevokeButton().
+  if (type_ == POST_INSTALL_PERMISSIONS_PROMPT &&
+      !ShouldDisplayRevokeButton()) {
+    return ui::DIALOG_BUTTON_CANCEL;
   }
-
-  return kButtons[type_];
+  return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
 }
 
 base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
-  int id = kAcceptButtonIds[type_];
-
-  if (type_ == INSTALL_PROMPT || type_ == INLINE_INSTALL_PROMPT) {
-    if (extension_->is_app())
-      id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
-    else if (extension_->is_theme())
-      id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
-    else
-      id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
-  } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
-    if (extension_->is_app())
-      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
-    else if (extension_->is_theme())
-      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
-    else
-      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
-  } else if (type_ == POST_INSTALL_PERMISSIONS_PROMPT) {
-    if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
-      id =
-          IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON;
-    } else if (GetRetainedFileCount()) {
-      id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON;
-    } else if (GetRetainedDeviceCount()) {
-      id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON;
-    }
-    // If there are neither retained files nor devices, leave id 0 so there
-    // will be no "accept" button.
-  } else if (type_ == REMOTE_INSTALL_PROMPT) {
-    if (extension_->is_app())
-      id = IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_APP;
-    else
-      id = IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_EXTENSION;
-  } else if (type_ == REPAIR_PROMPT) {
-    if (extension_->is_app())
-      id = IDS_EXTENSION_PROMPT_REPAIR_BUTTON_APP;
-    else
-      id = IDS_EXTENSION_PROMPT_REPAIR_BUTTON_EXTENSION;
+  int id = -1;
+  switch (type_) {
+    case INSTALL_PROMPT:
+    case INLINE_INSTALL_PROMPT:
+      if (extension_->is_app())
+        id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
+      else if (extension_->is_theme())
+        id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
+      else
+        id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
+      break;
+    case RE_ENABLE_PROMPT:
+      id = IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON;
+      break;
+    case PERMISSIONS_PROMPT:
+      id = IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON;
+      break;
+    case EXTERNAL_INSTALL_PROMPT:
+      if (extension_->is_app())
+        id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
+      else if (extension_->is_theme())
+        id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
+      else
+        id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
+      break;
+    case POST_INSTALL_PERMISSIONS_PROMPT:
+      if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
+        id =
+            IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON;
+      } else if (GetRetainedFileCount()) {
+        id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON;
+      } else if (GetRetainedDeviceCount()) {
+        id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON;
+      }
+      // If there are neither retained files nor devices, leave id -1 so there
+      // will be no "accept" button.
+      break;
+    case REMOTE_INSTALL_PROMPT:
+      if (extension_->is_app())
+        id = IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_APP;
+      else
+        id = IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_EXTENSION;
+      break;
+    case REPAIR_PROMPT:
+      if (extension_->is_app())
+        id = IDS_EXTENSION_PROMPT_REPAIR_BUTTON_APP;
+      else
+        id = IDS_EXTENSION_PROMPT_REPAIR_BUTTON_EXTENSION;
+      break;
+    case DELEGATED_PERMISSIONS_PROMPT:
+      id = IDS_EXTENSION_PROMPT_INSTALL_BUTTON;
+      break;
+    case UNSET_PROMPT_TYPE:
+    case NUM_PROMPT_TYPES:
+      NOTREACHED();
   }
-  return id ? l10n_util::GetStringUTF16(id) : base::string16();
+
+  return id != -1 ? l10n_util::GetStringUTF16(id) : base::string16();
 }
 
 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
-  return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
+  int id = -1;
+  switch (type_) {
+    case INSTALL_PROMPT:
+    case INLINE_INSTALL_PROMPT:
+    case RE_ENABLE_PROMPT:
+    case REMOTE_INSTALL_PROMPT:
+    case REPAIR_PROMPT:
+    case DELEGATED_PERMISSIONS_PROMPT:
+      id = IDS_CANCEL;
+      break;
+    case PERMISSIONS_PROMPT:
+      id = IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON;
+      break;
+    case EXTERNAL_INSTALL_PROMPT:
+      id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON;
+      break;
+    case POST_INSTALL_PERMISSIONS_PROMPT:
+      id = IDS_CLOSE;
+      break;
+    case UNSET_PROMPT_TYPE:
+    case NUM_PROMPT_TYPES:
+      NOTREACHED();
+  }
+
+  return l10n_util::GetStringUTF16(id);
 }
 
 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
     PermissionsType permissions_type) const {
   switch (permissions_type) {
-    case REGULAR_PERMISSIONS:
-      return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
+    case REGULAR_PERMISSIONS: {
+      int id = -1;
+      switch (type_) {
+        case INSTALL_PROMPT:
+        case INLINE_INSTALL_PROMPT:
+        case EXTERNAL_INSTALL_PROMPT:
+        case REMOTE_INSTALL_PROMPT:
+        case DELEGATED_PERMISSIONS_PROMPT:
+          id = IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO;
+          break;
+        case RE_ENABLE_PROMPT:
+          id = IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO;
+          break;
+        case PERMISSIONS_PROMPT:
+          id = IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO;
+          break;
+        case POST_INSTALL_PERMISSIONS_PROMPT:
+        case REPAIR_PROMPT:
+          id = IDS_EXTENSION_PROMPT_CAN_ACCESS;
+          break;
+        case UNSET_PROMPT_TYPE:
+        case NUM_PROMPT_TYPES:
+          NOTREACHED();
+      }
+      return l10n_util::GetStringUTF16(id);
+    }
     case WITHHELD_PERMISSIONS:
       return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD);
     case ALL_PERMISSIONS:
-    default:
       NOTREACHED();
       return base::string16();
   }
+  NOTREACHED();
+  return base::string16();
 }
 
 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
@@ -785,24 +806,7 @@
     }
   }
 
-  switch (prompt_->type()) {
-    case PERMISSIONS_PROMPT:
-    case RE_ENABLE_PROMPT:
-    case INLINE_INSTALL_PROMPT:
-    case EXTERNAL_INSTALL_PROMPT:
-    case INSTALL_PROMPT:
-    case POST_INSTALL_PERMISSIONS_PROMPT:
-    case REMOTE_INSTALL_PROMPT:
-    case REPAIR_PROMPT:
-    case DELEGATED_PERMISSIONS_PROMPT: {
-      prompt_->set_extension(extension_);
-      break;
-    }
-    case LAUNCH_PROMPT_DEPRECATED:
-    default:
-      NOTREACHED() << "Unknown message";
-      return;
-  }
+  prompt_->set_extension(extension_);
   prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
 
   if (show_params_->WasParentDestroyed()) {
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index 20d0938..3079697 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -54,18 +54,18 @@
   enum PromptType {
     UNSET_PROMPT_TYPE = -1,
     INSTALL_PROMPT = 0,
-    INLINE_INSTALL_PROMPT,
-    BUNDLE_INSTALL_PROMPT_DEPRECATED,
-    RE_ENABLE_PROMPT,
-    PERMISSIONS_PROMPT,
-    EXTERNAL_INSTALL_PROMPT,
-    POST_INSTALL_PERMISSIONS_PROMPT,
-    LAUNCH_PROMPT_DEPRECATED,
-    REMOTE_INSTALL_PROMPT,
-    REPAIR_PROMPT,
-    DELEGATED_PERMISSIONS_PROMPT,
-    DELEGATED_BUNDLE_PERMISSIONS_PROMPT_DEPRECATED,
-    NUM_PROMPT_TYPES
+    INLINE_INSTALL_PROMPT = 1,
+    // BUNDLE_INSTALL_PROMPT_DEPRECATED = 2,
+    RE_ENABLE_PROMPT = 3,
+    PERMISSIONS_PROMPT = 4,
+    EXTERNAL_INSTALL_PROMPT = 5,
+    POST_INSTALL_PERMISSIONS_PROMPT = 6,
+    // LAUNCH_PROMPT_DEPRECATED = 7,
+    REMOTE_INSTALL_PROMPT = 8,
+    REPAIR_PROMPT = 9,
+    DELEGATED_PERMISSIONS_PROMPT = 10,
+    // DELEGATED_BUNDLE_PERMISSIONS_PROMPT_DEPRECATED = 11,
+    NUM_PROMPT_TYPES = 12,
   };
 
   // The last prompt type to display; only used for testing.
@@ -109,7 +109,6 @@
                          int rating_count);
 
     PromptType type() const { return type_; }
-    void set_type(PromptType type) { type_ = type; }
 
     // Getters for UI element labels.
     base::string16 GetDialogTitle() const;
@@ -199,7 +198,7 @@
 
     bool ShouldDisplayRevokeFilesButton() const;
 
-    PromptType type_;
+    const PromptType type_;
 
     // Permissions that are being requested (may not be all of an extension's
     // permissions if only additional ones are being requested)
diff --git a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
index 0a46686..ba3ad736 100644
--- a/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_apprtc_browsertest.cc
@@ -52,8 +52,11 @@
 
     // The video playback will not work without a GPU, so force its use here.
     command_line->AppendSwitch(switches::kUseGpuInTests);
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kUseFakeDeviceForMediaStream);
+    // This test fails on some Mac bots if no default devices are specified on
+    // the command line.
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kUseFakeDeviceForMediaStream,
+        "audio-input-default-id=default,video-input-default-id=default");
   }
 
   void TearDown() override {
diff --git a/chrome/browser/ntp_snippets/content_suggestions_notifier_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_notifier_service_factory.cc
index 408debd..57ed436 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_notifier_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_notifier_service_factory.cc
@@ -16,6 +16,8 @@
 #include "chrome/browser/android/ntp/content_suggestions_notifier_service.h"
 #endif
 
+using params::ntp_snippets::kNotificationsFeature;
+
 ContentSuggestionsNotifierServiceFactory*
 ContentSuggestionsNotifierServiceFactory::GetInstance() {
   return base::Singleton<ContentSuggestionsNotifierServiceFactory>::get();
@@ -57,7 +59,7 @@
 KeyedService* ContentSuggestionsNotifierServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
 #if defined(OS_ANDROID)
-  if (base::FeatureList::IsEnabled(kContentSuggestionsNotificationsFeature)) {
+  if (base::FeatureList::IsEnabled(kNotificationsFeature)) {
     Profile* profile = Profile::FromBrowserContext(context);
     ntp_snippets::ContentSuggestionsService* suggestions =
         ContentSuggestionsServiceFactory::GetForProfile(profile);
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_features.cc b/chrome/browser/ntp_snippets/ntp_snippets_features.cc
index 643fcea..5af0a6f 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_features.cc
+++ b/chrome/browser/ntp_snippets/ntp_snippets_features.cc
@@ -4,16 +4,18 @@
 
 #include "chrome/browser/ntp_snippets/ntp_snippets_features.h"
 
-const base::Feature kContentSuggestionsNotificationsFeature = {
-    "ContentSuggestionsNotifications", base::FEATURE_DISABLED_BY_DEFAULT};
+namespace params {
+namespace ntp_snippets {
 
-const char kContentSuggestionsNotificationsAlwaysNotifyParam[] =
-    "always_notify";
-const char kContentSuggestionsNotificationsUseSnippetAsTextParam[] =
-    "use_snippet_as_text";
-const char
-    kContentSuggestionsNotificationsKeepNotificationWhenFrontmostParam[] =
-        "keep_notification_when_frontmost";
-const char kContentSuggestionsNotificationsDailyLimit[] = "daily_limit";
-const char kContentSuggestionsNotificationsIgnoredLimitParam[] =
-    "ignored_limit";
+const base::Feature kNotificationsFeature = {"ContentSuggestionsNotifications",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kNotificationsAlwaysNotifyParam[] = "always_notify";
+const char kNotificationsUseSnippetAsTextParam[] = "use_snippet_as_text";
+const char kNotificationsKeepWhenFrontmostParam[] =
+    "keep_notification_when_frontmost";
+const char kNotificationsDailyLimit[] = "daily_limit";
+const char kNotificationsIgnoredLimitParam[] = "ignored_limit";
+
+}  // namespace ntp_snippets
+}  // namespace params
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_features.h b/chrome/browser/ntp_snippets/ntp_snippets_features.h
index 1d84bc5c..867077b7 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_features.h
+++ b/chrome/browser/ntp_snippets/ntp_snippets_features.h
@@ -7,29 +7,34 @@
 
 #include "base/feature_list.h"
 
+namespace params {
+namespace ntp_snippets {
+
 // Enables and configures notifications for content suggestions.
-extern const base::Feature kContentSuggestionsNotificationsFeature;
+extern const base::Feature kNotificationsFeature;
 
 // "false": use server signals to decide whether to send a notification
 // "true": always send a notification when we receive ARTICLES suggestions
-extern const char kContentSuggestionsNotificationsAlwaysNotifyParam[];
+extern const char kNotificationsAlwaysNotifyParam[];
 
 // "true": use article's snippet as notification's text
 // "false": use article's publisher as notification's text
-extern const char kContentSuggestionsNotificationsUseSnippetAsTextParam[];
+extern const char kNotificationsUseSnippetAsTextParam[];
 
 // "true": when Chrome becomes frontmost, leave notifications open.
 // "false": automatically dismiss notification when Chrome becomes frontmost.
-extern const char
-    kContentSuggestionsNotificationsKeepNotificationWhenFrontmostParam[];
+extern const char kNotificationsKeepWhenFrontmostParam[];
 
 // An integer. The maximum number of notifications that will be shown in 1 day.
-extern const char kContentSuggestionsNotificationsDailyLimit[];
-constexpr int kContentSuggestionsNotificationsDefaultDailyLimit = 1;
+extern const char kNotificationsDailyLimit[];
+constexpr int kNotificationsDefaultDailyLimit = 1;
 
 // An integer. The number of notifications that can be ignored. If the user
 // ignores this many notifications or more, we stop sending them.
-extern const char kContentSuggestionsNotificationsIgnoredLimitParam[];
-constexpr int kContentSuggestionsNotificationsIgnoredDefaultLimit = 3;
+extern const char kNotificationsIgnoredLimitParam[];
+constexpr int kNotificationsIgnoredDefaultLimit = 3;
+
+}  // namespace ntp_snippets
+}  // namespace params
 
 #endif  // CHROME_BROWSER_NTP_SNIPPETS_NTP_SNIPPETS_FEATURES_H_
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index a2e34478..d58dc78 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -82,7 +82,7 @@
 
 MetricsWebContentsObserver::~MetricsWebContentsObserver() {
   // TODO(csharrison): Use a more user-initiated signal for CLOSE.
-  NotifyAbortAllLoads(ABORT_CLOSE, UserInitiatedInfo::NotUserInitiated());
+  NotifyPageEndAllLoads(END_CLOSE, UserInitiatedInfo::NotUserInitiated());
 }
 
 void MetricsWebContentsObserver::RegisterInputEventObserver(
@@ -293,8 +293,8 @@
     // Notify other loads that they may have been aborted by this committed
     // load. is_certainly_browser_timestamp is set to false because
     // NavigationStart() could be set in either the renderer or browser process.
-    NotifyAbortAllLoadsWithTimestamp(
-        AbortTypeForPageTransition(navigation_handle->GetPageTransition()),
+    NotifyPageEndAllLoadsWithTimestamp(
+        EndReasonForPageTransition(navigation_handle->GetPageTransition()),
         user_initiated_info, navigation_handle->NavigationStart(), false);
 
     if (should_track) {
@@ -314,21 +314,28 @@
 void MetricsWebContentsObserver::HandleFailedNavigationForTrackedLoad(
     content::NavigationHandle* navigation_handle,
     std::unique_ptr<PageLoadTracker> tracker) {
-  tracker->FailedProvisionalLoad(navigation_handle);
+  const base::TimeTicks now = base::TimeTicks::Now();
+  tracker->FailedProvisionalLoad(navigation_handle, now);
 
-  net::Error error = navigation_handle->GetNetErrorCode();
+  const net::Error error = navigation_handle->GetNetErrorCode();
 
   // net::OK: This case occurs when the NavigationHandle finishes and reports
   // !HasCommitted(), but reports no net::Error. This should not occur
   // pre-PlzNavigate, but afterwards it should represent the navigation stopped
   // by the user before it was ready to commit.
-  // net::ERR_ABORTED: An aborted provisional load has error
-  // net::ERR_ABORTED.
-  if ((error == net::OK) || (error == net::ERR_ABORTED)) {
-    tracker->NotifyAbort(ABORT_OTHER, UserInitiatedInfo::NotUserInitiated(),
-                         base::TimeTicks::Now(), true);
+  // net::ERR_ABORTED: An aborted provisional load has error net::ERR_ABORTED.
+  const bool is_aborted_provisional_load =
+      error == net::OK || error == net::ERR_ABORTED;
+
+  // If is_aborted_provisional_load, the page end reason is not yet known, and
+  // will be updated as additional information is available from subsequent
+  // navigations.
+  tracker->NotifyPageEnd(
+      is_aborted_provisional_load ? END_OTHER : END_PROVISIONAL_LOAD_FAILED,
+      UserInitiatedInfo::NotUserInitiated(), now, true);
+
+  if (is_aborted_provisional_load)
     aborted_provisional_loads_.push_back(std::move(tracker));
-  }
 }
 
 void MetricsWebContentsObserver::HandleCommittedNavigationForTrackedLoad(
@@ -350,7 +357,7 @@
 
 void MetricsWebContentsObserver::NavigationStopped() {
   // TODO(csharrison): Use a more user-initiated signal for STOP.
-  NotifyAbortAllLoads(ABORT_STOP, UserInitiatedInfo::NotUserInitiated());
+  NotifyPageEndAllLoads(END_STOP, UserInitiatedInfo::NotUserInitiated());
 }
 
 void MetricsWebContentsObserver::OnInputEvent(
@@ -414,9 +421,7 @@
 
 // This will occur when the process for the main RenderFrameHost exits, either
 // normally or from a crash. We eagerly log data from the last committed load if
-// we have one. Don't notify aborts here because this is probably not user
-// initiated. If it is (e.g. browser shutdown), other code paths will take care
-// of notifying.
+// we have one.
 void MetricsWebContentsObserver::RenderProcessGone(
     base::TerminationStatus status) {
   // Other code paths will be run for normal renderer shutdown. Note that we
@@ -426,6 +431,16 @@
     return;
   }
 
+  // RenderProcessGone is associated with the render frame host for the
+  // currently committed load. We don't know if the pending navs or aborted
+  // pending navs are associated w/ the render process that died, so we can't be
+  // sure the info should propagate to them.
+  if (committed_load_) {
+    committed_load_->NotifyPageEnd(END_RENDER_PROCESS_GONE,
+                                   UserInitiatedInfo::NotUserInitiated(),
+                                   base::TimeTicks::Now(), true);
+  }
+
   // If this is a crash, eagerly log the aborted provisional loads and the
   // committed load. |provisional_loads_| don't need to be destroyed here
   // because their lifetime is tied to the NavigationHandle.
@@ -433,30 +448,30 @@
   aborted_provisional_loads_.clear();
 }
 
-void MetricsWebContentsObserver::NotifyAbortAllLoads(
-    UserAbortType abort_type,
+void MetricsWebContentsObserver::NotifyPageEndAllLoads(
+    PageEndReason page_end_reason,
     UserInitiatedInfo user_initiated_info) {
-  NotifyAbortAllLoadsWithTimestamp(abort_type, user_initiated_info,
-                                   base::TimeTicks::Now(), true);
+  NotifyPageEndAllLoadsWithTimestamp(page_end_reason, user_initiated_info,
+                                     base::TimeTicks::Now(), true);
 }
 
-void MetricsWebContentsObserver::NotifyAbortAllLoadsWithTimestamp(
-    UserAbortType abort_type,
+void MetricsWebContentsObserver::NotifyPageEndAllLoadsWithTimestamp(
+    PageEndReason page_end_reason,
     UserInitiatedInfo user_initiated_info,
     base::TimeTicks timestamp,
     bool is_certainly_browser_timestamp) {
   if (committed_load_) {
-    committed_load_->NotifyAbort(abort_type, user_initiated_info, timestamp,
-                                 is_certainly_browser_timestamp);
+    committed_load_->NotifyPageEnd(page_end_reason, user_initiated_info,
+                                   timestamp, is_certainly_browser_timestamp);
   }
   for (const auto& kv : provisional_loads_) {
-    kv.second->NotifyAbort(abort_type, user_initiated_info, timestamp,
-                           is_certainly_browser_timestamp);
+    kv.second->NotifyPageEnd(page_end_reason, user_initiated_info, timestamp,
+                             is_certainly_browser_timestamp);
   }
   for (const auto& tracker : aborted_provisional_loads_) {
     if (tracker->IsLikelyProvisionalAbort(timestamp)) {
-      tracker->UpdateAbort(abort_type, user_initiated_info, timestamp,
-                           is_certainly_browser_timestamp);
+      tracker->UpdatePageEnd(page_end_reason, user_initiated_info, timestamp,
+                             is_certainly_browser_timestamp);
     }
   }
   aborted_provisional_loads_.clear();
@@ -480,8 +495,8 @@
 
   base::TimeTicks timestamp = new_navigation->NavigationStart();
   if (last_aborted_load->IsLikelyProvisionalAbort(timestamp)) {
-    last_aborted_load->UpdateAbort(
-        AbortTypeForPageTransition(new_navigation->GetPageTransition()),
+    last_aborted_load->UpdatePageEnd(
+        EndReasonForPageTransition(new_navigation->GetPageTransition()),
         user_initiated_info, timestamp, false);
   }
 
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
index fe55a24..681e7ce 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
@@ -111,12 +111,12 @@
 
   // Notify all loads, provisional and committed, that we performed an action
   // that might abort them.
-  void NotifyAbortAllLoads(UserAbortType abort_type,
-                           UserInitiatedInfo user_initiated_info);
-  void NotifyAbortAllLoadsWithTimestamp(UserAbortType abort_type,
-                                        UserInitiatedInfo user_initiated_info,
-                                        base::TimeTicks timestamp,
-                                        bool is_certainly_browser_timestamp);
+  void NotifyPageEndAllLoads(PageEndReason page_end_reason,
+                             UserInitiatedInfo user_initiated_info);
+  void NotifyPageEndAllLoadsWithTimestamp(PageEndReason page_end_reason,
+                                          UserInitiatedInfo user_initiated_info,
+                                          base::TimeTicks timestamp,
+                                          bool is_certainly_browser_timestamp);
 
   // Register / Unregister input event callback to given RenderViewHost
   void RegisterInputEventObserver(content::RenderViewHost* host);
diff --git a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
index bee219e8..aaa848f 100644
--- a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
@@ -6,12 +6,10 @@
 
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 
-using page_load_metrics::UserAbortType;
+using page_load_metrics::PageAbortReason;
 
 namespace internal {
 
-const char kHistogramAbortClientRedirectBeforeCommit[] =
-    "PageLoad.Experimental.AbortTiming.ClientRedirect.BeforeCommit";
 const char kHistogramAbortForwardBackBeforeCommit[] =
     "PageLoad.Experimental.AbortTiming.ForwardBackNavigation.BeforeCommit";
 const char kHistogramAbortReloadBeforeCommit[] =
@@ -27,8 +25,6 @@
 const char kHistogramAbortOtherBeforeCommit[] =
     "PageLoad.Experimental.AbortTiming.Other.BeforeCommit";
 
-const char kHistogramAbortClientRedirectBeforePaint[] =
-    "PageLoad.Experimental.AbortTiming.ClientRedirect.AfterCommit.BeforePaint";
 const char kHistogramAbortForwardBackBeforePaint[] =
     "PageLoad.Experimental.AbortTiming.ForwardBackNavigation.AfterCommit."
     "BeforePaint";
@@ -43,8 +39,6 @@
 const char kHistogramAbortBackgroundBeforePaint[] =
     "PageLoad.Experimental.AbortTiming.Background.AfterCommit.BeforePaint";
 
-const char kHistogramAbortClientRedirectDuringParse[] =
-    "PageLoad.Experimental.AbortTiming.ClientRedirect.DuringParse";
 const char kHistogramAbortForwardBackDuringParse[] =
     "PageLoad.Experimental.AbortTiming.ForwardBackNavigation.DuringParse";
 const char kHistogramAbortReloadDuringParse[] =
@@ -63,98 +57,91 @@
 namespace {
 
 void RecordAbortBeforeCommit(
-    UserAbortType abort_type,
-    page_load_metrics::UserInitiatedInfo user_initiated_info,
-    base::TimeDelta time_to_abort) {
-  switch (abort_type) {
-    case UserAbortType::ABORT_RELOAD:
+    const page_load_metrics::PageAbortInfo& abort_info) {
+  switch (abort_info.reason) {
+    case PageAbortReason::ABORT_RELOAD:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforeCommit,
-                          time_to_abort);
-      if (user_initiated_info.user_gesture) {
+                          abort_info.time_to_abort);
+      if (abort_info.user_initiated_info.user_gesture) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
             "UserGesture",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.user_input_event) {
+      if (abort_info.user_initiated_info.user_input_event) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
             "UserInputEvent",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.browser_initiated) {
+      if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
             "BrowserInitiated",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
       return;
-    case UserAbortType::ABORT_FORWARD_BACK:
+    case PageAbortReason::ABORT_FORWARD_BACK:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforeCommit,
-                          time_to_abort);
-      if (user_initiated_info.user_gesture) {
+                          abort_info.time_to_abort);
+      if (abort_info.user_initiated_info.user_gesture) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
             "BeforeCommit.UserGesture",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.user_input_event) {
+      if (abort_info.user_initiated_info.user_input_event) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
             "BeforeCommit.UserInputEvent",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.browser_initiated) {
+      if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
             "BeforeCommit.BrowserInitiated",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
       return;
-    case UserAbortType::ABORT_CLIENT_REDIRECT:
-      PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortClientRedirectBeforeCommit,
-                          time_to_abort);
-      return;
-    case UserAbortType::ABORT_NEW_NAVIGATION:
+    case PageAbortReason::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforeCommit,
-                          time_to_abort);
-      if (user_initiated_info.user_gesture) {
+                          abort_info.time_to_abort);
+      if (abort_info.user_initiated_info.user_gesture) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
             "UserGesture",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.user_input_event) {
+      if (abort_info.user_initiated_info.user_input_event) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
             "UserInputEvent",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.browser_initiated) {
+      if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
             "BrowserInitiated",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
       return;
-    case UserAbortType::ABORT_STOP:
+    case PageAbortReason::ABORT_STOP:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_CLOSE:
+    case PageAbortReason::ABORT_CLOSE:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_BACKGROUND:
+    case PageAbortReason::ABORT_BACKGROUND:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortBackgroundBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_OTHER:
+    case PageAbortReason::ABORT_OTHER:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortOtherBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_NONE:
-    case UserAbortType::ABORT_LAST_ENTRY:
+    case PageAbortReason::ABORT_NONE:
       NOTREACHED();
       return;
   }
@@ -162,155 +149,142 @@
 }
 
 void RecordAbortAfterCommitBeforePaint(
-    UserAbortType abort_type,
-    page_load_metrics::UserInitiatedInfo user_initiated_info,
-    base::TimeDelta time_to_abort) {
-  switch (abort_type) {
-    case UserAbortType::ABORT_RELOAD:
+    const page_load_metrics::PageAbortInfo& abort_info) {
+  switch (abort_info.reason) {
+    case PageAbortReason::ABORT_RELOAD:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforePaint,
-                          time_to_abort);
-      if (user_initiated_info.user_gesture) {
+                          abort_info.time_to_abort);
+      if (abort_info.user_initiated_info.user_gesture) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
             "UserGesture",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.user_input_event) {
+      if (abort_info.user_initiated_info.user_input_event) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
             "UserInputEvent",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.browser_initiated) {
+      if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
             "BrowserInitiated",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
       return;
-    case UserAbortType::ABORT_FORWARD_BACK:
+    case PageAbortReason::ABORT_FORWARD_BACK:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforePaint,
-                          time_to_abort);
-      if (user_initiated_info.user_gesture) {
+                          abort_info.time_to_abort);
+      if (abort_info.user_initiated_info.user_gesture) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
             "AfterCommit.BeforePaint.UserGesture",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.user_input_event) {
+      if (abort_info.user_initiated_info.user_input_event) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
             "AfterCommit.BeforePaint.UserInputEvent",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.browser_initiated) {
+      if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
             "AfterCommit.BeforePaint.BrowserInitiated",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
       return;
-    case UserAbortType::ABORT_CLIENT_REDIRECT:
-      PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortClientRedirectBeforePaint,
-                          time_to_abort);
-      return;
-    case UserAbortType::ABORT_NEW_NAVIGATION:
+    case PageAbortReason::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforePaint,
-                          time_to_abort);
-      if (user_initiated_info.user_gesture) {
+                          abort_info.time_to_abort);
+      if (abort_info.user_initiated_info.user_gesture) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
             "BeforePaint.UserGesture",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.user_input_event) {
+      if (abort_info.user_initiated_info.user_input_event) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
             "BeforePaint.UserInputEvent",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
-      if (user_initiated_info.browser_initiated) {
+      if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
             "BeforePaint.BrowserInitiated",
-            time_to_abort);
+            abort_info.time_to_abort);
       }
       return;
-    case UserAbortType::ABORT_STOP:
+    case PageAbortReason::ABORT_STOP:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforePaint,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_CLOSE:
+    case PageAbortReason::ABORT_CLOSE:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforePaint,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_BACKGROUND:
+    case PageAbortReason::ABORT_BACKGROUND:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortBackgroundBeforePaint,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_OTHER:
-      NOTREACHED() << "Received UserAbortType::ABORT_OTHER for committed load.";
+    case PageAbortReason::ABORT_OTHER:
+      NOTREACHED()
+          << "Received PageAbortReason::ABORT_OTHER for committed load.";
       return;
-    case UserAbortType::ABORT_NONE:
-    case UserAbortType::ABORT_LAST_ENTRY:
+    case PageAbortReason::ABORT_NONE:
       NOTREACHED();
       return;
   }
   NOTREACHED();
 }
 
-void RecordAbortDuringParse(UserAbortType abort_type,
-                            base::TimeDelta time_to_abort) {
-  switch (abort_type) {
-    case UserAbortType::ABORT_RELOAD:
+void RecordAbortDuringParse(
+    const page_load_metrics::PageAbortInfo& abort_info) {
+  switch (abort_info.reason) {
+    case PageAbortReason::ABORT_RELOAD:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadDuringParse,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_FORWARD_BACK:
+    case PageAbortReason::ABORT_FORWARD_BACK:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackDuringParse,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_CLIENT_REDIRECT:
-      PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortClientRedirectDuringParse,
-                          time_to_abort);
-      return;
-    case UserAbortType::ABORT_NEW_NAVIGATION:
+    case PageAbortReason::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationDuringParse,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_STOP:
+    case PageAbortReason::ABORT_STOP:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopDuringParse,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_CLOSE:
+    case PageAbortReason::ABORT_CLOSE:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseDuringParse,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_BACKGROUND:
+    case PageAbortReason::ABORT_BACKGROUND:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortBackgroundDuringParse,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       return;
-    case UserAbortType::ABORT_OTHER:
-      NOTREACHED() << "Received UserAbortType::ABORT_OTHER for committed load.";
+    case PageAbortReason::ABORT_OTHER:
+      NOTREACHED()
+          << "Received PageAbortReason::ABORT_OTHER for committed load.";
       return;
-    case UserAbortType::ABORT_NONE:
-    case UserAbortType::ABORT_LAST_ENTRY:
+    case PageAbortReason::ABORT_NONE:
       NOTREACHED();
       return;
   }
   NOTREACHED();
 }
 
-bool ShouldTrackMetrics(
-    const page_load_metrics::PageLoadExtraInfo& extra_info) {
-  UserAbortType abort_type = extra_info.abort_type;
-  if (abort_type == UserAbortType::ABORT_NONE)
+bool ShouldTrackMetrics(const page_load_metrics::PageLoadExtraInfo& extra_info,
+                        const page_load_metrics::PageAbortInfo& abort_info) {
+  if (abort_info.reason == PageAbortReason::ABORT_NONE)
     return false;
 
-  DCHECK(extra_info.time_to_abort);
-
   // Don't log abort times if the page was backgrounded before the abort event.
-  if (!WasStartedInForegroundOptionalEventInForeground(extra_info.time_to_abort,
+  if (!WasStartedInForegroundOptionalEventInForeground(abort_info.time_to_abort,
                                                        extra_info))
     return false;
 
@@ -324,7 +298,8 @@
 void AbortsPageLoadMetricsObserver::OnComplete(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& extra_info) {
-  if (!ShouldTrackMetrics(extra_info))
+  page_load_metrics::PageAbortInfo abort_info = GetPageAbortInfo(extra_info);
+  if (!ShouldTrackMetrics(extra_info, abort_info))
     return;
 
   // If we did not receive any timing IPCs from the render process, we can't
@@ -337,25 +312,21 @@
   if (timing.IsEmpty())
     return;
 
-  const base::TimeDelta& time_to_abort = extra_info.time_to_abort.value();
-  if (timing.parse_start && time_to_abort >= timing.parse_start &&
-      (!timing.parse_stop || timing.parse_stop >= time_to_abort)) {
-    RecordAbortDuringParse(extra_info.abort_type, time_to_abort);
+  if (timing.parse_start && abort_info.time_to_abort >= timing.parse_start &&
+      (!timing.parse_stop || timing.parse_stop >= abort_info.time_to_abort)) {
+    RecordAbortDuringParse(abort_info);
   }
-  if (!timing.first_paint || timing.first_paint >= time_to_abort) {
-    RecordAbortAfterCommitBeforePaint(extra_info.abort_type,
-                                      extra_info.abort_user_initiated_info,
-                                      time_to_abort);
+  if (!timing.first_paint || timing.first_paint >= abort_info.time_to_abort) {
+    RecordAbortAfterCommitBeforePaint(abort_info);
   }
 }
 
 void AbortsPageLoadMetricsObserver::OnFailedProvisionalLoad(
     const page_load_metrics::FailedProvisionalLoadInfo& failed_load_info,
     const page_load_metrics::PageLoadExtraInfo& extra_info) {
-  if (!ShouldTrackMetrics(extra_info))
+  page_load_metrics::PageAbortInfo abort_info = GetPageAbortInfo(extra_info);
+  if (!ShouldTrackMetrics(extra_info, abort_info))
     return;
 
-  RecordAbortBeforeCommit(extra_info.abort_type,
-                          extra_info.abort_user_initiated_info,
-                          extra_info.time_to_abort.value());
+  RecordAbortBeforeCommit(abort_info);
 }
diff --git a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h
index 56b11fd..f261dc6 100644
--- a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h
@@ -13,7 +13,6 @@
 extern const char kHistogramAbortForwardBackBeforeCommit[];
 extern const char kHistogramAbortReloadBeforeCommit[];
 extern const char kHistogramAbortNewNavigationBeforeCommit[];
-extern const char kHistogramAbortClientRedirectBeforeCommit[];
 extern const char kHistogramAbortStopBeforeCommit[];
 extern const char kHistogramAbortCloseBeforeCommit[];
 extern const char kHistogramAbortBackgroundBeforeCommit[];
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
index 28bf13d..14d1318 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -157,6 +157,21 @@
     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
     "NewNavigation";
 
+const char kHistogramPageTimingPageEnd[] =
+    "PageLoad.Experimental.PageTiming.NavigationToPageEnd";
+const char kHistogramPageTimingFirstPaintToPageEnd[] =
+    "PageLoad.Experimental.PageTiming.FirstPaintToPageEnd";
+
+const char kHistogramPageTimingPageEndNoEndTime[] =
+    "PageLoad.Experimental.PageTiming.NavigationToPageEnd.NoEndTime";
+const char kHistogramPageTimingFirstPaintToPageEndNoEndTime[] =
+    "PageLoad.Experimental.PageTiming.FirstPaintToPageEnd.NoEndTime";
+
+const char kHistogramPageTimingFirstBackground[] =
+    "PageLoad.Experimental.PageTiming.NavigationToFirstBackground";
+const char kHistogramPageTimingFirstPaintToFirstBackground[] =
+    "PageLoad.Experimental.PageTiming.FirstPaintToFirstBackground";
+
 const char kHistogramLoadTypeParseStartReload[] =
     "PageLoad.ParseTiming.NavigationToParseStart.LoadType.Reload";
 const char kHistogramLoadTypeParseStartForwardBack[] =
@@ -169,10 +184,10 @@
     "PageLoad.ParseTiming.NavigationToParseStart.LoadType.NewNavigation";
 
 const char kHistogramFirstForeground[] =
-    "PageLoad.Timing2.NavigationToFirstForeground";
+    "PageLoad.PageTiming.NavigationToFirstForeground";
 
 const char kHistogramFailedProvisionalLoad[] =
-    "PageLoad.Timing2.NavigationToFailedProvisionalLoad";
+    "PageLoad.PageTiming.NavigationToFailedProvisionalLoad";
 
 const char kHistogramForegroundToFirstPaint[] =
     "PageLoad.PaintTiming.ForegroundToFirstPaint";
@@ -632,10 +647,9 @@
     const page_load_metrics::PageLoadExtraInfo& info) {
   // Log time to first foreground / time to first background. Log counts that we
   // started a relevant page load in the foreground / background.
-  if (!info.started_in_foreground) {
-    if (info.first_foreground_time)
-      PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstForeground,
-                          info.first_foreground_time.value());
+  if (!info.started_in_foreground && info.first_foreground_time) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstForeground,
+                        info.first_foreground_time.value());
   }
 
   if (timing.first_paint && !timing.first_meaningful_paint) {
@@ -668,6 +682,39 @@
                           timing.first_meaningful_paint.value());
     }
   }
+
+  if (!info.started_in_foreground)
+    return;
+
+  if (info.first_background_time) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramPageTimingFirstBackground,
+                        info.first_background_time.value());
+    if (timing.first_paint &&
+        timing.first_paint <= info.first_background_time) {
+      PAGE_LOAD_HISTOGRAM(
+          internal::kHistogramPageTimingFirstPaintToFirstBackground,
+          info.first_background_time.value() - timing.first_paint.value());
+    }
+  } else if (info.page_end_time) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramPageTimingPageEnd,
+                        info.page_end_time.value());
+    if (timing.first_paint && timing.first_paint <= info.page_end_time) {
+      PAGE_LOAD_HISTOGRAM(
+          internal::kHistogramPageTimingFirstPaintToPageEnd,
+          info.page_end_time.value() - timing.first_paint.value());
+    }
+  } else {
+    // If we terminate via FlushMetricsOnAppEnterBackground, we may have neither
+    // a first_background_time nor a page_end_time.
+    base::TimeDelta end_time = base::TimeTicks::Now() - navigation_start_;
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramPageTimingPageEndNoEndTime,
+                        end_time);
+    if (timing.first_paint && timing.first_paint <= end_time) {
+      PAGE_LOAD_HISTOGRAM(
+          internal::kHistogramPageTimingFirstPaintToPageEndNoEndTime,
+          end_time - timing.first_paint.value());
+    }
+  }
 }
 
 void CorePageLoadMetricsObserver::RecordByteAndResourceHistograms(
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
index ee4a86f..dd31e12 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -41,6 +41,9 @@
 
 extern const char kHistogramFailedProvisionalLoad[];
 
+extern const char kHistogramPageTimingPageEnd[];
+extern const char kHistogramPageTimingFirstBackground[];
+
 extern const char kRapporMetricsNameCoarseTiming[];
 extern const char kHistogramFirstMeaningfulPaintStatus[];
 
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
index e8a7178..7212172 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -104,6 +104,10 @@
       internal::kHistogramParseBlockedOnScriptExecution,
       parse_script_exec_duration.InMilliseconds(), 1);
   histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+
+  histogram_tester().ExpectTotalCount(internal::kHistogramPageTimingPageEnd, 1);
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramPageTimingFirstBackground, 0);
 }
 
 TEST_F(CorePageLoadMetricsObserverTest, MultipleMetricsAfterCommits) {
@@ -260,6 +264,10 @@
 
   histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
   histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+
+  histogram_tester().ExpectTotalCount(internal::kHistogramPageTimingPageEnd, 0);
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramPageTimingFirstBackground, 1);
 }
 
 TEST_F(CorePageLoadMetricsObserverTest, DontBackgroundQuickerLoad) {
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
index 49faa4f..3cf2d12 100644
--- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc
@@ -11,7 +11,7 @@
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
-using page_load_metrics::UserAbortType;
+using page_load_metrics::PageAbortReason;
 
 namespace internal {
 
@@ -100,114 +100,113 @@
 
 namespace {
 
-void LogCommittedAbortsBeforePaint(UserAbortType abort_type,
-                                   base::TimeDelta time_to_abort) {
-  switch (abort_type) {
-    case UserAbortType::ABORT_STOP:
+void LogCommittedAbortsBeforePaint(PageAbortReason abort_reason,
+                                   base::TimeDelta page_end_time) {
+  switch (abort_reason) {
+    case PageAbortReason::ABORT_STOP:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortStopBeforePaint,
-                          time_to_abort);
+                          page_end_time);
       break;
-    case UserAbortType::ABORT_CLOSE:
+    case PageAbortReason::ABORT_CLOSE:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortCloseBeforePaint,
-                          time_to_abort);
+                          page_end_time);
       break;
-    case UserAbortType::ABORT_NEW_NAVIGATION:
+    case PageAbortReason::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortNewNavigationBeforePaint,
-          time_to_abort);
+          page_end_time);
       break;
-    case UserAbortType::ABORT_RELOAD:
+    case PageAbortReason::ABORT_RELOAD:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortReloadBeforePaint,
-                          time_to_abort);
+                          page_end_time);
       break;
-    case UserAbortType::ABORT_FORWARD_BACK:
+    case PageAbortReason::ABORT_FORWARD_BACK:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortForwardBackBeforePaint,
-          time_to_abort);
+          page_end_time);
       break;
-    case UserAbortType::ABORT_BACKGROUND:
+    case PageAbortReason::ABORT_BACKGROUND:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortBackgroundBeforePaint,
-                          time_to_abort);
+                          page_end_time);
       break;
     default:
       // These should only be logged for provisional aborts.
-      DCHECK_NE(abort_type, UserAbortType::ABORT_OTHER);
+      DCHECK_NE(abort_reason, PageAbortReason::ABORT_OTHER);
       break;
   }
 }
 
-void LogAbortsAfterPaintBeforeInteraction(UserAbortType abort_type,
-                                          base::TimeDelta time_to_abort) {
-  switch (abort_type) {
-    case UserAbortType::ABORT_STOP:
+void LogAbortsAfterPaintBeforeInteraction(
+    const page_load_metrics::PageAbortInfo& abort_info) {
+  switch (abort_info.reason) {
+    case PageAbortReason::ABORT_STOP:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortStopBeforeInteraction,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_CLOSE:
+    case PageAbortReason::ABORT_CLOSE:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortCloseBeforeInteraction,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_NEW_NAVIGATION:
+    case PageAbortReason::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortNewNavigationBeforeInteraction,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_RELOAD:
+    case PageAbortReason::ABORT_RELOAD:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortReloadBeforeInteraction,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_FORWARD_BACK:
+    case PageAbortReason::ABORT_FORWARD_BACK:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortForwardBackBeforeInteraction,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_BACKGROUND:
+    case PageAbortReason::ABORT_BACKGROUND:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortBackgroundBeforeInteraction,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
     default:
       // These should only be logged for provisional aborts.
-      DCHECK_NE(abort_type, UserAbortType::ABORT_OTHER);
+      DCHECK_NE(abort_info.reason, PageAbortReason::ABORT_OTHER);
       break;
   }
 }
 
-void LogProvisionalAborts(UserAbortType abort_type,
-                          base::TimeDelta time_to_abort) {
-  switch (abort_type) {
-    case UserAbortType::ABORT_STOP:
+void LogProvisionalAborts(const page_load_metrics::PageAbortInfo& abort_info) {
+  switch (abort_info.reason) {
+    case PageAbortReason::ABORT_STOP:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortStopBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_CLOSE:
+    case PageAbortReason::ABORT_CLOSE:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortCloseBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_OTHER:
+    case PageAbortReason::ABORT_OTHER:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortOtherBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_NEW_NAVIGATION:
+    case PageAbortReason::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortNewNavigationBeforeCommit,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_RELOAD:
+    case PageAbortReason::ABORT_RELOAD:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortReloadBeforeCommit,
-                          time_to_abort);
+                          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_FORWARD_BACK:
+    case PageAbortReason::ABORT_FORWARD_BACK:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortForwardBackBeforeCommit,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
-    case UserAbortType::ABORT_BACKGROUND:
+    case PageAbortReason::ABORT_BACKGROUND:
       PAGE_LOAD_HISTOGRAM(
           internal::kHistogramFromGWSAbortBackgroundBeforeCommit,
-          time_to_abort);
+          abort_info.time_to_abort);
       break;
     default:
       NOTREACHED();
@@ -216,24 +215,21 @@
 }
 
 bool WasAbortedInForeground(
-    UserAbortType abort_type,
-    const base::Optional<base::TimeDelta>& time_to_abort,
-    const page_load_metrics::PageLoadExtraInfo& info) {
-  if (!time_to_abort)
-    return false;
-  if (abort_type == UserAbortType::ABORT_NONE)
-    return false;
-  if (WasStartedInForegroundOptionalEventInForeground(time_to_abort, info))
-    return true;
-  if (!info.started_in_foreground)
+    const page_load_metrics::PageLoadExtraInfo& info,
+    const page_load_metrics::PageAbortInfo& abort_info) {
+  if (!info.started_in_foreground ||
+      abort_info.reason == PageAbortReason::ABORT_NONE)
     return false;
 
-  const base::TimeDelta time_to_abort_val = time_to_abort.value();
+  base::Optional<base::TimeDelta> time_to_abort(abort_info.time_to_abort);
+  if (WasStartedInForegroundOptionalEventInForeground(time_to_abort, info))
+    return true;
+
   const base::TimeDelta time_to_first_background =
       info.first_background_time.value();
-  DCHECK_GT(time_to_abort_val, time_to_first_background);
+  DCHECK_GT(abort_info.time_to_abort, time_to_first_background);
   base::TimeDelta background_abort_delta =
-      time_to_abort_val - time_to_first_background;
+      abort_info.time_to_abort - time_to_first_background;
   // Consider this a foregrounded abort if it occurred within 100ms of a
   // background. This is needed for closing some tabs, where the signal for
   // background is often slightly ahead of the signal for close.
@@ -243,14 +239,12 @@
 }
 
 bool WasAbortedBeforeInteraction(
-    UserAbortType abort_type,
-    const base::Optional<base::TimeDelta>& time_to_interaction,
-    const base::Optional<base::TimeDelta>& time_to_abort) {
+    const page_load_metrics::PageAbortInfo& abort_info,
+    const base::Optional<base::TimeDelta>& time_to_interaction) {
   // These conditions should be guaranteed by the call to
   // WasAbortedInForeground, which is called before WasAbortedBeforeInteraction
   // gets invoked.
-  DCHECK(time_to_abort);
-  DCHECK(abort_type != UserAbortType::ABORT_NONE);
+  DCHECK(abort_info.reason != PageAbortReason::ABORT_NONE);
 
   if (!time_to_interaction)
     return true;
@@ -264,13 +258,13 @@
   // 1000ms is enough to perform a pull to reload / forward_back gesture.
   // It's also too short a time for a user to consume any content
   // revealed by the interaction.
-  if (abort_type == UserAbortType::ABORT_RELOAD ||
-      abort_type == UserAbortType::ABORT_FORWARD_BACK) {
+  if (abort_info.reason == PageAbortReason::ABORT_RELOAD ||
+      abort_info.reason == PageAbortReason::ABORT_FORWARD_BACK) {
     return time_to_interaction.value() +
                base::TimeDelta::FromMilliseconds(1000) >
-           time_to_abort;
+           abort_info.time_to_abort;
   } else {
-    return time_to_interaction > time_to_abort;
+    return time_to_interaction > abort_info.time_to_abort;
   }
 }
 
@@ -532,8 +526,8 @@
   if (!ShouldLogPostCommitMetrics(extra_info.url))
     return;
 
-  UserAbortType abort_type = extra_info.abort_type;
-  if (!WasAbortedInForeground(abort_type, extra_info.time_to_abort, extra_info))
+  page_load_metrics::PageAbortInfo abort_info = GetPageAbortInfo(extra_info);
+  if (!WasAbortedInForeground(extra_info, abort_info))
     return;
 
   // If we did not receive any timing IPCs from the render process, we can't
@@ -546,13 +540,11 @@
   if (timing.IsEmpty())
     return;
 
-  base::TimeDelta time_to_abort = extra_info.time_to_abort.value();
-  if (!timing.first_paint || timing.first_paint >= time_to_abort) {
-    LogCommittedAbortsBeforePaint(abort_type, time_to_abort);
-  } else if (WasAbortedBeforeInteraction(abort_type,
-                                         first_user_interaction_after_paint_,
-                                         extra_info.time_to_abort)) {
-    LogAbortsAfterPaintBeforeInteraction(abort_type, time_to_abort);
+  if (!timing.first_paint || timing.first_paint >= abort_info.time_to_abort) {
+    LogCommittedAbortsBeforePaint(abort_info.reason, abort_info.time_to_abort);
+  } else if (WasAbortedBeforeInteraction(abort_info,
+                                         first_user_interaction_after_paint_)) {
+    LogAbortsAfterPaintBeforeInteraction(abort_info);
   }
 }
 
@@ -562,11 +554,11 @@
   if (!ShouldLogFailedProvisionalLoadMetrics())
     return;
 
-  UserAbortType abort_type = extra_info.abort_type;
-  if (!WasAbortedInForeground(abort_type, extra_info.time_to_abort, extra_info))
+  page_load_metrics::PageAbortInfo abort_info = GetPageAbortInfo(extra_info);
+  if (!WasAbortedInForeground(extra_info, abort_info))
     return;
 
-  LogProvisionalAborts(abort_type, extra_info.time_to_abort.value());
+  LogProvisionalAborts(abort_info);
 }
 
 bool FromGWSPageLoadMetricsLogger::ShouldLogFailedProvisionalLoadMetrics() {
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
index 13f70d8..32de069 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
@@ -5,8 +5,14 @@
 #include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
 
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
 #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
 
+using subresource_filter::ContentSubresourceFilterDriverFactory;
+
+using ActivationDecision = subresource_filter::
+    ContentSubresourceFilterDriverFactory::ActivationDecision;
+
 namespace internal {
 
 const char kHistogramSubresourceFilterFirstContentfulPaint[] =
@@ -47,8 +53,34 @@
 const char kHistogramSubresourceFilterCount[] =
     "PageLoad.Clients.SubresourceFilter.Count";
 
+const char kHistogramSubresourceFilterActivationDecision[] =
+    "PageLoad.Clients.SubresourceFilter.ActivationDecision";
+const char kHistogramSubresourceFilterActivationDecisionReload[] =
+    "PageLoad.Clients.SubresourceFilter.ActivationDecision.LoadType.Reload";
+
 }  // namespace internal
 
+namespace {
+
+void LogActivationDecisionMetrics(content::NavigationHandle* navigation_handle,
+                                  ActivationDecision decision) {
+  UMA_HISTOGRAM_ENUMERATION(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(decision),
+      static_cast<int>(ActivationDecision::ACTIVATION_DECISION_MAX));
+
+  if (ContentSubresourceFilterDriverFactory::NavigationIsPageReload(
+          navigation_handle->GetURL(), navigation_handle->GetReferrer(),
+          navigation_handle->GetPageTransition())) {
+    UMA_HISTOGRAM_ENUMERATION(
+        internal::kHistogramSubresourceFilterActivationDecisionReload,
+        static_cast<int>(decision),
+        static_cast<int>(ActivationDecision::ACTIVATION_DECISION_MAX));
+  }
+}
+
+}  // namespace
+
 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
 SubresourceFilterMetricsObserver::FlushMetricsOnAppEnterBackground(
     const page_load_metrics::PageLoadTiming& timing,
@@ -62,6 +94,19 @@
   return STOP_OBSERVING;
 }
 
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+SubresourceFilterMetricsObserver::OnCommit(
+    content::NavigationHandle* navigation_handle) {
+  const auto* subres_filter =
+      ContentSubresourceFilterDriverFactory::FromWebContents(
+          navigation_handle->GetWebContents());
+  if (subres_filter)
+    LogActivationDecisionMetrics(
+        navigation_handle,
+        subres_filter->GetActivationDecisionForLastCommittedPageLoad());
+  return CONTINUE_OBSERVING;
+}
+
 void SubresourceFilterMetricsObserver::OnComplete(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
index 27b0128..ebc9b3c 100644
--- a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
@@ -27,6 +27,9 @@
 
 extern const char kHistogramSubresourceFilterCount[];
 
+extern const char kHistogramSubresourceFilterActivationDecision[];
+extern const char kHistogramSubresourceFilterActivationDecisionReload[];
+
 }  // namespace internal
 
 class SubresourceFilterMetricsObserver
@@ -36,6 +39,7 @@
   ~SubresourceFilterMetricsObserver() override = default;
 
   // page_load_metrics::PageLoadMetricsObserver:
+  ObservePolicy OnCommit(content::NavigationHandle* navigation_handle) override;
   ObservePolicy FlushMetricsOnAppEnterBackground(
       const page_load_metrics::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& info) override;
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc
new file mode 100644
index 0000000..1223f5f5
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc
@@ -0,0 +1,85 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h"
+
+#include <string>
+
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/restore_type.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/page_transition_types.h"
+
+namespace {
+
+const char kHistogramNetworkBytes[] =
+    "PageLoad.Clients.TabRestore.Experimental.Bytes.Network";
+const char kHistogramCacheBytes[] =
+    "PageLoad.Clients.TabRestore.Experimental.Bytes.Cache";
+const char kHistogramTotalBytes[] =
+    "PageLoad.Clients.TabRestore.Experimental.Bytes.Total";
+
+}  // namespace
+
+TabRestorePageLoadMetricsObserver::TabRestorePageLoadMetricsObserver()
+    : cache_bytes_(0), network_bytes_(0) {}
+
+TabRestorePageLoadMetricsObserver::~TabRestorePageLoadMetricsObserver() {}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+TabRestorePageLoadMetricsObserver::OnStart(
+    content::NavigationHandle* navigation_handle,
+    const GURL& currently_committed_url,
+    bool started_in_foreground) {
+  return IsTabRestore(navigation_handle) ? CONTINUE_OBSERVING : STOP_OBSERVING;
+}
+
+void TabRestorePageLoadMetricsObserver::OnLoadedResource(
+    const page_load_metrics::ExtraRequestInfo& extra_request_info) {
+  if (extra_request_info.was_cached) {
+    cache_bytes_ += extra_request_info.raw_body_bytes;
+  } else {
+    network_bytes_ += extra_request_info.raw_body_bytes;
+  }
+}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+TabRestorePageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  // FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
+  // app is about to be backgrounded, as part of the Activity.onPause()
+  // flow. After this method is invoked, Chrome may be killed without further
+  // notification, so we record final metrics collected up to this point.
+  if (!info.did_commit) {
+    RecordByteHistograms();
+  }
+  return STOP_OBSERVING;
+}
+
+void TabRestorePageLoadMetricsObserver::OnComplete(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  RecordByteHistograms();
+}
+
+void TabRestorePageLoadMetricsObserver::RecordByteHistograms() {
+  PAGE_BYTES_HISTOGRAM(kHistogramNetworkBytes, network_bytes_);
+  PAGE_BYTES_HISTOGRAM(kHistogramCacheBytes, cache_bytes_);
+  PAGE_BYTES_HISTOGRAM(kHistogramTotalBytes, network_bytes_ + cache_bytes_);
+}
+
+bool TabRestorePageLoadMetricsObserver::IsTabRestore(
+    content::NavigationHandle* navigation_handle) {
+  // Only count restored tabs, and eliminate forward-back navigations, as
+  // restored tab history is considered a restored navigation until they are
+  // loaded the first time.
+  return navigation_handle->GetRestoreType() != content::RestoreType::NONE &&
+         !(navigation_handle->GetPageTransition() &
+           ui::PAGE_TRANSITION_FORWARD_BACK);
+}
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h
new file mode 100644
index 0000000..316500c
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_TAB_RESTORE_PAGE_LOAD_METRICS_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_TAB_RESTORE_PAGE_LOAD_METRICS_OBSERVER_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
+
+namespace content {
+class NavigationHandle;
+}
+
+namespace page_load_metrics {
+struct PageLoadExtraInfo;
+struct PageLoadTiming;
+}
+
+// Observer responsible for recording core page load metrics relevant to
+// restored tabs.
+class TabRestorePageLoadMetricsObserver
+    : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+  TabRestorePageLoadMetricsObserver();
+  ~TabRestorePageLoadMetricsObserver() override;
+
+  // page_load_metrics::PageLoadMetricsObserver:
+  void OnComplete(const page_load_metrics::PageLoadTiming& timing,
+                  const page_load_metrics::PageLoadExtraInfo& info) override;
+  page_load_metrics::PageLoadMetricsObserver::ObservePolicy OnStart(
+      content::NavigationHandle* navigation_handle,
+      const GURL& currently_committed_url,
+      bool started_in_foreground) override;
+  void OnLoadedResource(
+      const page_load_metrics::ExtraRequestInfo& extra_request_info) override;
+  page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+  FlushMetricsOnAppEnterBackground(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& info) override;
+
+ protected:
+  // Whether the navigation handle is a tab restore.
+  // Overridden in testing.
+  virtual bool IsTabRestore(content::NavigationHandle* navigation_handle);
+
+ private:
+  // Records histograms for byte information.
+  void RecordByteHistograms();
+
+  // The number of body (not header) prefilter bytes consumed by requests for
+  // the page.
+  int64_t cache_bytes_;
+  int64_t network_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabRestorePageLoadMetricsObserver);
+};
+
+#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_TAB_RESTORE_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc
new file mode 100644
index 0000000..218286d
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h"
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/test/histogram_tester.h"
+#include "base/time/time.h"
+#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
+#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
+#include "chrome/common/page_load_metrics/page_load_timing.h"
+#include "content/public/browser/restore_type.h"
+#include "content/public/browser/web_contents.h"
+#include "url/gurl.h"
+
+namespace previews {
+
+namespace {
+
+const char kDefaultTestUrl[] = "https://google.com";
+
+class TestTabRestorePageLoadMetricsObserver
+    : public TabRestorePageLoadMetricsObserver {
+ public:
+  explicit TestTabRestorePageLoadMetricsObserver(bool is_restore)
+      : is_restore_(is_restore) {}
+  ~TestTabRestorePageLoadMetricsObserver() override {}
+
+ private:
+  bool IsTabRestore(content::NavigationHandle* navigation_handle) override {
+    return is_restore_;
+  }
+
+  const bool is_restore_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestTabRestorePageLoadMetricsObserver);
+};
+
+}  // namespace
+
+class TabRestorePageLoadMetricsObserverTest
+    : public page_load_metrics::PageLoadMetricsObserverTestHarness {
+ public:
+  TabRestorePageLoadMetricsObserverTest() {}
+
+  void ResetTest() {
+    // Reset to the default testing state. Does not reset histogram state.
+    timing_.navigation_start = base::Time::FromDoubleT(1);
+    timing_.response_start = base::TimeDelta::FromSeconds(2);
+    timing_.parse_start = base::TimeDelta::FromSeconds(3);
+    timing_.first_contentful_paint = base::TimeDelta::FromSeconds(4);
+    timing_.first_image_paint = base::TimeDelta::FromSeconds(5);
+    timing_.first_text_paint = base::TimeDelta::FromSeconds(6);
+    timing_.load_event_start = base::TimeDelta::FromSeconds(7);
+    PopulateRequiredTimingFields(&timing_);
+  }
+
+  void RunTest(content::RestoreType restore_type) {
+    is_restore_ = restore_type == content::RestoreType::NONE;
+    NavigateAndCommit(GURL(kDefaultTestUrl));
+    SimulateTimingUpdate(timing_);
+
+    // Prepare 4 resources of varying size and configurations.
+    page_load_metrics::ExtraRequestInfo resources[] = {
+        // Cached request.
+        {true /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+         false /* data_reduction_proxy_used*/,
+         0 /* original_network_content_length */},
+        // Uncached non-proxied request.
+        {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+         false /* data_reduction_proxy_used*/,
+         1024 * 40 /* original_network_content_length */},
+        // Uncached proxied request with .1 compression ratio.
+        {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+         false /* data_reduction_proxy_used*/,
+         1024 * 40 /* original_network_content_length */},
+        // Uncached proxied request with .5 compression ratio.
+        {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+         false /* data_reduction_proxy_used*/,
+         1024 * 40 /* original_network_content_length */},
+    };
+
+    int64_t network_bytes = 0;
+    int64_t cache_bytes = 0;
+    for (auto request : resources) {
+      SimulateLoadedResource(request);
+      if (!request.was_cached) {
+        network_bytes += request.raw_body_bytes;
+      } else {
+        cache_bytes += request.raw_body_bytes;
+      }
+    }
+
+    NavigateToUntrackedUrl();
+    if (!is_restore_.value()) {
+      histogram_tester().ExpectTotalCount(
+          "PageLoad.Clients.TabRestore.Experimental.Bytes.Network", 0);
+      histogram_tester().ExpectTotalCount(
+          "PageLoad.Clients.TabRestore.Experimental.Bytes.Cache", 0);
+      histogram_tester().ExpectTotalCount(
+          "PageLoad.Clients.TabRestore.Experimental.Bytes.Total", 0);
+    } else {
+      histogram_tester().ExpectUniqueSample(
+          "PageLoad.Clients.TabRestore.Experimental.Bytes.Network",
+          static_cast<int>(network_bytes / 1024), 1);
+      histogram_tester().ExpectUniqueSample(
+          "PageLoad.Clients.TabRestore.Experimental.Bytes.Cache",
+          static_cast<int>(cache_bytes / 1024), 1);
+      histogram_tester().ExpectUniqueSample(
+          "PageLoad.Clients.TabRestore.Experimental.Bytes.Total",
+          static_cast<int>((network_bytes + cache_bytes) / 1024), 1);
+    }
+  }
+
+ protected:
+  void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
+    tracker->AddObserver(base::WrapUnique(
+        new TestTabRestorePageLoadMetricsObserver(is_restore_.value())));
+  }
+
+ private:
+  base::Optional<bool> is_restore_;
+  page_load_metrics::PageLoadTiming timing_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabRestorePageLoadMetricsObserverTest);
+};
+
+TEST_F(TabRestorePageLoadMetricsObserverTest, NotRestored) {
+  ResetTest();
+  RunTest(content::RestoreType::NONE);
+}
+
+TEST_F(TabRestorePageLoadMetricsObserverTest, Restored) {
+  ResetTest();
+  RunTest(content::RestoreType::CURRENT_SESSION);
+}
+
+}  // namespace previews
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 8c28b08f..bd43931 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -215,6 +215,7 @@
   histogram_tester_.ExpectTotalCount(
       internal::kHistogramParseBlockedOnScriptExecution, 1);
   histogram_tester_.ExpectTotalCount(internal::kHistogramTotalBytes, 1);
+  histogram_tester_.ExpectTotalCount(internal::kHistogramPageTimingPageEnd, 1);
 
   // Verify that NoPageLoadMetricsRecorded returns false when PageLoad metrics
   // have been recorded.
@@ -597,7 +598,8 @@
       internal::kHistogramAbortNewNavigationBeforeCommit, 2);
 }
 
-IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, AbortClientRedirect) {
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
+                       NoAbortMetricsOnClientRedirect) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL first_url(embedded_test_server()->GetURL("/title1.html"));
@@ -621,8 +623,9 @@
 
   manager.WaitForNavigationFinished();
 
-  histogram_tester_.ExpectTotalCount(
-      internal::kHistogramAbortClientRedirectBeforeCommit, 1);
+  EXPECT_TRUE(histogram_tester_
+                  .GetTotalCountsForPrefix("PageLoad.Experimental.AbortTiming.")
+                  .empty());
 }
 
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index a409b5e..3af2ffd 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
@@ -88,6 +89,7 @@
             web_contents_->GetBrowserContext()));
     tracker->AddObserver(base::MakeUnique<CssScanningMetricsObserver>());
     tracker->AddObserver(base::MakeUnique<ProtocolPageLoadMetricsObserver>());
+    tracker->AddObserver(base::MakeUnique<TabRestorePageLoadMetricsObserver>());
 
     std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> ukm_observer =
         UkmPageLoadMetricsObserver::CreateIfNeeded();
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/page_load_metrics_observer.cc
index 61a43a6b..8d1bb02 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.cc
@@ -14,9 +14,9 @@
     const GURL& url,
     const GURL& start_url,
     bool did_commit,
-    UserAbortType abort_type,
-    UserInitiatedInfo abort_user_initiated_info,
-    const base::Optional<base::TimeDelta>& time_to_abort,
+    PageEndReason page_end_reason,
+    UserInitiatedInfo page_end_user_initiated_info,
+    const base::Optional<base::TimeDelta>& page_end_time,
     const PageLoadMetadata& metadata)
     : first_background_time(first_background_time),
       first_foreground_time(first_foreground_time),
@@ -25,9 +25,9 @@
       url(url),
       start_url(start_url),
       did_commit(did_commit),
-      abort_type(abort_type),
-      abort_user_initiated_info(abort_user_initiated_info),
-      time_to_abort(time_to_abort),
+      page_end_reason(page_end_reason),
+      page_end_user_initiated_info(page_end_user_initiated_info),
+      page_end_time(page_end_time),
       metadata(metadata) {}
 
 PageLoadExtraInfo::PageLoadExtraInfo(const PageLoadExtraInfo& other) = default;
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
index 691d383..0f9cc76 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -19,43 +19,41 @@
 // This enum represents how a page load ends. If the action occurs before the
 // page load finishes (or reaches some point like first paint), then we consider
 // the load to be aborted.
-enum UserAbortType {
-  // Represents no abort.
-  ABORT_NONE,
+enum PageEndReason {
+  // Page lifetime has not yet ended (page is still active).
+  END_NONE,
 
-  // If the user presses reload or shift-reload.
-  ABORT_RELOAD,
+  // The page was reloaded, possibly by the user.
+  END_RELOAD,
 
-  // The user presses the back/forward button.
-  ABORT_FORWARD_BACK,
+  // The page was navigated away from, via a back or forward navigation.
+  END_FORWARD_BACK,
 
   // The navigation is replaced with a navigation with the qualifier
   // ui::PAGE_TRANSITION_CLIENT_REDIRECT, which is caused by Javascript, or the
   // meta refresh tag.
-  ABORT_CLIENT_REDIRECT,
+  END_CLIENT_REDIRECT,
 
   // If the page load is replaced by a new navigation. This includes link
   // clicks, typing in the omnibox (not a reload), and form submissions.
-  ABORT_NEW_NAVIGATION,
+  END_NEW_NAVIGATION,
 
-  // If the user presses the stop X button.
-  ABORT_STOP,
+  // The page load was stopped (e.g. the user presses the stop X button).
+  END_STOP,
 
-  // If the page load is aborted by closing the tab or browser.
-  ABORT_CLOSE,
+  // Page load ended due to closing the tab or browser.
+  END_CLOSE,
 
-  // The page load was backgrounded, e.g. the browser was minimized or the user
-  // switched tabs. Note that the same page may be foregrounded in the future,
-  // so this is not a 'terminal' abort type.
-  ABORT_BACKGROUND,
+  // The provisional load for this page load failed before committing.
+  END_PROVISIONAL_LOAD_FAILED,
 
-  // We don't know why the page load aborted. This is the value we assign to an
-  // aborted load if the only signal we get is a provisional load finishing
+  // The render process hosting the page terminated unexpectedly.
+  END_RENDER_PROCESS_GONE,
+
+  // We don't know why the page load ended. This is the value we assign to a
+  // terminated provisional load if the only signal we get is the load finished
   // without committing, either without error or with net::ERR_ABORTED.
-  ABORT_OTHER,
-
-  // Add values before this final count.
-  ABORT_LAST_ENTRY
+  END_OTHER
 };
 
 // Information related to failed provisional loads.
@@ -116,9 +114,9 @@
       const GURL& url,
       const GURL& start_url,
       bool did_commit,
-      UserAbortType abort_type,
-      UserInitiatedInfo abort_user_initiated_info,
-      const base::Optional<base::TimeDelta>& time_to_abort,
+      PageEndReason page_end_reason,
+      UserInitiatedInfo page_end_user_initiated_info,
+      const base::Optional<base::TimeDelta>& page_end_time,
       const PageLoadMetadata& metadata);
 
   PageLoadExtraInfo(const PageLoadExtraInfo& other);
@@ -147,24 +145,37 @@
   // Whether the navigation for this page load committed.
   const bool did_commit;
 
-  // The abort time and time to abort for this page load. If the page was not
-  // aborted, |abort_type| will be |ABORT_NONE|.
-  const UserAbortType abort_type;
+  // The reason the page load ended. If the page is still active,
+  // |page_end_reason| will be |END_NONE|. |page_end_time| contains the duration
+  // of time until the cause of the page end reason was encountered.
+  const PageEndReason page_end_reason;
 
-  // Whether the abort for this page load was user initiated. For example, if
-  // this page load was aborted by a new navigation, this field tracks whether
+  // Whether the end reason for this page load was user initiated. For example,
+  // if
+  // this page load was ended due to a new navigation, this field tracks whether
   // that new navigation was user-initiated. This field is only useful if this
-  // page load's abort type is a value other than ABORT_NONE. Note that this
+  // page load's end reason is a value other than END_NONE. Note that this
   // value is currently experimental, and is subject to change. In particular,
-  // this field is not currently set for some abort types, such as stop and
+  // this field is not currently set for some end reasons, such as stop and
   // close, since we don't yet have sufficient instrumentation to know if a stop
   // or close was caused by a user action.
   //
-  // TODO(csharrison): If more metadata for aborts is needed we should provide a
+  // TODO(csharrison): If more metadata for end reasons is needed we should
+  // provide a
   // better abstraction. Note that this is an approximation.
-  UserInitiatedInfo abort_user_initiated_info;
+  UserInitiatedInfo page_end_user_initiated_info;
 
-  const base::Optional<base::TimeDelta> time_to_abort;
+  // Total lifetime of the page from the user standoint, starting at navigation
+  // start. The page lifetime ends when the first of the following events
+  // happen:
+  // * the load of the main resource fails
+  // * the page load is stopped
+  // * the tab hosting the page is closed
+  // * the render process hosting the page goes away
+  // * a new navigation which later commits is initiated in the same tab
+  // This field will not be set if the page is still active and hasn't yet
+  // finished.
+  const base::Optional<base::TimeDelta> page_end_time;
 
   // Extra information supplied to the page load metrics system from the
   // renderer.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_util.cc b/chrome/browser/page_load_metrics/page_load_metrics_util.cc
index 1203a2d7..1449f5c5 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_util.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_util.cc
@@ -6,11 +6,43 @@
 
 #include <algorithm>
 
-#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 
 namespace page_load_metrics {
 
+namespace {
+
+bool IsBackgroundAbort(const PageLoadExtraInfo& info) {
+  if (!info.started_in_foreground || !info.first_background_time)
+    return false;
+
+  if (!info.page_end_time)
+    return true;
+
+  return info.first_background_time <= info.page_end_time;
+}
+
+PageAbortReason GetAbortReasonForEndReason(PageEndReason end_reason) {
+  switch (end_reason) {
+    case END_RELOAD:
+      return ABORT_RELOAD;
+    case END_FORWARD_BACK:
+      return ABORT_FORWARD_BACK;
+    case END_NEW_NAVIGATION:
+      return ABORT_NEW_NAVIGATION;
+    case END_STOP:
+      return ABORT_STOP;
+    case END_CLOSE:
+      return ABORT_CLOSE;
+    case END_OTHER:
+      return ABORT_OTHER;
+    default:
+      return ABORT_NONE;
+  }
+}
+
+}  // namespace
+
 bool WasStartedInForegroundOptionalEventInForeground(
     const base::Optional<base::TimeDelta>& event,
     const PageLoadExtraInfo& info) {
@@ -19,4 +51,23 @@
           event.value() <= info.first_background_time.value());
 }
 
+PageAbortInfo GetPageAbortInfo(const PageLoadExtraInfo& info) {
+  if (IsBackgroundAbort(info)) {
+    // Though most cases where a tab is backgrounded are user initiated, we
+    // can't be certain that we were backgrounded due to a user action. For
+    // example, on Android, the screen times out after a period of inactivity,
+    // resulting in a non-user-initiated backgrounding.
+    return {ABORT_BACKGROUND, UserInitiatedInfo::NotUserInitiated(),
+            info.first_background_time.value()};
+  }
+
+  PageAbortReason abort_reason =
+      GetAbortReasonForEndReason(info.page_end_reason);
+  if (abort_reason == ABORT_NONE)
+    return PageAbortInfo();
+
+  return {abort_reason, info.page_end_user_initiated_info,
+          info.page_end_time.value()};
+}
+
 }  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_util.h b/chrome/browser/page_load_metrics/page_load_metrics_util.h
index 3babd6a..4c62c39 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_util.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_util.h
@@ -8,6 +8,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 
 #define PAGE_LOAD_HISTOGRAM(name, sample)                           \
   UMA_HISTOGRAM_CUSTOM_TIMES(name, sample,                          \
@@ -25,6 +26,62 @@
 
 struct PageLoadExtraInfo;
 
+// Reasons a page load can be aborted.
+enum PageAbortReason {
+  // Represents no abort.
+  ABORT_NONE,
+
+  // The page was reloaded, possibly by the user.
+  ABORT_RELOAD,
+
+  // The page was navigated away from, via a back or forward navigation.
+  ABORT_FORWARD_BACK,
+
+  // If the page load is replaced by a new navigation. This includes link
+  // clicks, typing in the omnibox (not a reload), and form submissions.
+  ABORT_NEW_NAVIGATION,
+
+  // The page load was stopped (e.g. the user presses the stop X button).
+  ABORT_STOP,
+
+  // Page load ended due to closing the tab or browser.
+  ABORT_CLOSE,
+
+  // The page load was backgrounded, e.g. the browser was minimized or the user
+  // switched tabs. Note that the same page may be foregrounded in the future,
+  // so this is not a 'terminal' abort type.
+  ABORT_BACKGROUND,
+
+  // We don't know why the page load ended. This is the value we assign to a
+  // terminated provisional load if the only signal we get is the load finished
+  // without committing, either without error or with net::ERR_ABORTED.
+  ABORT_OTHER
+};
+
+// Information related to a page load abort.
+struct PageAbortInfo {
+  PageAbortInfo()
+      : reason(ABORT_NONE),
+        user_initiated_info(UserInitiatedInfo::NotUserInitiated()) {}
+  PageAbortInfo(PageAbortReason reason,
+                UserInitiatedInfo user_initiated_info,
+                base::TimeDelta time_to_abort)
+      : reason(reason),
+        user_initiated_info(user_initiated_info),
+        time_to_abort(time_to_abort) {}
+
+  // The reason / cause for the abort.
+  const PageAbortReason reason;
+
+  // The fields below are only valid if reason != ABORT_NONE.
+
+  // Information about whether the abort was initiated by a user.
+  const UserInitiatedInfo user_initiated_info;
+
+  // The time from navigation start to the time the page load was aborted.
+  const base::TimeDelta time_to_abort;
+};
+
 // Returns true if:
 // - We have timing information for the event.
 // - The page load started while the page was in the foreground.
@@ -39,6 +96,8 @@
     const base::Optional<base::TimeDelta>& event,
     const PageLoadExtraInfo& info);
 
+PageAbortInfo GetPageAbortInfo(const PageLoadExtraInfo& info);
+
 }  // namespace page_load_metrics
 
 #endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_UTIL_H_
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index 650d0f87..39941ae 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -65,20 +65,20 @@
 
 // TODO(csharrison): Add a case for client side redirects, which is what JS
 // initiated window.location / window.history navigations get set to.
-UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) {
+PageEndReason EndReasonForPageTransition(ui::PageTransition transition) {
   if (transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT) {
-    return ABORT_CLIENT_REDIRECT;
+    return END_CLIENT_REDIRECT;
   }
   if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
-    return ABORT_RELOAD;
+    return END_RELOAD;
   if (transition & ui::PAGE_TRANSITION_FORWARD_BACK)
-    return ABORT_FORWARD_BACK;
+    return END_FORWARD_BACK;
   if (ui::PageTransitionIsNewNavigation(transition))
-    return ABORT_NEW_NAVIGATION;
+    return END_NEW_NAVIGATION;
   NOTREACHED()
-      << "AbortTypeForPageTransition received unexpected ui::PageTransition: "
+      << "EndReasonForPageTransition received unexpected ui::PageTransition: "
       << transition;
-  return ABORT_OTHER;
+  return END_OTHER;
 }
 
 void LogAbortChainSameURLHistogram(int aborted_chain_size_same_url) {
@@ -298,8 +298,8 @@
       url_(navigation_handle->GetURL()),
       start_url_(navigation_handle->GetURL()),
       did_commit_(false),
-      abort_type_(ABORT_NONE),
-      abort_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()),
+      page_end_reason_(END_NONE),
+      page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()),
       started_in_foreground_(in_foreground),
       page_transition_(navigation_handle->GetPageTransition()),
       user_initiated_info_(user_initiated_info),
@@ -320,14 +320,20 @@
   if (did_stop_tracking_)
     return;
 
+  if (page_end_time_.is_null()) {
+    RecordInternalError(ERR_NO_PAGE_LOAD_END_TIME);
+    page_end_time_ = base::TimeTicks::Now();
+  }
+
   if (!did_commit_) {
     if (!failed_provisional_load_info_)
       RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD);
 
     // Don't include any aborts that resulted in a new navigation, as the chain
     // length will be included in the aborter PageLoadTracker.
-    if (abort_type_ != ABORT_RELOAD && abort_type_ != ABORT_FORWARD_BACK &&
-        abort_type_ != ABORT_NEW_NAVIGATION) {
+    if (page_end_reason_ != END_RELOAD &&
+        page_end_reason_ != END_FORWARD_BACK &&
+        page_end_reason_ != END_NEW_NAVIGATION) {
       LogAbortChainHistograms(nullptr);
     }
   } else if (timing_.IsEmpty()) {
@@ -368,12 +374,12 @@
 
   ui::PageTransition committed_transition =
       final_navigation->GetPageTransition();
-  switch (AbortTypeForPageTransition(committed_transition)) {
-    case ABORT_RELOAD:
+  switch (EndReasonForPageTransition(committed_transition)) {
+    case END_RELOAD:
       UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeReload,
                            aborted_chain_size_);
       return;
-    case ABORT_FORWARD_BACK:
+    case END_FORWARD_BACK:
       UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeForwardBack,
                            aborted_chain_size_);
       return;
@@ -382,8 +388,8 @@
     // chain, log a histogram of the counts of each of these metrics. For now,
     // merge client redirects with new navigations, which was (basically) the
     // previous behavior.
-    case ABORT_CLIENT_REDIRECT:
-    case ABORT_NEW_NAVIGATION:
+    case END_CLIENT_REDIRECT:
+    case END_NEW_NAVIGATION:
       UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeNewNavigation,
                            aborted_chain_size_);
       return;
@@ -404,12 +410,6 @@
     DCHECK_EQ(started_in_foreground_, foreground_time_.is_null());
     background_time_ = base::TimeTicks::Now();
     ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_);
-    // Though most cases where a tab is backgrounded are user initiated, we
-    // can't be certain that we were backgrounded due to a user action. For
-    // example, on Android, the screen times out after a period of inactivity,
-    // resulting in a non-user-initiated backgrounding.
-    NotifyAbort(ABORT_BACKGROUND, UserInitiatedInfo::NotUserInitiated(),
-                background_time_, true);
   }
   const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
   INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info);
@@ -459,10 +459,11 @@
 }
 
 void PageLoadTracker::FailedProvisionalLoad(
-    content::NavigationHandle* navigation_handle) {
+    content::NavigationHandle* navigation_handle,
+    base::TimeTicks failed_load_time) {
   DCHECK(!failed_provisional_load_info_);
   failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo(
-      base::TimeTicks::Now() - navigation_handle->NavigationStart(),
+      failed_load_time - navigation_handle->NavigationStart(),
       navigation_handle->GetNetErrorCode()));
 }
 
@@ -589,7 +590,7 @@
 PageLoadExtraInfo PageLoadTracker::ComputePageLoadExtraInfo() {
   base::Optional<base::TimeDelta> first_background_time;
   base::Optional<base::TimeDelta> first_foreground_time;
-  base::Optional<base::TimeDelta> time_to_abort;
+  base::Optional<base::TimeDelta> page_end_time;
 
   if (!background_time_.is_null()) {
     DCHECK_GE(background_time_, navigation_start_);
@@ -601,23 +602,23 @@
     first_foreground_time = foreground_time_ - navigation_start_;
   }
 
-  if (abort_type_ != ABORT_NONE) {
-    DCHECK_GE(abort_time_, navigation_start_);
-    time_to_abort = abort_time_ - navigation_start_;
+  if (page_end_reason_ != END_NONE) {
+    DCHECK_GE(page_end_time_, navigation_start_);
+    page_end_time = page_end_time_ - navigation_start_;
   } else {
-    DCHECK(abort_time_.is_null());
+    DCHECK(page_end_time_.is_null());
   }
 
-  // abort_type_ == ABORT_NONE implies abort_user_initiated_info_ is not user
-  // initiated.
-  DCHECK(abort_type_ != ABORT_NONE ||
-         (!abort_user_initiated_info_.browser_initiated &&
-          !abort_user_initiated_info_.user_gesture &&
-          !abort_user_initiated_info_.user_input_event));
+  // page_end_reason_ == END_NONE implies page_end_user_initiated_info_ is not
+  // user initiated.
+  DCHECK(page_end_reason_ != END_NONE ||
+         (!page_end_user_initiated_info_.browser_initiated &&
+          !page_end_user_initiated_info_.user_gesture &&
+          !page_end_user_initiated_info_.user_input_event));
   return PageLoadExtraInfo(
       first_background_time, first_foreground_time, started_in_foreground_,
-      user_initiated_info_, url(), start_url_, did_commit_, abort_type_,
-      abort_user_initiated_info_, time_to_abort, metadata_);
+      user_initiated_info_, url(), start_url_, did_commit_, page_end_reason_,
+      page_end_user_initiated_info_, page_end_time, metadata_);
 }
 
 bool PageLoadTracker::HasMatchingNavigationRequestID(
@@ -627,40 +628,43 @@
          navigation_request_id_.value() == request_id;
 }
 
-void PageLoadTracker::NotifyAbort(UserAbortType abort_type,
-                                  UserInitiatedInfo user_initiated_info,
-                                  base::TimeTicks timestamp,
-                                  bool is_certainly_browser_timestamp) {
-  DCHECK_NE(abort_type, ABORT_NONE);
-  // Use UpdateAbort to update an already notified PageLoadTracker.
-  if (abort_type_ != ABORT_NONE)
+void PageLoadTracker::NotifyPageEnd(PageEndReason page_end_reason,
+                                    UserInitiatedInfo user_initiated_info,
+                                    base::TimeTicks timestamp,
+                                    bool is_certainly_browser_timestamp) {
+  DCHECK_NE(page_end_reason, END_NONE);
+  // Use UpdatePageEnd to update an already notified PageLoadTracker.
+  if (page_end_reason_ != END_NONE)
     return;
 
-  UpdateAbortInternal(abort_type, user_initiated_info, timestamp,
-                      is_certainly_browser_timestamp);
+  UpdatePageEndInternal(page_end_reason, user_initiated_info, timestamp,
+                        is_certainly_browser_timestamp);
 }
 
-void PageLoadTracker::UpdateAbort(UserAbortType abort_type,
-                                  UserInitiatedInfo user_initiated_info,
-                                  base::TimeTicks timestamp,
-                                  bool is_certainly_browser_timestamp) {
-  DCHECK_NE(abort_type, ABORT_NONE);
-  DCHECK_NE(abort_type, ABORT_OTHER);
-  DCHECK_EQ(abort_type_, ABORT_OTHER);
+void PageLoadTracker::UpdatePageEnd(PageEndReason page_end_reason,
+                                    UserInitiatedInfo user_initiated_info,
+                                    base::TimeTicks timestamp,
+                                    bool is_certainly_browser_timestamp) {
+  DCHECK_NE(page_end_reason, END_NONE);
+  DCHECK_NE(page_end_reason, END_OTHER);
+  DCHECK_EQ(page_end_reason_, END_OTHER);
+  DCHECK(!page_end_time_.is_null());
+  if (page_end_time_.is_null() || page_end_reason_ != END_OTHER)
+    return;
 
   // For some aborts (e.g. navigations), the initiated timestamp can be earlier
   // than the timestamp that aborted the load. Taking the minimum gives the
   // closest user initiated time known.
-  UpdateAbortInternal(abort_type, user_initiated_info,
-                      std::min(abort_time_, timestamp),
-                      is_certainly_browser_timestamp);
+  UpdatePageEndInternal(page_end_reason, user_initiated_info,
+                        std::min(page_end_time_, timestamp),
+                        is_certainly_browser_timestamp);
 }
 
 bool PageLoadTracker::IsLikelyProvisionalAbort(
     base::TimeTicks abort_cause_time) const {
-  // Note that |abort_cause_time - abort_time| can be negative.
-  return abort_type_ == ABORT_OTHER &&
-         (abort_cause_time - abort_time_).InMilliseconds() < 100;
+  // Note that |abort_cause_time - page_end_time_| can be negative.
+  return page_end_reason_ == END_OTHER &&
+         (abort_cause_time - page_end_time_).InMilliseconds() < 100;
 }
 
 bool PageLoadTracker::MatchesOriginalNavigation(
@@ -671,10 +675,11 @@
   return navigation_handle->GetURL() == start_url_;
 }
 
-void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type,
-                                          UserInitiatedInfo user_initiated_info,
-                                          base::TimeTicks timestamp,
-                                          bool is_certainly_browser_timestamp) {
+void PageLoadTracker::UpdatePageEndInternal(
+    PageEndReason page_end_reason,
+    UserInitiatedInfo user_initiated_info,
+    base::TimeTicks timestamp,
+    bool is_certainly_browser_timestamp) {
   // When a provisional navigation commits, that navigation's start time is
   // interpreted as the abort time for other provisional loads in the tab.
   // However, this only makes sense if the committed load started after the
@@ -685,13 +690,13 @@
   // instead report the actual cause of an aborted navigation. See crbug/571647
   // for details.
   if (timestamp < navigation_start_) {
-    RecordInternalError(ERR_ABORT_BEFORE_NAVIGATION_START);
-    abort_type_ = ABORT_NONE;
-    abort_time_ = base::TimeTicks();
+    RecordInternalError(ERR_END_BEFORE_NAVIGATION_START);
+    page_end_reason_ = END_NONE;
+    page_end_time_ = base::TimeTicks();
     return;
   }
-  abort_type_ = abort_type;
-  abort_time_ = timestamp;
+  page_end_reason_ = page_end_reason;
+  page_end_time_ = timestamp;
   // A client redirect can never be user initiated. Due to the way Blink
   // implements user gesture tracking, where all events that occur within 1
   // second after a user interaction are considered to be triggered by user
@@ -700,11 +705,11 @@
   // these navs may sometimes be reported as user initiated by Blink. Thus, we
   // explicitly filter these types of aborts out when deciding if the abort was
   // user initiated.
-  if (abort_type != ABORT_CLIENT_REDIRECT)
-    abort_user_initiated_info_ = user_initiated_info;
+  if (page_end_reason != END_CLIENT_REDIRECT)
+    page_end_user_initiated_info_ = user_initiated_info;
 
   if (is_certainly_browser_timestamp) {
-    ClampBrowserTimestampIfInterProcessTimeTickSkew(&abort_time_);
+    ClampBrowserTimestampIfInterProcessTimeTickSkew(&page_end_time_);
   }
 }
 
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h
index ef782b2..c08628d 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.h
+++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -77,11 +77,11 @@
   // occur if the browser filters loads less aggressively than the renderer.
   ERR_NO_IPCS_RECEIVED,
 
-  // Tracks frequency with which we record an abort time that occurred before
+  // Tracks frequency with which we record an end time that occurred before
   // navigation start. This is expected to happen in some cases (see comments in
   // cc file for details). We use this error counter to understand how often it
   // happens.
-  ERR_ABORT_BEFORE_NAVIGATION_START,
+  ERR_END_BEFORE_NAVIGATION_START,
 
   // A new navigation triggers abort updates in multiple trackers in
   // |aborted_provisional_loads_|, when usually there should only be one (the
@@ -104,6 +104,9 @@
   // commit nor a failed provisional load.
   ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD,
 
+  // No page load end time was recorded for this page load.
+  ERR_NO_PAGE_LOAD_END_TIME,
+
   // Add values before this final count.
   ERR_LAST_ENTRY,
 };
@@ -112,7 +115,7 @@
 // metrics_web_contents_observer.cc. They are declared here to allow both files
 // to access them.
 void RecordInternalError(InternalErrorLoadEvent event);
-UserAbortType AbortTypeForPageTransition(ui::PageTransition transition);
+PageEndReason EndReasonForPageTransition(ui::PageTransition transition);
 void LogAbortChainSameURLHistogram(int aborted_chain_size_same_url);
 bool IsNavigationUserInitiated(content::NavigationHandle* handle);
 
@@ -138,7 +141,8 @@
   void WillProcessNavigationResponse(
       content::NavigationHandle* navigation_handle);
   void Commit(content::NavigationHandle* navigation_handle);
-  void FailedProvisionalLoad(content::NavigationHandle* navigation_handle);
+  void FailedProvisionalLoad(content::NavigationHandle* navigation_handle,
+                             base::TimeTicks failed_load_time);
   void WebContentsHidden();
   void WebContentsShown();
 
@@ -168,8 +172,8 @@
     return aborted_chain_size_same_url_;
   }
 
-  UserAbortType abort_type() const { return abort_type_; }
-  base::TimeTicks abort_time() const { return abort_time_; }
+  PageEndReason page_end_reason() const { return page_end_reason_; }
+  base::TimeTicks page_end_time() const { return page_end_time_; }
 
   void AddObserver(std::unique_ptr<PageLoadMetricsObserver> observer);
 
@@ -180,19 +184,19 @@
   // in the
   // browser process or not. We need this to possibly clamp browser timestamp on
   // a machine with inter process time tick skew.
-  void NotifyAbort(UserAbortType abort_type,
-                   UserInitiatedInfo user_initiated_info,
-                   base::TimeTicks timestamp,
-                   bool is_certainly_browser_timestamp);
-  void UpdateAbort(UserAbortType abort_type,
-                   UserInitiatedInfo user_initiated_info,
-                   base::TimeTicks timestamp,
-                   bool is_certainly_browser_timestamp);
+  void NotifyPageEnd(PageEndReason page_end_reason,
+                     UserInitiatedInfo user_initiated_info,
+                     base::TimeTicks timestamp,
+                     bool is_certainly_browser_timestamp);
+  void UpdatePageEnd(PageEndReason page_end_reason,
+                     UserInitiatedInfo user_initiated_info,
+                     base::TimeTicks timestamp,
+                     bool is_certainly_browser_timestamp);
 
   // This method returns true if this page load has been aborted with type of
-  // ABORT_OTHER, and the |abort_cause_time| is within a sufficiently close
+  // END_OTHER, and the |abort_cause_time| is within a sufficiently close
   // delta to when it was aborted. Note that only provisional loads can be
-  // aborted with ABORT_OTHER. While this heuristic is coarse, it works better
+  // aborted with END_OTHER. While this heuristic is coarse, it works better
   // and is simpler than other feasible methods. See https://goo.gl/WKRG98.
   bool IsLikelyProvisionalAbort(base::TimeTicks abort_cause_time) const;
 
@@ -228,10 +232,10 @@
   void ClampBrowserTimestampIfInterProcessTimeTickSkew(
       base::TimeTicks* event_time);
 
-  void UpdateAbortInternal(UserAbortType abort_type,
-                           UserInitiatedInfo user_initiated_info,
-                           base::TimeTicks timestamp,
-                           bool is_certainly_browser_timestamp);
+  void UpdatePageEndInternal(PageEndReason page_end_reason,
+                             UserInitiatedInfo user_initiated_info,
+                             base::TimeTicks timestamp,
+                             bool is_certainly_browser_timestamp);
 
   // If |final_navigation| is null, then this is an "unparented" abort chain,
   // and represents a sequence of provisional aborts that never ends with a
@@ -266,21 +270,21 @@
 
   std::unique_ptr<FailedProvisionalLoadInfo> failed_provisional_load_info_;
 
-  // Will be ABORT_NONE if we have not aborted this load yet. Otherwise will
-  // be the first abort action the user performed.
-  UserAbortType abort_type_;
+  // Will be END_NONE if we have not ended this load yet. Otherwise will
+  // be the first page end reason encountered.
+  PageEndReason page_end_reason_;
 
-  // Whether the abort for this page load was user initiated. For example, if
-  // this page load was aborted by a new navigation, this field tracks whether
-  // that new navigation was user-initiated. This field is only useful if this
-  // page load's abort type is a value other than ABORT_NONE. Note that this
-  // value is currently experimental, and is subject to change. In particular,
-  // this field is never set to true for some abort types, such as stop and
-  // close, since we don't yet have sufficient instrumentation to know if a stop
-  // or close was caused by a user action.
-  UserInitiatedInfo abort_user_initiated_info_;
+  // Whether the page end cause for this page load was user initiated. For
+  // example, if this page load was ended by a new navigation, this field tracks
+  // whether that new navigation was user-initiated. This field is only useful
+  // if this page load's end reason is a value other than END_NONE. Note that
+  // this value is currently experimental, and is subject to change. In
+  // particular, this field is never set to true for some page end reasons, such
+  // as stop and close, since we don't yet have sufficient instrumentation to
+  // know if a stop or close was caused by a user action.
+  UserInitiatedInfo page_end_user_initiated_info_;
 
-  base::TimeTicks abort_time_;
+  base::TimeTicks page_end_time_;
 
   // We record separate metrics for events that occur after a background,
   // because metrics like layout/paint are delayed artificially
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 7452c2d..607b9a2 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -67,6 +67,27 @@
 
 namespace {
 
+// Fixture with the Form-Not-Secure in-field warning feature enabled.
+class PasswordManagerBrowserTestWarning
+    : public PasswordManagerBrowserTestBase {
+ public:
+  PasswordManagerBrowserTestWarning() {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // We need to set the feature state before the render process is created,
+    // in order for it to inherit the feature state from the browser process.
+    // SetUp() runs too early, and SetUpOnMainThread() runs too late.
+    scoped_feature_list_.InitAndEnableFeature(
+        security_state::kHttpFormWarningFeature);
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTestWarning);
+};
+
 class MockLoginModelObserver : public password_manager::LoginModelObserver {
  public:
   MOCK_METHOD2(OnAutofillDataAvailableInternal,
@@ -1828,111 +1849,6 @@
   observing_autofill_client->Wait();
 }
 
-// Flaky on official builds (?): https://crbug.com/693717
-IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       DISABLED_ShowFormNotSecureOnUsernameField) {
-  password_manager::ContentPasswordManagerDriverFactory* driver_factory =
-      password_manager::ContentPasswordManagerDriverFactory::FromWebContents(
-          WebContents());
-  ObservingAutofillClient::CreateForWebContents(WebContents());
-  ObservingAutofillClient* observing_autofill_client =
-      ObservingAutofillClient::FromWebContents(WebContents());
-  password_manager::ContentPasswordManagerDriver* driver =
-      driver_factory->GetDriverForFrame(RenderViewHost()->GetMainFrame());
-  DCHECK(driver);
-  driver->GetPasswordAutofillManager()->set_autofill_client(
-      observing_autofill_client);
-
-  // We need to serve from a non-localhost context for the form to be treated as
-  // Not Secure.
-  host_resolver()->AddRule("example.com", "127.0.0.1");
-  NavigationObserver observer(WebContents());
-  ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(
-                     "example.com", "/password/password_form.html"));
-  observer.Wait();
-
-  ASSERT_TRUE(content::ExecuteScript(
-      RenderViewHost(),
-      "var inputRect = document.getElementById('username_field_no_name')"
-      ".getBoundingClientRect();"));
-
-  // Click on the username field to verify the warning is shown.
-  int top;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
-      RenderViewHost(), "window.domAutomationController.send(inputRect.top);",
-      &top));
-  int left;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
-      RenderViewHost(), "window.domAutomationController.send(inputRect.left);",
-      &left));
-
-  const char kHistogram[] =
-      "PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation";
-  base::HistogramTester histograms;
-
-  content::SimulateMouseClickAt(WebContents(), 0,
-                                blink::WebMouseEvent::Button::Left,
-                                gfx::Point(left + 1, top + 1));
-  // Ensure the warning would be shown.
-  observing_autofill_client->Wait();
-  // Ensure the histogram was updated.
-  histograms.ExpectUniqueSample(kHistogram, true, 1);
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       DoNotShowFormNotSecureOnUnrelatedField) {
-  password_manager::ContentPasswordManagerDriverFactory* driver_factory =
-      password_manager::ContentPasswordManagerDriverFactory::FromWebContents(
-          WebContents());
-  ObservingAutofillClient::CreateForWebContents(WebContents());
-  ObservingAutofillClient* observing_autofill_client =
-      ObservingAutofillClient::FromWebContents(WebContents());
-  password_manager::ContentPasswordManagerDriver* driver =
-      driver_factory->GetDriverForFrame(RenderViewHost()->GetMainFrame());
-  DCHECK(driver);
-  driver->GetPasswordAutofillManager()->set_autofill_client(
-      observing_autofill_client);
-
-  // We need to serve from a non-localhost context for the form to be treated as
-  // Not Secure.
-  host_resolver()->AddRule("example.com", "127.0.0.1");
-  NavigationObserver observer(WebContents());
-  ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(
-                     "example.com", "/password/password_form.html"));
-  observer.Wait();
-
-  ASSERT_TRUE(content::ExecuteScript(
-      RenderViewHost(),
-      "var inputRect = document.getElementById('ef_extra')"
-      ".getBoundingClientRect();"));
-
-  // Click on the non-username text field.
-  int top;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
-      RenderViewHost(), "window.domAutomationController.send(inputRect.top);",
-      &top));
-  int left;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
-      RenderViewHost(), "window.domAutomationController.send(inputRect.left);",
-      &left));
-
-  const char kHistogram[] =
-      "PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation";
-  base::HistogramTester histograms;
-
-  content::SimulateMouseClickAt(WebContents(), 0,
-                                blink::WebMouseEvent::Button::Left,
-                                gfx::Point(left + 1, top + 1));
-  // Force a round-trip.
-  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "var noop = 'noop';"));
-  // Ensure the warning was not triggered.
-  ASSERT_FALSE(observing_autofill_client->DidPopupAppear());
-  // Ensure the histogram remains empty.
-  histograms.ExpectTotalCount(kHistogram, 0);
-}
-
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
                        ChangePwdFormBubbleShown) {
   NavigateToFile("/password/password_form.html");
@@ -3333,4 +3249,116 @@
                                   TabStripModel::ADD_ACTIVE);
 }
 
+// Verify the Form-Not-Secure warning is shown on a non-secure username field.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestWarning,
+                       ShowFormNotSecureOnUsernameField) {
+  ASSERT_TRUE(
+      base::FeatureList::IsEnabled(security_state::kHttpFormWarningFeature));
+
+  password_manager::ContentPasswordManagerDriverFactory* driver_factory =
+      password_manager::ContentPasswordManagerDriverFactory::FromWebContents(
+          WebContents());
+  ObservingAutofillClient::CreateForWebContents(WebContents());
+  ObservingAutofillClient* observing_autofill_client =
+      ObservingAutofillClient::FromWebContents(WebContents());
+  password_manager::ContentPasswordManagerDriver* driver =
+      driver_factory->GetDriverForFrame(RenderViewHost()->GetMainFrame());
+  DCHECK(driver);
+  driver->GetPasswordAutofillManager()->set_autofill_client(
+      observing_autofill_client);
+
+  // We need to serve from a non-localhost context for the form to be treated as
+  // Not Secure.
+  host_resolver()->AddRule("example.com", "127.0.0.1");
+  NavigationObserver observer(WebContents());
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL(
+                     "example.com", "/password/password_form.html"));
+  observer.Wait();
+
+  ASSERT_TRUE(content::ExecuteScript(
+      RenderViewHost(),
+      "var inputRect = document.getElementById('username_field_no_name')"
+      ".getBoundingClientRect();"));
+
+  // Click on the username field to verify the warning is shown.
+  int top;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      RenderViewHost(), "window.domAutomationController.send(inputRect.top);",
+      &top));
+  int left;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      RenderViewHost(), "window.domAutomationController.send(inputRect.left);",
+      &left));
+
+  const char kHistogram[] =
+      "PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation";
+  base::HistogramTester histograms;
+
+  content::SimulateMouseClickAt(WebContents(), 0,
+                                blink::WebMouseEvent::Button::Left,
+                                gfx::Point(left + 1, top + 1));
+  // Ensure the warning would be shown.
+  observing_autofill_client->Wait();
+  // Ensure the histogram was updated.
+  histograms.ExpectUniqueSample(kHistogram, true, 1);
+}
+
+// Verify the Form-Not-Secure warning is not shown on a non-credential field.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestWarning,
+                       DoNotShowFormNotSecureOnUnrelatedField) {
+  ASSERT_TRUE(
+      base::FeatureList::IsEnabled(security_state::kHttpFormWarningFeature));
+
+  password_manager::ContentPasswordManagerDriverFactory* driver_factory =
+      password_manager::ContentPasswordManagerDriverFactory::FromWebContents(
+          WebContents());
+  ObservingAutofillClient::CreateForWebContents(WebContents());
+  ObservingAutofillClient* observing_autofill_client =
+      ObservingAutofillClient::FromWebContents(WebContents());
+  password_manager::ContentPasswordManagerDriver* driver =
+      driver_factory->GetDriverForFrame(RenderViewHost()->GetMainFrame());
+  DCHECK(driver);
+  driver->GetPasswordAutofillManager()->set_autofill_client(
+      observing_autofill_client);
+
+  // We need to serve from a non-localhost context for the form to be treated as
+  // Not Secure.
+  host_resolver()->AddRule("example.com", "127.0.0.1");
+  NavigationObserver observer(WebContents());
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL(
+                     "example.com", "/password/password_form.html"));
+  observer.Wait();
+
+  ASSERT_TRUE(content::ExecuteScript(
+      RenderViewHost(),
+      "var inputRect = document.getElementById('ef_extra')"
+      ".getBoundingClientRect();"));
+
+  // Click on the non-username text field.
+  int top;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      RenderViewHost(), "window.domAutomationController.send(inputRect.top);",
+      &top));
+  int left;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      RenderViewHost(), "window.domAutomationController.send(inputRect.left);",
+      &left));
+
+  const char kHistogram[] =
+      "PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation";
+  base::HistogramTester histograms;
+
+  content::SimulateMouseClickAt(WebContents(), 0,
+                                blink::WebMouseEvent::Button::Left,
+                                gfx::Point(left + 1, top + 1));
+  // Force a round-trip.
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "var noop = 'noop';"));
+  // Ensure the warning was not triggered.
+  ASSERT_FALSE(observing_autofill_client->DidPopupAppear());
+  // Ensure the histogram remains empty.
+  histograms.ExpectTotalCount(kHistogram, 0);
+}
+
 }  // namespace password_manager
diff --git a/chrome/browser/power/OWNERS b/chrome/browser/power/OWNERS
deleted file mode 100644
index 76a50a4..0000000
--- a/chrome/browser/power/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-derat@chromium.org
-dhnishi@chromium.org
-sivachandra@chromium.org
diff --git a/chrome/browser/prefs/preferences_connection_manager.cc b/chrome/browser/prefs/preferences_connection_manager.cc
index f87f1e865..c2ca9214 100644
--- a/chrome/browser/prefs/preferences_connection_manager.cc
+++ b/chrome/browser/prefs/preferences_connection_manager.cc
@@ -43,26 +43,9 @@
 
 PreferencesConnectionManager::~PreferencesConnectionManager() {}
 
-void PreferencesConnectionManager::OnConnectionError(
-    mojo::StrongBindingPtr<prefs::mojom::PreferencesService> binding) {
-  if (!binding)
-    return;
-  for (auto it = manager_bindings_.begin(); it != manager_bindings_.end();
-       ++it) {
-    if (it->get() == binding.get()) {
-      manager_bindings_.erase(it);
-      return;
-    }
-  }
-}
-
 void PreferencesConnectionManager::OnProfileDestroyed() {
-  for (auto& it : manager_bindings_) {
-    // Shutdown any PreferenceManager that is still alive.
-    if (it)
-      it->Close();
-  }
-
+  // Shutdown any PreferenceService that is still alive.
+  manager_bindings_.CloseAllBindings();
   profile_shutdown_notification_.reset();
 }
 
@@ -74,16 +57,10 @@
   if (!g_browser_process->profile_manager()->GetNumberOfProfiles())
     return;
 
-  Profile* profile = ProfileManager::GetActiveUserProfile();
-  mojo::StrongBindingPtr<prefs::mojom::PreferencesService> binding =
-      mojo::MakeStrongBinding(
-          base::MakeUnique<PreferencesService>(std::move(client), profile),
-          std::move(service));
-  // Copying the base::WeakPtr for future deletion.
-  binding->set_connection_error_handler(
-      base::Bind(&PreferencesConnectionManager::OnConnectionError,
-                 base::Unretained(this), binding));
-  manager_bindings_.push_back(std::move(binding));
+  manager_bindings_.AddBinding(
+      base::MakeUnique<PreferencesService>(
+          std::move(client), ProfileManager::GetActiveUserProfile()),
+      std::move(service));
 }
 
 void PreferencesConnectionManager::Create(
@@ -101,13 +78,6 @@
   }
 }
 
-void PreferencesConnectionManager::OnStart() {
-  // Certain tests have no profiles to connect to, and static initializers
-  // which block the creation of test profiles.
-  if (!g_browser_process->profile_manager()->GetNumberOfProfiles())
-    return;
-}
-
 bool PreferencesConnectionManager::OnConnect(
     const service_manager::ServiceInfo& remote_info,
     service_manager::InterfaceRegistry* registry) {
diff --git a/chrome/browser/prefs/preferences_connection_manager.h b/chrome/browser/prefs/preferences_connection_manager.h
index d0cc1d55..b0f14759 100644
--- a/chrome/browser/prefs/preferences_connection_manager.h
+++ b/chrome/browser/prefs/preferences_connection_manager.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/service.h"
@@ -33,10 +33,6 @@
   ~PreferencesConnectionManager() override;
 
  private:
-  // mojo::StrongBinding callback:
-  void OnConnectionError(
-      mojo::StrongBindingPtr<prefs::mojom::PreferencesService> binding);
-
   // KeyedServiceShutdownNotifier::Subscription callback. Used to cleanup when
   // the active PrefService is being destroyed.
   void OnProfileDestroyed();
@@ -50,15 +46,13 @@
               prefs::mojom::PreferencesServiceFactoryRequest request) override;
 
   // service_manager::Service:
-  void OnStart() override;
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) override;
 
   mojo::BindingSet<prefs::mojom::PreferencesServiceFactory> factory_bindings_;
 
   // Bindings that automatically cleanup during connection errors.
-  std::vector<mojo::StrongBindingPtr<prefs::mojom::PreferencesService>>
-      manager_bindings_;
+  mojo::StrongBindingSet<prefs::mojom::PreferencesService> manager_bindings_;
 
   // Observes shutdown, when PrefService is being destroyed.
   std::unique_ptr<KeyedServiceShutdownNotifier::Subscription>
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 262706d..df20cd02 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -544,7 +544,7 @@
   return page_load_metrics::PageLoadExtraInfo(
       base::TimeDelta(), base::TimeDelta(), false,
       page_load_metrics::UserInitiatedInfo::BrowserInitiated(), dest_url,
-      dest_url, true /* did_commit */, page_load_metrics::ABORT_NONE,
+      dest_url, true /* did_commit */, page_load_metrics::END_NONE,
       page_load_metrics::UserInitiatedInfo::NotUserInitiated(),
       base::TimeDelta(), page_load_metrics::PageLoadMetadata());
 }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel_menu.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel_menu.js
index 0520f34..b4b3f5c4 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel_menu.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/panel_menu.js
@@ -217,9 +217,13 @@
    * Handles key presses for first letter accelerators.
    */
   onKeyPress_: function(evt) {
-    var query = String.fromCharCode(evt.charCode).toLowerCase();
+    if (!this.items_.length)
+      return;
 
-    for (var i = this.activeIndex_ + 1; i < this.items_.length; i++) {
+    var query = String.fromCharCode(evt.charCode).toLowerCase();
+    for (var i = this.activeIndex_ + 1;
+         i != this.activeIndex_;
+         i = (i + 1) % this.items_.length) {
       if (this.items_[i].text.toLowerCase().indexOf(query) == 0) {
         this.activateItem(i);
         break;
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index 182ae144..adfa836 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -177,6 +177,7 @@
     // appropriately.
     this.async(function() {
       this.$.networkSelect.refreshNetworks();
+      this.$.networkSelect.focus();
     }.bind(this));
   },
 
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui.css b/chrome/browser/resources/vr_shell/vr_shell_ui.css
index c89f16f..aae8654 100644
--- a/chrome/browser/resources/vr_shell/vr_shell_ui.css
+++ b/chrome/browser/resources/vr_shell/vr_shell_ui.css
@@ -8,10 +8,10 @@
 
 #ui {
   left: 0;
-  max-width: 1920px;
   position: absolute;
   top: 0;
   transform-origin: left top;
+  width: 1920px;
 }
 
 /* This class manages the position of elements on the texture page.
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui.js b/chrome/browser/resources/vr_shell/vr_shell_ui.js
index 2fd4a7a..12c5f8c 100644
--- a/chrome/browser/resources/vr_shell/vr_shell_ui.js
+++ b/chrome/browser/resources/vr_shell/vr_shell_ui.js
@@ -711,7 +711,6 @@
       /** @const */ var TAB_CONTAINER_Y_OFFSET = 0.4;
       /** @const */ var TAB_CONTAINER_Z_OFFSET = -1;
 
-      this.tabs = {};
       this.domTabs = {};
       this.contentQuadId = contentQuadId;
       this.domTabTemplate = document.querySelector(DOM_TAB_TEMPLATE_SELECTOR);
@@ -734,10 +733,6 @@
           parseInt(domTabStyle.marginRight, 10);
     }
 
-    getQualifiedTabId(tab) {
-      return (tab.incognito ? 'i' : 'n') + tab.id;
-    }
-
     makeDomTab(tab) {
       // Make a copy of the template tab and add this copy to the tab container
       // view.
@@ -748,14 +743,14 @@
       });
       domTab.tab = tab;
       this.domTabClip.appendChild(domTab);
-      this.domTabs[this.getQualifiedTabId(tab)] = domTab;
+      this.domTabs[tab.id] = domTab;
       return domTab;
     }
 
     resizeClipElement() {
       // Resize clip element so that scrolling works.
       this.domTabClip.style.width =
-          (Object.keys(this.tabs).length * this.domTabWidth) + 'px';
+          (Object.keys(this.domTabs).length * this.domTabWidth) + 'px';
     }
 
     setTabs(tabs) {
@@ -763,7 +758,7 @@
       while (this.domTabClip.firstChild) {
         this.domTabClip.removeChild(this.domTabClip.firstChild);
       }
-      this.tabs = {};
+      this.domTabs = {};
 
       // Add new tabs.
       for (let i = 0; i < tabs.length; i++) {
@@ -772,18 +767,17 @@
     }
 
     hasTab(tab) {
-      return this.getQualifiedTabId(tab) in this.tabs;
+      return tab.id in this.domTabs;
     }
 
     addTab(tab) {
-      this.tabs[this.getQualifiedTabId(tab)] = tab;
       this.makeDomTab(tab);
       this.updateTab(tab);
       this.resizeClipElement();
     }
 
     updateTab(tab) {
-      let domTab = this.domTabs[this.getQualifiedTabId(tab)];
+      let domTab = this.domTabs[tab.id];
       domTab.textContent = tab.title;
       domTab.classList.remove('tab-incognito');
       if (tab.incognito) {
@@ -792,11 +786,10 @@
     }
 
     removeTab(tab) {
-      let qualifiedTabId = this.getQualifiedTabId(tab);
+      let qualifiedTabId = tab.id;
       let domTab = this.domTabs[qualifiedTabId];
       delete this.domTabs[qualifiedTabId];
       this.domTabClip.removeChild(domTab);
-      delete this.tabs[qualifiedTabId];
       this.resizeClipElement();
     }
 
@@ -946,7 +939,7 @@
 
     /** @override */
     onSetTabs(tabs) {
-      uiManager.tabContainer.setTabs(tabs)
+      uiManager.tabContainer.setTabs(tabs);
     }
 
     /** @override */
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui_api.js b/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
index 751372d..14cf808 100644
--- a/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
+++ b/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
@@ -129,6 +129,10 @@
   'CONTENT': 4
 };
 
+/**
+ * Abstract fill base class.
+ * @abstract
+ */
 api.Fill = class {
   constructor(type) {
     this.properties = {};
@@ -348,13 +352,63 @@
  * @enum {number}
  * @const
  */
-api.Easing = {
+api.EasingType = {
   'LINEAR': 0,
   'CUBICBEZIER': 1,
   'EASEIN': 2,
   'EASEOUT': 3
 };
 
+/** @const */ var DEFAULT_EASING_POW = 2;
+/** @const */ var DEFAULT_CUBIC_BEZIER_P1X = 0.25;
+/** @const */ var DEFAULT_CUBIC_BEZIER_P1Y = 0;
+/** @const */ var DEFAULT_CUBIC_BEZIER_P2X = 0.75;
+/** @const */ var DEFAULT_CUBIC_BEZIER_P2Y = 1;
+
+/**
+ * Abstract easing base class.
+ * @abstract
+ */
+api.Easing = class {
+  constructor(type) {
+    this.type = type;
+  }
+}
+
+api.LinearEasing = class extends api.Easing {
+  constructor() {
+    super(api.EasingType.LINEAR);
+  }
+}
+
+api.CubicBezierEasing = class extends api.Easing {
+  constructor(
+      p1x = DEFAULT_CUBIC_BEZIER_P1X,
+      p1y = DEFAULT_CUBIC_BEZIER_P1Y,
+      p2x = DEFAULT_CUBIC_BEZIER_P2X,
+      p2y = DEFAULT_CUBIC_BEZIER_P2Y) {
+    super(api.EasingType.CUBICBEZIER);
+    this.p1x = p1x;
+    this.p1y = p1y;
+    this.p2x = p2x;
+    this.p2y = p2y;
+  }
+}
+
+api.InEasing = class extends api.Easing {
+  constructor(pow = DEFAULT_EASING_POW) {
+    super(api.EasingType.EASEIN);
+    this.pow = pow;
+  }
+}
+
+api.OutEasing = class extends api.Easing {
+  constructor(pow = DEFAULT_EASING_POW) {
+    super(api.EasingType.EASEOUT);
+    this.pow = pow;
+  }
+}
+
 /**
  * Base animation class. An animation can vary only one object property.
  * @struct
@@ -370,7 +424,7 @@
     /** @private {Object} */
     this.to = {};
     /** @private {Object} */
-    this.easing = {};
+    this.easing = new api.LinearEasing();
 
     // How many milliseconds in the future to start the animation.
     /** @private {number} */
@@ -379,8 +433,6 @@
     // Duration of the animation (milliseconds).
     /** @private {number} */
     this.durationMillis = durationMs;
-
-    this.easing.type = api.Easing.LINEAR;
   }
 
   /**
@@ -451,11 +503,20 @@
     this.property = api.Property.OPACITY;
     this.to.x = opacity;
   }
+
+  /**
+   * Set the animation's easing.
+   * @param {api.Easing} easing
+   */
+  setEasing(easing) {
+    this.easing = easing;
+  }
 };
 
 /**
  * Abstract class handling webui command calls from native.  The UI must
  * subclass this and override the handlers.
+ * @abstract
  */
 api.NativeCommandHandler = class {
   /**
@@ -581,7 +642,7 @@
       this.onSetTabs(dict['setTabs']);
     }
     if ('updateTab' in dict) {
-      this.onUpdateTab(dict['updateTabs']);
+      this.onUpdateTab(dict['updateTab']);
     }
     if ('removeTab' in dict) {
       this.onRemoveTab(dict['removeTab']);
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
index 9724eae2..04b77aa 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -30,6 +30,7 @@
 #include "components/safe_browsing_db/test_database_manager.h"
 #include "components/safe_browsing_db/util.h"
 #include "components/security_interstitials/content/unsafe_resource.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
 #include "components/subresource_filter/core/common/activation_level.h"
@@ -190,6 +191,8 @@
 using subresource_filter::testing::TestRulesetPublisher;
 using subresource_filter::testing::TestRulesetCreator;
 using subresource_filter::testing::TestRulesetPair;
+using ActivationDecision =
+    ContentSubresourceFilterDriverFactory::ActivationDecision;
 
 // SubresourceFilterDisabledBrowserTest ---------------------------------------
 
@@ -767,6 +770,8 @@
   ConfigureAsPhishingURL(url);
   ASSERT_NO_FATAL_FAILURE(
       SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+
+  base::HistogramTester tester;
   ui_test_utils::NavigateToURL(browser(), url);
   EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
 
@@ -776,6 +781,18 @@
   chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
   observer.Wait();
   EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecision, 2);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::ACTIVATED), 2);
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload, 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload,
+      static_cast<int>(ActivationDecision::ACTIVATED), 1);
 }
 
 IN_PROC_BROWSER_TEST_F(SubresourceFilterWhitelistSiteOnReloadBrowserTest,
@@ -784,6 +801,8 @@
   ConfigureAsPhishingURL(url);
   ASSERT_NO_FATAL_FAILURE(
       SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+
+  base::HistogramTester tester;
   ui_test_utils::NavigateToURL(browser(), url);
   EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
 
@@ -793,6 +812,21 @@
   chrome::Reload(browser(), WindowOpenDisposition::CURRENT_TAB);
   observer.Wait();
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecision, 2);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::ACTIVATED), 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload, 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload,
+      static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
 }
 
 IN_PROC_BROWSER_TEST_F(SubresourceFilterWhitelistSiteOnReloadBrowserTest,
@@ -801,6 +835,8 @@
   ConfigureAsPhishingURL(url);
   ASSERT_NO_FATAL_FAILURE(
       SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+
+  base::HistogramTester tester;
   ui_test_utils::NavigateToURL(browser(), url);
   EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
 
@@ -812,6 +848,21 @@
       "location.reload();"));
   observer.Wait();
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecision, 2);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::ACTIVATED), 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload, 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload,
+      static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
 }
 
 IN_PROC_BROWSER_TEST_F(SubresourceFilterWhitelistSiteOnReloadBrowserTest,
@@ -820,6 +871,8 @@
   ConfigureAsPhishingURL(url);
   ASSERT_NO_FATAL_FAILURE(
       SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+
+  base::HistogramTester tester;
   ui_test_utils::NavigateToURL(browser(), url);
   EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
 
@@ -831,6 +884,21 @@
       browser()->tab_strip_model()->GetActiveWebContents(), nav_frame_script));
   observer.Wait();
   EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecision, 2);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::ACTIVATED), 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecision,
+      static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
+
+  tester.ExpectTotalCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload, 1);
+  tester.ExpectBucketCount(
+      internal::kHistogramSubresourceFilterActivationDecisionReload,
+      static_cast<int>(ActivationDecision::URL_WHITELISTED), 1);
 }
 
 }  // namespace subresource_filter
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
index 08ec1b5..69c51bc 100644
--- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -20,6 +20,10 @@
 #include "components/sync/test/fake_server/fake_server_verifier.h"
 #include "components/sync/test/fake_server/sessions_hierarchy.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/chromeos_switches.h"
+#endif
+
 using base::HistogramBase;
 using base::HistogramSamples;
 using base::HistogramTester;
@@ -66,6 +70,15 @@
 
     if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride))
       cl->AppendSwitch(switches::kSyncShortInitialRetryOverride);
+
+#if defined(OS_CHROMEOS)
+    // kIgnoreUserProfileMappingForTests will let UserManager always return
+    // active user. If this switch is not set, sync test's profile will not
+    // match UserManager's active user, then UserManager won't return active
+    // user to our tests.
+    if (!cl->HasSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests))
+      cl->AppendSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests);
+#endif
   }
 
  private:
diff --git a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
index bbc3204..7457bc1 100644
--- a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
@@ -201,6 +201,13 @@
     ProfileSyncServiceFactory::SetSyncClientFactoryForTest(
         &sync_client_factory_);
     ProfileSyncComponentsFactoryImpl::OverridePrefsForUssTest(true);
+    // The test infra creates a profile before the two made for sync tests.
+    number_of_clients_ignored_ = 1;
+#if defined(OS_CHROMEOS)
+    // ChromeOS will force loading a signin profile, so we need to ingore one
+    // more client.
+    ++number_of_clients_ignored_;
+#endif
   }
 
   ~TwoClientUssSyncTest() override {
@@ -216,9 +223,8 @@
 
  protected:
   std::unique_ptr<syncer::SyncClient> CreateSyncClient(Profile* profile) {
-    if (!first_client_ignored_) {
-      // The test infra creates a profile before the two made for sync tests.
-      first_client_ignored_ = true;
+    if (number_of_clients_ignored_ > 0) {
+      --number_of_clients_ignored_;
       return base::MakeUnique<ChromeSyncClient>(profile);
     }
     auto bridge = base::MakeUnique<TestModelTypeSyncBridge>();
@@ -231,7 +237,7 @@
   ProfileSyncServiceFactory::SyncClientFactory sync_client_factory_;
   std::vector<std::unique_ptr<TestModelTypeSyncBridge>> bridges_;
   std::vector<TestSyncClient*> clients_;
-  bool first_client_ignored_ = false;
+  size_t number_of_clients_ignored_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TwoClientUssSyncTest);
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index e1f40f7..a124ccbb 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -251,7 +251,12 @@
   void StateChanged(ButtonState old_state) override {
     LabelButton::StateChanged(old_state);
 
-    views::Label* title = title_ ? title_ : label();
+    auto set_title_color = [&](SkColor color) {
+      if (title_)
+        title_->SetEnabledColor(color);
+      else
+        SetEnabledTextColors(color);
+    };
 
     bool was_prelight =
         old_state == STATE_HOVERED || old_state == STATE_PRESSED;
@@ -260,7 +265,7 @@
       // The pointer is no longer over this button.  Set the
       // background and text colors back to their normal states.
       set_background(nullptr);
-      title->SetEnabledColor(normal_title_color_);
+      set_title_color(normal_title_color_);
       if (subtitle_)
         subtitle_->SetDisabledColor(normal_subtitle_color_);
     } else if (!was_prelight && is_prelight) {
@@ -274,12 +279,11 @@
         // When using the system (GTK) theme, use the selected menuitem colors.
         bg_color = GetNativeTheme()->GetSystemColor(
             ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor);
-        title->SetEnabledColor(GetNativeTheme()->GetSystemColor(
-            ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor));
-        if (subtitle_) {
-          subtitle_->SetDisabledColor(GetNativeTheme()->GetSystemColor(
-              ui::NativeTheme::kColorId_MenuItemSubtitleColor));
-        }
+        SkColor text_color = GetNativeTheme()->GetSystemColor(
+            ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor);
+        set_title_color(text_color);
+        if (subtitle_)
+          subtitle_->SetDisabledColor(text_color);
       }
 #endif
       set_background(views::Background::CreateSolidBackground(bg_color));
@@ -1756,6 +1760,7 @@
   views::Label* current_profile_name = new views::Label(
       profiles::GetAvatarNameForProfile(browser_->profile()->GetPath()));
   current_profile_card->set_title(current_profile_name);
+  current_profile_name->SetAutoColorReadabilityEnabled(false);
   current_profile_name->SetFontList(
       ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
           1, gfx::Font::FontStyle::NORMAL, gfx::Font::Weight::MEDIUM));
@@ -1806,6 +1811,7 @@
     } else {
       views::Label* email_label = new views::Label(avatar_item.username);
       current_profile_card->set_subtitle(email_label);
+      email_label->SetAutoColorReadabilityEnabled(false);
       email_label->SetElideBehavior(gfx::ELIDE_EMAIL);
       email_label->SetEnabled(false);
       email_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index e57c9a8..937dee5 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -241,9 +241,6 @@
     // Temporary for https://crbug.com/612711.
     { "aci_wrong_sp_extension_id", kSmallSize },
 
-    // Temporary for https://crbug.com/616149.
-    { "existing_extension_pref_value_type", crash_keys::kSmallSize },
-
     // Temporary for https://crbug.com/668633.
     { "swdh_set_hosted_version_worker_pid", crash_keys::kSmallSize },
     { "swdh_set_hosted_version_host_pid", crash_keys::kSmallSize },
diff --git a/chrome/common/extensions/api/extension.json b/chrome/common/extensions/api/extension.json
index 9b7b95a1..2c706e0 100644
--- a/chrome/common/extensions/api/extension.json
+++ b/chrome/common/extensions/api/extension.json
@@ -13,6 +13,7 @@
       "lastError": {
         "type": "object",
         "optional": true,
+        "deprecated": "Please use $(ref:runtime.lastError).",
         "description": "Set for the lifetime of a callback if an ansychronous extension api has resulted in an error. If no error has occured lastError will be <var>undefined</var>.",
         "properties": {
           "message": { "type": "string", "description": "Description of the error that has taken place." }
@@ -59,6 +60,7 @@
       },
       {
         "name": "getURL",
+        "deprecated": "Please use $(ref:runtime.getURL).",
         "nocompile": true,
         "type": "function",
         "description": "Converts a relative path within an extension install directory to a fully-qualified URL.",
diff --git a/chrome/installer/linux/debian/expected_deps_x64_jessie b/chrome/installer/linux/debian/expected_deps_x64_jessie
index ab8362a..ce5804d 100644
--- a/chrome/installer/linux/debian/expected_deps_x64_jessie
+++ b/chrome/installer/linux/debian/expected_deps_x64_jessie
@@ -2,7 +2,7 @@
 libasound2 (>= 1.0.16)
 libatk1.0-0 (>= 1.12.4)
 libc6 (>= 2.15)
-libcairo2 (>= 1.2.4)
+libcairo2 (>= 1.6.0)
 libcups2 (>= 1.4.0)
 libdbus-1-3 (>= 1.1.4)
 libexpat1 (>= 2.0.1)
@@ -12,9 +12,9 @@
 libgconf-2-4 (>= 3.2.5)
 libgdk-pixbuf2.0-0 (>= 2.22.0)
 libglib2.0-0 (>= 2.41.1)
-libgtk2.0-0 (>= 2.24.0)
-libnspr4 (>= 2:4.9-2~) | libnspr4-0d (>= 1.8.0.10)
-libnss3 (>= 2:3.13.4-2~) | libnss3-1d (>= 3.12.4)
+libgtk-3-0 (>= 3.3.16)
+libnspr4 (>= 2:4.9-2~)
+libnss3 (>= 2:3.13.4-2~)
 libpango-1.0-0 (>= 1.14.0)
 libpangocairo-1.0-0 (>= 1.14.0)
 libstdc++6 (>= 4.8.1)
diff --git a/chrome/installer/linux/debian/expected_deps_x64_wheezy b/chrome/installer/linux/debian/expected_deps_x64_wheezy
index 98c6bd6..cea1252 100644
--- a/chrome/installer/linux/debian/expected_deps_x64_wheezy
+++ b/chrome/installer/linux/debian/expected_deps_x64_wheezy
@@ -2,7 +2,7 @@
 libasound2 (>= 1.0.16)
 libatk1.0-0 (>= 1.12.4)
 libc6 (>= 2.11)
-libcairo2 (>= 1.2.4)
+libcairo2 (>= 1.6.0)
 libcups2 (>= 1.4.0)
 libdbus-1-3 (>= 1.1.4)
 libexpat1 (>= 2.0.1)
@@ -11,8 +11,8 @@
 libgcc1 (>= 1:4.1.1)
 libgconf-2-4 (>= 2.31.1)
 libgdk-pixbuf2.0-0 (>= 2.22.0)
-libglib2.0-0 (>= 2.26.0)
-libgtk2.0-0 (>= 2.24.0)
+libglib2.0-0 (>= 2.28.0)
+libgtk-3-0 (>= 3.3.16)
 libnspr4 (>= 2:4.9-2~) | libnspr4-0d (>= 1.8.0.10)
 libnss3 (>= 2:3.13.4-2~) | libnss3-1d (>= 3.12.4)
 libpango1.0-0 (>= 1.14.0)
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index 5f6fb5a..ddaf415 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -36,13 +36,13 @@
 libgcc_s.so.1(GCC_3.0)(64bit)
 libgcc_s.so.1(GCC_4.0.0)(64bit)
 libgconf-2.so.4()(64bit)
-libgdk-x11-2.0.so.0()(64bit)
+libgdk-3.so.0()(64bit)
 libgdk_pixbuf-2.0.so.0()(64bit)
 libgio-2.0.so.0()(64bit)
 libglib-2.0.so.0()(64bit)
 libgmodule-2.0.so.0()(64bit)
 libgobject-2.0.so.0()(64bit)
-libgtk-x11-2.0.so.0()(64bit)
+libgtk-3.so.0()(64bit)
 libm.so.6()(64bit)
 libm.so.6(GLIBC_2.2.5)(64bit)
 libnspr4.so()(64bit)
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index e8ee1d95..b55941f 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -284,7 +284,6 @@
   correction_fetcher_->Start(
       render_frame()->GetWebFrame(),
       blink::WebURLRequest::RequestContextInternal,
-      blink::WebURLRequest::FrameTypeNone,
       base::Bind(&NetErrorHelper::OnNavigationCorrectionsFetched,
                  base::Unretained(this)));
 
@@ -308,7 +307,6 @@
   tracking_fetcher_->Start(
       render_frame()->GetWebFrame(),
       blink::WebURLRequest::RequestContextInternal,
-      blink::WebURLRequest::FrameTypeNone,
       base::Bind(&NetErrorHelper::OnTrackingRequestComplete,
                  base::Unretained(this)));
 }
diff --git a/chrome/renderer/resources/extensions/automation/OWNERS b/chrome/renderer/resources/extensions/automation/OWNERS
index 344aea38..e6cc90e 100644
--- a/chrome/renderer/resources/extensions/automation/OWNERS
+++ b/chrome/renderer/resources/extensions/automation/OWNERS
@@ -1,2 +1,4 @@
 aboxhall@chromium.org
 dtseng@chromium.org
+
+# COMPONENT: UI>Accessibility
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index bbdae48..87875d24 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3258,6 +3258,7 @@
     "../browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc",
+    "../browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/user_input_tracker_unittest.cc",
     "../browser/password_manager/chrome_password_manager_client_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestCaseBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestCaseBase.java
index 6a81592..c3043f7 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestCaseBase.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestCaseBase.java
@@ -20,6 +20,9 @@
 @CommandLineFlags.Add({"enable-features=ChromeHome"})
 @Restriction(RESTRICTION_TYPE_PHONE) // ChromeHome is only enabled on phones
 public abstract class BottomSheetTestCaseBase extends ChromeTabbedActivityTestBase {
+    /** A handle to the bottom sheet. */
+    protected BottomSheet mBottomSheet;
+
     private boolean mOldChromeHomeFlagValue;
     @Override
     protected void setUp() throws Exception {
@@ -41,6 +44,8 @@
         });
         RecyclerViewTestUtils.waitForStableRecyclerView(
                 getBottomSheetContent().getScrollingContentView());
+
+        mBottomSheet = getActivity().getBottomSheet();
     }
 
     @Override
@@ -54,6 +59,33 @@
         ChromePreferenceManager.getInstance().setChromeHomeEnabled(mOldChromeHomeFlagValue);
     }
 
+    /**
+     * Set the bottom sheet's state on the UI thread.
+     * @param state The state to set the sheet to.
+     * @param animate If the sheet should animate to the provided state.
+     */
+    protected void setSheetState(final int state, final boolean animate) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mBottomSheet.setSheetState(state, animate);
+            }
+        });
+    }
+
+    /**
+     * Set the bottom sheet's offset from the bottom of the screen on the UI thread.
+     * @param offset The offset from the bottom that the sheet should be.
+     */
+    protected void setSheetOffsetFromBottom(final float offset) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mBottomSheet.setSheetOffsetFromBottomForTesting(offset);
+            }
+        });
+    }
+
     protected BottomSheetContent getBottomSheetContent() {
         return getActivity().getBottomSheet().getCurrentSheetContent();
     }
diff --git a/chrome/test/base/v8_unit_test.h b/chrome/test/base/v8_unit_test.h
index a483b43..830da54 100644
--- a/chrome/test/base/v8_unit_test.h
+++ b/chrome/test/base/v8_unit_test.h
@@ -10,7 +10,6 @@
 
 #include "base/files/file_path.h"
 #include "base/strings/string_piece.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "v8/include/v8.h"
 
@@ -75,10 +74,6 @@
   // Initializes paths and libraries.
   void InitPathsAndLibraries();
 
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
-
   // Handle scope that is used throughout the life of this class.
   v8::HandleScope handle_scope_;
 
diff --git a/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js b/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js
index 360debc..30e8e86 100644
--- a/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js
@@ -170,10 +170,7 @@
   },
 };
 
-// Disabled because of flakiness http://crbug.com/694289
-TEST_F('SettingsAutofillSectionBrowserTest',
-       'DISABLED_CreditCardTests',
-       function() {
+TEST_F('SettingsAutofillSectionBrowserTest', 'CreditCardTests', function() {
   var self = this;
 
   setup(function() {
@@ -264,6 +261,12 @@
       assertNotEquals(oldCreditCardDialog.title_, newCreditCardDialog.title_);
       assertNotEquals('', newCreditCardDialog.title_);
       assertNotEquals('', oldCreditCardDialog.title_);
+
+      // Wait for dialogs to open before finishing test.
+      return Promise.all([
+        test_util.whenAttributeIs(newCreditCardDialog.$.dialog, 'open', true),
+        test_util.whenAttributeIs(oldCreditCardDialog.$.dialog, 'open', true),
+      ]);
     });
 
     test('verifyExpiredCreditCardYear', function() {
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index c2a8922..652ca56 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -39,6 +39,8 @@
     "cast_quota_permission_context.h",
     "cast_resource_dispatcher_host_delegate.cc",
     "cast_resource_dispatcher_host_delegate.h",
+    "cast_web_view.cc",
+    "cast_web_view.h",
     "devtools/cast_devtools_manager_delegate.cc",
     "devtools/cast_devtools_manager_delegate.h",
     "devtools/remote_debugging_server.cc",
diff --git a/chromecast/browser/android/cast_content_window_android.cc b/chromecast/browser/android/cast_content_window_android.cc
index a82992d6..2a1251a 100644
--- a/chromecast/browser/android/cast_content_window_android.cc
+++ b/chromecast/browser/android/cast_content_window_android.cc
@@ -7,13 +7,8 @@
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/memory/ptr_util.h"
-#include "chromecast/base/metrics/cast_metrics_helper.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/renderer_preferences.h"
-#include "ipc/ipc_message.h"
 #include "jni/CastContentWindowAndroid_jni.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -44,7 +39,6 @@
 CastContentWindowAndroid::CastContentWindowAndroid(
     CastContentWindow::Delegate* delegate)
     : delegate_(delegate),
-      transparent_(false),
       java_window_(CreateJavaWindow(reinterpret_cast<jlong>(this))) {
   DCHECK(delegate_);
 }
@@ -54,9 +48,7 @@
   Java_CastContentWindowAndroid_onNativeDestroyed(env, java_window_.obj());
 }
 
-void CastContentWindowAndroid::SetTransparent() {
-  transparent_ = true;
-}
+void CastContentWindowAndroid::SetTransparent() {}
 
 void CastContentWindowAndroid::ShowWebContents(
     content::WebContents* web_contents,
@@ -70,55 +62,6 @@
                                                 java_web_contents.obj());
 }
 
-std::unique_ptr<content::WebContents>
-CastContentWindowAndroid::CreateWebContents(
-    content::BrowserContext* browser_context,
-    scoped_refptr<content::SiteInstance> site_instance) {
-  CHECK(display::Screen::GetScreen());
-  gfx::Size display_size =
-      display::Screen::GetScreen()->GetPrimaryDisplay().size();
-
-  content::WebContents::CreateParams create_params(browser_context, nullptr);
-  create_params.routing_id = MSG_ROUTING_NONE;
-  create_params.initial_size = display_size;
-  create_params.site_instance = site_instance;
-  std::unique_ptr<content::WebContents> web_contents(
-      content::WebContents::Create(create_params));
-
-  content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs();
-  prefs->use_video_overlay_for_embedded_encrypted_video = true;
-  web_contents->GetRenderViewHost()->SyncRendererPrefs();
-
-  content::WebContentsObserver::Observe(web_contents.get());
-  return web_contents;
-}
-
-void CastContentWindowAndroid::DidFirstVisuallyNonEmptyPaint() {
-  metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstPaint();
-}
-
-void CastContentWindowAndroid::MediaStartedPlaying(
-    const MediaPlayerInfo& media_info,
-    const MediaPlayerId& id) {
-  metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
-}
-
-void CastContentWindowAndroid::MediaStoppedPlaying(
-    const MediaPlayerInfo& media_info,
-    const MediaPlayerId& id) {
-  metrics::CastMetricsHelper::GetInstance()->LogMediaPause();
-}
-
-void CastContentWindowAndroid::RenderViewCreated(
-    content::RenderViewHost* render_view_host) {
-  content::RenderWidgetHostView* view =
-      render_view_host->GetWidget()->GetView();
-  if (view) {
-    view->SetBackgroundColor(transparent_ ? SK_ColorTRANSPARENT
-                                          : SK_ColorBLACK);
-  }
-}
-
 void CastContentWindowAndroid::OnActivityStopped(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller) {
diff --git a/chromecast/browser/android/cast_content_window_android.h b/chromecast/browser/android/cast_content_window_android.h
index d1cf85d..68f2a84 100644
--- a/chromecast/browser/android/cast_content_window_android.h
+++ b/chromecast/browser/android/cast_content_window_android.h
@@ -12,10 +12,8 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "chromecast/browser/cast_content_window.h"
-#include "content/public/browser/web_contents_observer.h"
 
 namespace content {
-class BrowserContext;
 class WebContents;
 }
 
@@ -24,8 +22,7 @@
 
 // Android implementation of CastContentWindow, which displays WebContents in
 // CastWebContentsActivity.
-class CastContentWindowAndroid : public CastContentWindow,
-                                 public content::WebContentsObserver {
+class CastContentWindowAndroid : public CastContentWindow {
  public:
   static bool RegisterJni(JNIEnv* env);
 
@@ -35,17 +32,6 @@
   void SetTransparent() override;
   void ShowWebContents(content::WebContents* web_contents,
                        CastWindowManager* window_manager) override;
-  std::unique_ptr<content::WebContents> CreateWebContents(
-      content::BrowserContext* browser_context,
-      scoped_refptr<content::SiteInstance> site_instance) override;
-
-  // content::WebContentsObserver implementation:
-  void DidFirstVisuallyNonEmptyPaint() override;
-  void MediaStartedPlaying(const MediaPlayerInfo& media_info,
-                           const MediaPlayerId& id) override;
-  void MediaStoppedPlaying(const MediaPlayerInfo& media_info,
-                           const MediaPlayerId& id) override;
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
 
   // Called through JNI.
   void OnActivityStopped(JNIEnv* env,
@@ -61,7 +47,6 @@
   explicit CastContentWindowAndroid(CastContentWindow::Delegate* delegate);
 
   CastContentWindow::Delegate* const delegate_;
-  bool transparent_;
   base::android::ScopedJavaGlobalRef<jobject> java_window_;
 
   DISALLOW_COPY_AND_ASSIGN(CastContentWindowAndroid);
diff --git a/chromecast/browser/cast_content_window.h b/chromecast/browser/cast_content_window.h
index 9047a52..bdc610b 100644
--- a/chromecast/browser/cast_content_window.h
+++ b/chromecast/browser/cast_content_window.h
@@ -13,8 +13,6 @@
 #include "ui/events/event.h"
 
 namespace content {
-class BrowserContext;
-class SiteInstance;
 class WebContents;
 }
 
@@ -53,17 +51,6 @@
   // |window_manager| should outlive this CastContentWindow.
   virtual void ShowWebContents(content::WebContents* web_contents,
                                CastWindowManager* window_manager) = 0;
-
-  // Creates a WebContents.
-  // TODO(derekjchow): remove this function from this class, since it doesn't
-  // have anything to do with displaying web_contents.
-  virtual std::unique_ptr<content::WebContents> CreateWebContents(
-      content::BrowserContext* browser_context,
-      scoped_refptr<content::SiteInstance> site_instance) = 0;
-  std::unique_ptr<content::WebContents> CreateWebContents(
-      content::BrowserContext* browser_context) {
-    return CreateWebContents(browser_context, nullptr);
-  }
 };
 
 }  // namespace shell
diff --git a/chromecast/browser/cast_content_window_linux.cc b/chromecast/browser/cast_content_window_linux.cc
index eb654d51..c3bf970 100644
--- a/chromecast/browser/cast_content_window_linux.cc
+++ b/chromecast/browser/cast_content_window_linux.cc
@@ -6,13 +6,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "chromecast/base/metrics/cast_metrics_helper.h"
-#include "chromecast/base/version.h"
-#include "chromecast/browser/cast_browser_process.h"
 #include "chromecast/graphics/cast_window_manager.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ipc/ipc_message.h"
 #include "ui/display/display.h"
@@ -20,7 +14,7 @@
 
 #if defined(USE_AURA)
 #include "ui/aura/window.h"
-#endif
+#endif  // defined(USE_AURA)
 
 namespace chromecast {
 namespace shell {
@@ -40,36 +34,6 @@
   transparent_ = true;
 }
 
-std::unique_ptr<content::WebContents> CastContentWindowLinux::CreateWebContents(
-    content::BrowserContext* browser_context,
-    scoped_refptr<content::SiteInstance> site_instance) {
-  CHECK(display::Screen::GetScreen());
-  gfx::Size display_size =
-      display::Screen::GetScreen()->GetPrimaryDisplay().size();
-
-  content::WebContents::CreateParams create_params(browser_context, NULL);
-  create_params.routing_id = MSG_ROUTING_NONE;
-  create_params.initial_size = display_size;
-  create_params.site_instance = site_instance;
-  content::WebContents* web_contents =
-      content::WebContents::Create(create_params);
-
-  content::WebContentsObserver::Observe(web_contents);
-  return base::WrapUnique(web_contents);
-}
-
-void CastContentWindowLinux::DidStartNavigation(
-    content::NavigationHandle* navigation_handle) {
-#if defined(USE_AURA)
-  // Resize window
-  gfx::Size display_size =
-      display::Screen::GetScreen()->GetPrimaryDisplay().size();
-  aura::Window* content_window = web_contents()->GetNativeView();
-  content_window->SetBounds(
-      gfx::Rect(display_size.width(), display_size.height()));
-#endif
-}
-
 void CastContentWindowLinux::ShowWebContents(
     content::WebContents* web_contents,
     CastWindowManager* window_manager) {
@@ -80,31 +44,5 @@
   window->Show();
 }
 
-void CastContentWindowLinux::DidFirstVisuallyNonEmptyPaint() {
-  metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstPaint();
-}
-
-void CastContentWindowLinux::MediaStartedPlaying(
-    const MediaPlayerInfo& media_info,
-    const MediaPlayerId& id) {
-  metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
-}
-
-void CastContentWindowLinux::MediaStoppedPlaying(
-    const MediaPlayerInfo& media_info,
-    const MediaPlayerId& id) {
-  metrics::CastMetricsHelper::GetInstance()->LogMediaPause();
-}
-
-void CastContentWindowLinux::RenderViewCreated(
-    content::RenderViewHost* render_view_host) {
-  content::RenderWidgetHostView* view =
-      render_view_host->GetWidget()->GetView();
-  if (view) {
-    view->SetBackgroundColor(transparent_ ? SK_ColorTRANSPARENT
-                                          : SK_ColorBLACK);
-  }
-}
-
 }  // namespace shell
 }  // namespace chromecast
diff --git a/chromecast/browser/cast_content_window_linux.h b/chromecast/browser/cast_content_window_linux.h
index a083a11..5b4c6c2 100644
--- a/chromecast/browser/cast_content_window_linux.h
+++ b/chromecast/browser/cast_content_window_linux.h
@@ -9,19 +9,16 @@
 
 #include "base/macros.h"
 #include "chromecast/browser/cast_content_window.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
 namespace content {
-class BrowserContext;
 class WebContents;
 }
 
 namespace chromecast {
 namespace shell {
 
-class CastContentWindowLinux : public CastContentWindow,
-                               public content::WebContentsObserver {
+class CastContentWindowLinux : public CastContentWindow {
  public:
   // Removes the window from the screen.
   ~CastContentWindowLinux() override;
@@ -30,19 +27,6 @@
   void SetTransparent() override;
   void ShowWebContents(content::WebContents* web_contents,
                        CastWindowManager* window_manager) override;
-  std::unique_ptr<content::WebContents> CreateWebContents(
-      content::BrowserContext* browser_context,
-      scoped_refptr<content::SiteInstance> site_instance) override;
-
-  // content::WebContentsObserver implementation:
-  void DidStartNavigation(
-      content::NavigationHandle* navigation_handle) override;
-  void DidFirstVisuallyNonEmptyPaint() override;
-  void MediaStartedPlaying(const MediaPlayerInfo& media_info,
-                           const MediaPlayerId& id) override;
-  void MediaStoppedPlaying(const MediaPlayerInfo& media_info,
-                           const MediaPlayerId& id) override;
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
 
  private:
   friend class CastContentWindow;
diff --git a/chromecast/browser/cast_web_view.cc b/chromecast/browser/cast_web_view.cc
new file mode 100644
index 0000000..4c90dca
--- /dev/null
+++ b/chromecast/browser/cast_web_view.cc
@@ -0,0 +1,257 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/browser/cast_web_view.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/base/metrics/cast_metrics_helper.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/common/renderer_preferences.h"
+#include "ipc/ipc_message.h"
+#include "net/base/net_errors.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "url/gurl.h"
+
+#if defined(OS_ANDROID)
+#include "chromecast/browser/android/cast_web_contents_activity.h"
+#endif  // defined(OS_ANDROID)
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#endif
+
+namespace chromecast {
+
+namespace {
+// The time (in milliseconds) we wait for after a page is closed (i.e.
+// after an app is stopped) before we delete the corresponding WebContents.
+constexpr int kWebContentsDestructionDelayInMs = 50;
+
+std::unique_ptr<content::WebContents> CreateWebContents(
+    content::BrowserContext* browser_context,
+    scoped_refptr<content::SiteInstance> site_instance) {
+  CHECK(display::Screen::GetScreen());
+  gfx::Size display_size =
+      display::Screen::GetScreen()->GetPrimaryDisplay().size();
+
+  content::WebContents::CreateParams create_params(browser_context, NULL);
+  create_params.routing_id = MSG_ROUTING_NONE;
+  create_params.initial_size = display_size;
+  create_params.site_instance = site_instance;
+  content::WebContents* web_contents =
+      content::WebContents::Create(create_params);
+
+#if defined(USE_AURA)
+  // Resize window
+  aura::Window* content_window = web_contents->GetNativeView();
+  content_window->SetBounds(
+      gfx::Rect(display_size.width(), display_size.height()));
+#endif
+
+#if defined(OS_ANDROID)
+  content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs();
+  prefs->use_video_overlay_for_embedded_encrypted_video = true;
+  web_contents->GetRenderViewHost()->SyncRendererPrefs();
+#endif
+
+  return base::WrapUnique(web_contents);
+}
+
+}  // namespace
+
+CastWebView::CastWebView(Delegate* delegate,
+                         content::BrowserContext* browser_context,
+                         scoped_refptr<content::SiteInstance> site_instance,
+                         bool transparent)
+    : delegate_(delegate),
+      browser_context_(browser_context),
+      site_instance_(std::move(site_instance)),
+      transparent_(transparent),
+      window_(shell::CastContentWindow::Create(delegate)),
+      web_contents_(CreateWebContents(browser_context_, site_instance_)),
+      weak_factory_(this) {
+  DCHECK(delegate_);
+  DCHECK(browser_context_);
+  DCHECK(window_);
+  content::WebContentsObserver::Observe(web_contents_.get());
+  web_contents_->SetDelegate(this);
+
+  if (transparent_)
+    window_->SetTransparent();
+}
+
+CastWebView::~CastWebView() {}
+
+void CastWebView::LoadUrl(GURL url) {
+  web_contents_->GetController().LoadURL(url, content::Referrer(),
+                                         ui::PAGE_TRANSITION_TYPED, "");
+}
+
+void CastWebView::ClosePage() {
+  content::WebContentsObserver::Observe(nullptr);
+  web_contents_->ClosePage();
+}
+
+void CastWebView::CloseContents(content::WebContents* source) {
+  DCHECK_EQ(source, web_contents_.get());
+
+  // We need to delay the deletion of web_contents_ to give (and guarantee) the
+  // renderer enough time to finish 'onunload' handler (but we don't want to
+  // wait any longer than that to delay the starting of next app).
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&CastWebView::DelayedCloseContents,
+                            weak_factory_.GetWeakPtr()),
+      base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs));
+}
+
+void CastWebView::DelayedCloseContents() {
+  // Delete the WebContents object here so that the gfx surface will be
+  // deleted as part of destroying RenderWidgetHostViewCast object.
+  // We want to delete the surface before we start the next app because
+  // the next app could be an external one whose Start() function would
+  // destroy the primary gfx plane.
+  web_contents_.reset();
+  delegate_->OnPageStopped(net::OK);
+}
+
+void CastWebView::Show(CastWindowManager* window_manager) {
+  DCHECK(window_manager);
+  window_->ShowWebContents(web_contents_.get(), window_manager);
+  web_contents_->Focus();
+}
+
+content::WebContents* CastWebView::OpenURLFromTab(
+    content::WebContents* source,
+    const content::OpenURLParams& params) {
+  LOG(INFO) << "Change url: " << params.url;
+  // If source is NULL which means current tab, use web_contents_ of this class.
+  if (!source)
+    source = web_contents_.get();
+  DCHECK_EQ(source, web_contents_.get());
+  // We don't want to create another web_contents. Load url only when source is
+  // specified.
+  source->GetController().LoadURL(params.url, params.referrer,
+                                  params.transition, params.extra_headers);
+  return source;
+}
+
+void CastWebView::LoadingStateChanged(content::WebContents* source,
+                                      bool to_different_document) {
+  delegate_->OnLoadingStateChanged(source->IsLoading());
+}
+
+void CastWebView::ActivateContents(content::WebContents* contents) {
+  DCHECK_EQ(contents, web_contents_.get());
+  contents->GetRenderViewHost()->GetWidget()->Focus();
+}
+
+#if defined(OS_ANDROID)
+base::android::ScopedJavaLocalRef<jobject>
+CastWebView::GetContentVideoViewEmbedder() {
+  DCHECK(web_contents_);
+  auto activity = shell::CastWebContentsActivity::Get(web_contents_.get());
+  return activity->GetContentVideoViewEmbedder();
+}
+#endif  // defined(OS_ANDROID)
+
+void CastWebView::RenderProcessGone(base::TerminationStatus status) {
+  LOG(INFO) << "APP_ERROR_CHILD_PROCESS_CRASHED";
+  delegate_->OnPageStopped(net::ERR_UNEXPECTED);
+}
+
+void CastWebView::RenderViewCreated(content::RenderViewHost* render_view_host) {
+  content::RenderWidgetHostView* view =
+      render_view_host->GetWidget()->GetView();
+  if (view) {
+    view->SetBackgroundColor(transparent_ ? SK_ColorTRANSPARENT
+                                          : SK_ColorBLACK);
+  }
+}
+
+void CastWebView::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  // If the navigation was not committed, it means either the page was a
+  // download or error 204/205, or the navigation never left the previous
+  // URL. Ignore these navigations.
+  if (!navigation_handle->HasCommitted()) {
+    LOG(WARNING) << "Navigation did not commit: url="
+                 << navigation_handle->GetURL();
+    return;
+  }
+
+  net::Error error_code = navigation_handle->GetNetErrorCode();
+  if (!navigation_handle->IsErrorPage())
+    return;
+
+  // If we abort errors in an iframe, it can create a really confusing
+  // and fragile user experience.  Rather than create a list of errors
+  // that are most likely to occur, we ignore all of them for now.
+  if (!navigation_handle->IsInMainFrame()) {
+    LOG(ERROR) << "Got error on sub-iframe: url=" << navigation_handle->GetURL()
+               << ", error=" << error_code
+               << ", description=" << net::ErrorToShortString(error_code);
+    return;
+  }
+
+  LOG(ERROR) << "Got error on navigation: url=" << navigation_handle->GetURL()
+             << ", error_code=" << error_code
+             << ", description= " << net::ErrorToShortString(error_code);
+  delegate_->OnPageStopped(error_code);
+}
+
+void CastWebView::DidFailLoad(content::RenderFrameHost* render_frame_host,
+                              const GURL& validated_url,
+                              int error_code,
+                              const base::string16& error_description,
+                              bool was_ignored_by_handler) {
+  // Only report an error if we are the main frame.  See b/8433611.
+  if (render_frame_host->GetParent()) {
+    LOG(ERROR) << "Got error on sub-iframe: url=" << validated_url.spec()
+               << ", error=" << error_code;
+  } else if (error_code == net::ERR_ABORTED) {
+    // ERR_ABORTED means download was aborted by the app, typically this happens
+    // when flinging URL for direct playback, the initial URLRequest gets
+    // cancelled/aborted and then the same URL is requested via the buffered
+    // data source for media::Pipeline playback.
+    LOG(INFO) << "Load canceled: url=" << validated_url.spec();
+  } else {
+    LOG(ERROR) << "Got error on load: url=" << validated_url.spec()
+               << ", error_code=" << error_code;
+    delegate_->OnPageStopped(error_code);
+  }
+}
+
+void CastWebView::DidFirstVisuallyNonEmptyPaint() {
+  metrics::CastMetricsHelper::GetInstance()->LogTimeToFirstPaint();
+}
+
+void CastWebView::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+#if defined(USE_AURA)
+  // Resize window
+  gfx::Size display_size =
+      display::Screen::GetScreen()->GetPrimaryDisplay().size();
+  aura::Window* content_window = web_contents()->GetNativeView();
+  content_window->SetBounds(
+      gfx::Rect(display_size.width(), display_size.height()));
+#endif
+}
+
+void CastWebView::MediaStartedPlaying(const MediaPlayerInfo& media_info,
+                                      const MediaPlayerId& id) {
+  metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
+}
+
+void CastWebView::MediaStoppedPlaying(const MediaPlayerInfo& media_info,
+                                      const MediaPlayerId& id) {
+  metrics::CastMetricsHelper::GetInstance()->LogMediaPause();
+}
+
+}  // namespace chromecast
diff --git a/chromecast/browser/cast_web_view.h b/chromecast/browser/cast_web_view.h
new file mode 100644
index 0000000..26195913
--- /dev/null
+++ b/chromecast/browser/cast_web_view.h
@@ -0,0 +1,114 @@
+// 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 CHROMECAST_BROWSER_CAST_WEB_VIEW_H_
+#define CHROMECAST_BROWSER_CAST_WEB_VIEW_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "chromecast/browser/cast_content_window.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class BrowserContext;
+class RenderViewHost;
+class SiteInstance;
+}
+
+namespace chromecast {
+
+class CastWindowManager;
+
+// A simplified interface for loading and displaying WebContents in cast_shell.
+class CastWebView : content::WebContentsObserver, content::WebContentsDelegate {
+ public:
+  class Delegate : public shell::CastContentWindow::Delegate {
+   public:
+    // Called when the page has stopped. ie: A 404 occured when loading the page
+    // or if the render process crashes. |error_code| will return a net::Error
+    // describing the failure, or net::OK if the page closed naturally.
+    virtual void OnPageStopped(int error_code) = 0;
+
+    // Called during WebContentsDelegate::LoadingStateChanged.
+    // |loading| indicates if web_contents_ IsLoading or not.
+    virtual void OnLoadingStateChanged(bool loading) = 0;
+  };
+
+  // |delegate| and |browser_context| should outlive the lifetime of this
+  // object.
+  CastWebView(Delegate* delegate,
+              content::BrowserContext* browser_context,
+              scoped_refptr<content::SiteInstance> site_instance,
+              bool transparent);
+  ~CastWebView() override;
+
+  shell::CastContentWindow* window() const { return window_.get(); }
+
+  content::WebContents* web_contents() const { return web_contents_.get(); }
+
+  // Navigates to |url|. The loaded page will be preloaded if MakeVisible has
+  // not been called on the object.
+  void LoadUrl(GURL url);
+
+  // Begins the close process for this page (ie. triggering document.onunload).
+  // A consumer of the class can be notified when the process has been finished
+  // via Delegate::OnPageStopped().
+  void ClosePage();
+
+  // Makes the page visible to the user.
+  void Show(CastWindowManager* window_manager);
+
+ private:
+  // WebContentsObserver implementation:
+  void RenderProcessGone(base::TerminationStatus status) override;
+  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void DidFailLoad(content::RenderFrameHost* render_frame_host,
+                   const GURL& validated_url,
+                   int error_code,
+                   const base::string16& error_description,
+                   bool was_ignored_by_handler) override;
+  void DidFirstVisuallyNonEmptyPaint() override;
+  void DidStartNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void MediaStartedPlaying(const MediaPlayerInfo& media_info,
+                           const MediaPlayerId& id) override;
+  void MediaStoppedPlaying(const MediaPlayerInfo& media_info,
+                           const MediaPlayerId& id) override;
+
+  // WebContentsDelegate implementation:
+  content::WebContents* OpenURLFromTab(
+      content::WebContents* source,
+      const content::OpenURLParams& params) override;
+  void CloseContents(content::WebContents* source) override;
+  void LoadingStateChanged(content::WebContents* source,
+                           bool to_different_document) override;
+  void ActivateContents(content::WebContents* contents) override;
+#if defined(OS_ANDROID)
+  base::android::ScopedJavaLocalRef<jobject> GetContentVideoViewEmbedder()
+      override;
+#endif  // defined(OS_ANDROID)
+
+  void DelayedCloseContents();
+
+  Delegate* const delegate_;
+  content::BrowserContext* const browser_context_;
+  const scoped_refptr<content::SiteInstance> site_instance_;
+  const bool transparent_;
+  const std::unique_ptr<shell::CastContentWindow> window_;
+  std::unique_ptr<content::WebContents> web_contents_;
+
+  base::WeakPtrFactory<CastWebView> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastWebView);
+};
+
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_CAST_WEB_VIEW_H_
diff --git a/chromecast/browser/service/cast_service_simple.cc b/chromecast/browser/service/cast_service_simple.cc
index d2ac5b75..96c4a48 100644
--- a/chromecast/browser/service/cast_service_simple.cc
+++ b/chromecast/browser/service/cast_service_simple.cc
@@ -9,11 +9,9 @@
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/memory/ptr_util.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "net/base/filename_util.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace chromecast {
 namespace shell {
@@ -60,26 +58,24 @@
     return;
   }
 
-  window_ = CastContentWindow::Create(this);
-  web_contents_ = window_->CreateWebContents(browser_context());
-  window_->ShowWebContents(web_contents_.get(), window_manager_);
-
-  web_contents_->GetController().LoadURL(startup_url_, content::Referrer(),
-                                         ui::PAGE_TRANSITION_TYPED,
-                                         std::string());
-  web_contents_->Focus();
+  cast_web_view_ = base::MakeUnique<CastWebView>(this, browser_context(),
+                                                 /*site_instance*/ nullptr,
+                                                 /*transparent*/ false);
+  cast_web_view_->Show(window_manager_);
+  cast_web_view_->LoadUrl(startup_url_);
 }
 
 void CastServiceSimple::StopInternal() {
-  if (web_contents_) {
-    web_contents_->ClosePage();
-    web_contents_.reset();
+  if (cast_web_view_) {
+    cast_web_view_->ClosePage();
   }
-  if (window_) {
-    window_.reset();
-  }
+  cast_web_view_.reset();
 }
 
+void CastServiceSimple::OnPageStopped(int error_code) {}
+
+void CastServiceSimple::OnLoadingStateChanged(bool loading) {}
+
 void CastServiceSimple::OnWindowDestroyed() {}
 
 void CastServiceSimple::OnKeyEvent(const ui::KeyEvent& key_event) {}
diff --git a/chromecast/browser/service/cast_service_simple.h b/chromecast/browser/service/cast_service_simple.h
index b37f341..1a48b89 100644
--- a/chromecast/browser/service/cast_service_simple.h
+++ b/chromecast/browser/service/cast_service_simple.h
@@ -8,21 +8,16 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "chromecast/browser/cast_content_window.h"
+#include "chromecast/browser/cast_web_view.h"
 #include "chromecast/service/cast_service.h"
 #include "url/gurl.h"
 
-namespace content {
-class WebContents;
-}
-
 namespace chromecast {
 class CastWindowManager;
 
 namespace shell {
 
-class CastServiceSimple : public CastService,
-                          public CastContentWindow::Delegate {
+class CastServiceSimple : public CastService, public CastWebView::Delegate {
  public:
   CastServiceSimple(content::BrowserContext* browser_context,
                     PrefService* pref_service,
@@ -36,14 +31,17 @@
   void StartInternal() override;
   void StopInternal() override;
 
+  // CastWebView::Delegate implementation:
+  void OnPageStopped(int error_code) override;
+  void OnLoadingStateChanged(bool loading) override;
+
   // CastContentWindow::Delegate implementation:
   void OnWindowDestroyed() override;
   void OnKeyEvent(const ui::KeyEvent& key_event) override;
 
  private:
   CastWindowManager* const window_manager_;
-  std::unique_ptr<CastContentWindow> window_;
-  std::unique_ptr<content::WebContents> web_contents_;
+  std::unique_ptr<CastWebView> cast_web_view_;
   GURL startup_url_;
 
   DISALLOW_COPY_AND_ASSIGN(CastServiceSimple);
diff --git a/chromecast/browser/test/cast_browser_test.cc b/chromecast/browser/test/cast_browser_test.cc
index 79aac36..29a32fe 100644
--- a/chromecast/browser/test/cast_browser_test.cc
+++ b/chromecast/browser/test/cast_browser_test.cc
@@ -34,8 +34,7 @@
 }
 
 void CastBrowserTest::TearDownOnMainThread() {
-  web_contents_.reset();
-  window_.reset();
+  cast_web_view_.reset();
 
   BrowserTestBase::TearDownOnMainThread();
 }
@@ -60,22 +59,25 @@
 }
 
 content::WebContents* CastBrowserTest::NavigateToURL(const GURL& url) {
-  window_ = CastContentWindow::Create(this);
+  cast_web_view_ = base::WrapUnique(new CastWebView(
+      this, CastBrowserProcess::GetInstance()->browser_context(), nullptr,
+      false /*transparent*/));
 
-  web_contents_ = window_->CreateWebContents(
-      CastBrowserProcess::GetInstance()->browser_context());
-  content::WaitForLoadStop(web_contents_.get());
+  content::WebContents* web_contents = cast_web_view_->web_contents();
+  content::WaitForLoadStop(web_contents);
+  content::TestNavigationObserver same_tab_observer(web_contents, 1);
 
-  content::TestNavigationObserver same_tab_observer(web_contents_.get(), 1);
-  content::NavigationController::LoadURLParams params(url);
-  params.transition_type = ui::PageTransitionFromInt(
-      ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-  web_contents_->GetController().LoadURLWithParams(params);
+  cast_web_view_->LoadUrl(url);
+
   same_tab_observer.Wait();
 
-  return web_contents_.get();
+  return web_contents;
 }
 
+void CastBrowserTest::OnPageStopped(int reason) {}
+
+void CastBrowserTest::OnLoadingStateChanged(bool loading) {}
+
 void CastBrowserTest::OnWindowDestroyed() {}
 
 void CastBrowserTest::OnKeyEvent(const ui::KeyEvent& key_event) {}
diff --git a/chromecast/browser/test/cast_browser_test.h b/chromecast/browser/test/cast_browser_test.h
index 63acd6b4..5c94dd3 100644
--- a/chromecast/browser/test/cast_browser_test.h
+++ b/chromecast/browser/test/cast_browser_test.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "chromecast/browser/cast_content_window.h"
+#include "chromecast/browser/cast_web_view.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_base.h"
 
@@ -24,8 +24,7 @@
 // case, then shuts down the entire shell.
 // Note that this process takes 7-10 seconds per test case on Chromecast, so
 // fewer test cases with more assertions are preferable.
-class CastBrowserTest : public content::BrowserTestBase,
-                        CastContentWindow::Delegate {
+class CastBrowserTest : public content::BrowserTestBase, CastWebView::Delegate {
  protected:
   CastBrowserTest();
   ~CastBrowserTest() override;
@@ -39,12 +38,13 @@
   content::WebContents* NavigateToURL(const GURL& url);
 
  private:
-  // CastContentWindow::Delegate implementation:
+  // CastWebView::Delegate implementation:
+  void OnPageStopped(int error_code) override;
+  void OnLoadingStateChanged(bool loading) override;
   void OnWindowDestroyed() override;
   void OnKeyEvent(const ui::KeyEvent& key_event) override;
 
-  std::unique_ptr<CastContentWindow> window_;
-  std::unique_ptr<content::WebContents> web_contents_;
+  std::unique_ptr<CastWebView> cast_web_view_;
 
   DISALLOW_COPY_AND_ASSIGN(CastBrowserTest);
 };
diff --git a/chromecast/crash/cast_crash_keys.cc b/chromecast/crash/cast_crash_keys.cc
index 72db754..7de30624 100644
--- a/chromecast/crash/cast_crash_keys.cc
+++ b/chromecast/crash/cast_crash_keys.cc
@@ -102,9 +102,6 @@
     // Temporary for https://crbug.com/612711.
     { "aci_wrong_sp_extension_id", kSmallSize },
 
-    // Temporary for https://crbug.com/616149.
-    { "existing_extension_pref_value_type", kSmallSize },
-
     // Temporary for https://crbug.com/668633.
     { "swdh_set_hosted_version_worker_pid", kSmallSize },
     { "swdh_set_hosted_version_host_pid", kSmallSize },
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index c60ef0ad..99860c7 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -237,6 +237,9 @@
 // Enables ARC OptIn flow in OOBE.
 const char kEnableArcOOBEOptIn[] = "enable-arc-oobe-optin";
 
+// Enables native ChromeVox support for Arc.
+const char kEnableChromeVoxArcSupport[] = "enable-chromevox-arc-support";
+
 // Enables consume kiosk mode.
 const char kEnableConsumerKiosk[] = "enable-consumer-kiosk";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 5e7e9fac..f320d62 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -79,6 +79,7 @@
 CHROMEOS_EXPORT extern const char kEnableAndroidWallpapersApp[];
 CHROMEOS_EXPORT extern const char kEnableArc[];
 CHROMEOS_EXPORT extern const char kEnableArcOOBEOptIn[];
+CHROMEOS_EXPORT extern const char kEnableChromeVoxArcSupport[];
 CHROMEOS_EXPORT extern const char kEnableConsumerKiosk[];
 CHROMEOS_EXPORT extern const char kEnableDataSaverPrompt[];
 CHROMEOS_EXPORT extern const char kEnableExperimentalAccessibilityFeatures[];
diff --git a/components/arc/common/accessibility_helper.mojom b/components/arc/common/accessibility_helper.mojom
index 325006dc..d80b735 100644
--- a/components/arc/common/accessibility_helper.mojom
+++ b/components/arc/common/accessibility_helper.mojom
@@ -2,18 +2,135 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 1
+// Next MinVersion: 2
 
 module arc.mojom;
 
 import "screen_rect.mojom";
 
-// AccessibilityEventType is a enum which corresponds to event types of
-// AccessibilityEvent in Android.
+// For future maintainers, each of the below enums were hand picked
+// from their equivalents in the Android source. Keep them in the
+// order given below and add as needed. The initial order matches the
+// order they appear in source files.
+
+// AccessibilityEventType lists the possible accessibility events on Android.
 // https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent.html
 [Extensible]
 enum AccessibilityEventType {
   VIEW_FOCUSED,
+  VIEW_CLICKED,
+  VIEW_LONG_CLICKED,
+  VIEW_SELECTED,
+  VIEW_TEXT_CHANGED,
+  WINDOW_STATE_CHANGED,
+  NOTIFICATION_STATE_CHANGED,
+  VIEW_HOVER_ENTER,
+  VIEW_HOVER_EXIT,
+  TOUCH_EXPLORATION_GESTURE_START,
+  TOUCH_EXPLORATION_GESTURE_END,
+  WINDOW_CONTENT_CHANGED,
+  VIEW_SCROLLED,
+  VIEW_TEXT_SELECTION_CHANGED,
+  ANNOUNCEMENT,
+  VIEW_ACCESSIBILITY_FOCUSED,
+  VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+  VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+  GESTURE_DETECTION_START,
+  GESTURE_DETECTION_END,
+  TOUCH_INTERACTION_START,
+  TOUCH_INTERACTION_END,
+  WINDOWS_CHANGED,
+  VIEW_CONTEXT_CLICKED,
+  ASSIST_READING_CONTEXT,
+};
+
+// AccessibilityActionType lists possible accessibility actions on Android.
+// https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.html
+[Extensible]
+enum AccessibilityActionType {
+  FOCUS,
+  CLEAR_FOCUS,
+  SELECT,
+  CLEAR_SELECTION,
+  CLICK,
+  LONG_CLICK,
+  ACCESSIBILITY_FOCUS,
+  CLEAR_ACCESSIBILITY_FOCUS,
+  NEXT_AT_MOVEMENT_GRANULARITY,  // unused
+  PREVIOUS_AT_MOVEMENT_GRANULARITY,  // unused
+  NEXT_HTML_ELEMENT,  // unused
+  PREVIOUS_HTML_ELEMENT,  // unused
+  SCROLL_FORWARD,
+  SCROLL_BACKWARD,
+  COPY,
+  PASTE,
+  CUT,
+  SET_SELECTION,
+  EXPAND,
+  COLLAPSE,
+  DISMISS,
+  SET_TEXT
+};
+
+// Possible boolean properties set on an AccessibilityNodeInfo.
+// https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.html
+// The enum values appear in the same order as they do within
+// AccessibilityNodeInfo.java.
+[Extensible]
+enum AccessibilityBooleanProperty {
+  CHECKABLE,
+  CHECKED,
+  FOCUSABLE,
+  FOCUSED,
+  SELECTED,
+  CLICKABLE,
+  LONG_CLICKABLE,
+  ENABLED,
+  PASSWORD,
+  SCROLLABLE,
+  ACCESSIBILITY_FOCUSED,
+  VISIBLE_TO_USER,
+  EDITABLE,
+  OPENS_POPUP,
+  DISMISSABLE,
+  MULTI_LINE,
+  CONTENT_INVALID,
+  CONTEXT_CLICKABLE,
+  IMPORTANCE
+};
+
+// These fields are taken from string instance members of
+// AccessibilityNodeInfo.
+[Extensible]
+enum AccessibilityStringProperty {
+  PACKAGE_NAME,
+  CLASS_NAME,
+  TEXT,
+  CONTENT_DESCRIPTION,
+  VIEW_ID_RESOURCE_NAME
+};
+
+// These fields are taken from int instance members of
+// AccessibilityNodeInfo.
+[Extensible]
+enum AccessibilityIntProperty {
+  LABEL_FOR,
+  LABELED_BY,
+  TRAVERSAL_BEFORE,
+  TRAVERSAL_AFTER,
+  MAX_TEXT_LENGTH,
+  TEXT_SELECTION_START,
+  TEXT_SELECTION_END,
+  INPUT_TYPE,
+  LIVE_REGION
+};
+
+// These fields are taken from List<int> instance members of
+// AccessibilityNodeInfo.
+[Extensible]
+enum AccessibilityIntListProperty {
+  CHILD_NODE_IDS,
+  ACTIONS
 };
 
 // AccessibilityNodeInfoData is a struct to contain info of
@@ -21,17 +138,53 @@
 // https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo.html
 struct AccessibilityNodeInfoData {
   ScreenRect boundsInScreen;
+  [MinVersion=1]int32 id;
+  [MinVersion=1]map<AccessibilityBooleanProperty, bool>? booleanProperties;
+  [MinVersion=1]map<AccessibilityStringProperty, string>? stringProperties;
+  [MinVersion=1]map<AccessibilityIntProperty, int32>? intProperties;
+  [MinVersion=1]map<AccessibilityIntListProperty, array<int32>>? intListProperties;
 };
 
-// Next method ID: 1
+// Filters the event type (and implicitly the data) sent by the ARC
+// accessibility service.
+[Extensible]
+enum AccessibilityFilterType {
+  // No events will be sent.
+  OFF,
+
+  // Only send focus events along with the source focus node.
+  FOCUS,
+
+  // Send a complete tree from the event source's root for every event.
+  ALL
+};
+
+// AccessibilityEventData is a struct to contain info of
+// AccessibilityEvent in Android.
+// https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent.html
+struct AccessibilityEventData {
+  AccessibilityEventType eventType;
+  int32 sourceId;
+  array<AccessibilityNodeInfoData> nodeData;
+};
+
+// Next method ID: 2
 interface AccessibilityHelperHost {
+  OnAccessibilityEventDeprecated@0(AccessibilityEventType eventType,
+                                   AccessibilityNodeInfoData? eventSource);
+
   // OnAccessibilityEvent is called when a converted Android accessibility event
   // is sent from Android.
-  OnAccessibilityEvent@0(AccessibilityEventType eventType,
-                         AccessibilityNodeInfoData? eventSource);
+  OnAccessibilityEvent@1(AccessibilityEventData eventData);
 };
 
-// Next method ID: 1
+// Next method ID: 3
 interface AccessibilityHelperInstance {
   Init@0(AccessibilityHelperHost host);
+
+  // Perform the specified action on a node requested by a Chrome client.
+  PerformAction@1(int32 id, AccessibilityActionType action);
+
+  // Set a filter on the event types received.
+  SetFilter@2(AccessibilityFilterType filterType);
 };
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index 5c2ade8..685d91b 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1053,7 +1053,7 @@
 
   blink::WebVector<blink::WebFormElement> forms;
   frame->document().forms(forms);
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kShowAutofillSignatures)) {
     AnnotateFormsWithSignatures(forms);
   }
diff --git a/components/autofill/core/browser/validation.cc b/components/autofill/core/browser/validation.cc
index 10e0b21..7bf3a938 100644
--- a/components/autofill/core/browser/validation.cc
+++ b/components/autofill/core/browser/validation.cc
@@ -271,9 +271,10 @@
       if (IsValidCreditCardNumber(value))
         return true;
 
-      if (error_message)
-        *error_message =
-            l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_NUMBER_INVALID);
+      if (error_message) {
+        *error_message = l10n_util::GetStringUTF16(
+            IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE);
+      }
       break;
 
     default:
diff --git a/components/autofill/core/browser/validation_unittest.cc b/components/autofill/core/browser/validation_unittest.cc
index 4a53c84..c2589da 100644
--- a/components/autofill/core/browser/validation_unittest.cc
+++ b/components/autofill/core/browser/validation_unittest.cc
@@ -255,19 +255,19 @@
         ValidationCase(kInvalidNumbers[0],
                        CREDIT_CARD_NUMBER,
                        false,
-                       IDS_PAYMENTS_CARD_NUMBER_INVALID),
+                       IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
         ValidationCase(kInvalidNumbers[1],
                        CREDIT_CARD_NUMBER,
                        false,
-                       IDS_PAYMENTS_CARD_NUMBER_INVALID),
+                       IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
         ValidationCase(kInvalidNumbers[2],
                        CREDIT_CARD_NUMBER,
                        false,
-                       IDS_PAYMENTS_CARD_NUMBER_INVALID),
+                       IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
         ValidationCase(kInvalidNumbers[3],
                        CREDIT_CARD_NUMBER,
                        false,
-                       IDS_PAYMENTS_CARD_NUMBER_INVALID)));
+                       IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE)));
 
 INSTANTIATE_TEST_CASE_P(
     CreditCardMonth,
diff --git a/components/cronet/OWNERS b/components/cronet/OWNERS
index 078e99e..fe8552d 100644
--- a/components/cronet/OWNERS
+++ b/components/cronet/OWNERS
@@ -4,3 +4,5 @@
 mgersh@chromium.org
 pauljensen@chromium.org
 xunjieli@chromium.org
+
+# COMPONENT: Internals>Network>Library
\ No newline at end of file
diff --git a/components/doodle/BUILD.gn b/components/doodle/BUILD.gn
index 6ba398c..82e2dc0 100644
--- a/components/doodle/BUILD.gn
+++ b/components/doodle/BUILD.gn
@@ -6,6 +6,7 @@
   sources = [
     "doodle_fetcher.cc",
     "doodle_fetcher.h",
+    "doodle_types.h",
   ]
 
   deps = [
diff --git a/components/doodle/doodle_fetcher.h b/components/doodle/doodle_fetcher.h
index 009dc55..951bbad 100644
--- a/components/doodle/doodle_fetcher.h
+++ b/components/doodle/doodle_fetcher.h
@@ -15,6 +15,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "components/doodle/doodle_types.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/gurl.h"
@@ -29,59 +30,6 @@
 
 namespace doodle {
 
-enum class DoodleState {
-  AVAILABLE,
-  NO_DOODLE,
-  DOWNLOAD_ERROR,
-  PARSING_ERROR,
-};
-
-enum class DoodleType {
-  UNKNOWN,
-  SIMPLE,
-  RANDOM,
-  VIDEO,
-  INTERACTIVE,
-  INLINE_INTERACTIVE,
-  SLIDESHOW,
-};
-
-// Information about a Doodle image. If the image is invalid, the |url| will be
-// empty and invalid. By default the dimensions are 0.
-struct DoodleImage {
-  DoodleImage();
-  ~DoodleImage();
-
-  GURL url;
-  int height;
-  int width;
-  bool is_animated_gif;
-  bool is_cta;
-
-  // Copying and assignment allowed.
-};
-
-// All information about a current doodle that can be fetched from the remote
-// end. By default, all URLs are empty and therefore invalid.
-struct DoodleConfig {
-  DoodleConfig();
-  DoodleConfig(const DoodleConfig& config);  // = default;
-  ~DoodleConfig();
-
-  DoodleType doodle_type;
-  std::string alt_text;
-  std::string interactive_html;
-
-  base::Time expiry_date;
-  GURL search_url;
-  GURL target_url;
-  GURL fullpage_interactive_url;
-
-  DoodleImage large_image;
-  DoodleImage large_cta_image;
-  DoodleImage transparent_large_image;
-};
-
 // This class provides information about any recent doodle.
 // It works asynchronously and calls a callback when finished fetching the
 // information from the remote enpoint.
diff --git a/components/doodle/doodle_types.h b/components/doodle/doodle_types.h
new file mode 100644
index 0000000..a4d92ff
--- /dev/null
+++ b/components/doodle/doodle_types.h
@@ -0,0 +1,67 @@
+// 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 COMPONENTS_DOODLE_DOODLE_TYPES_H_
+#define COMPONENTS_DOODLE_DOODLE_TYPES_H_
+
+#include "url/gurl.h"
+
+namespace doodle {
+
+enum class DoodleState {
+  AVAILABLE,
+  NO_DOODLE,
+  DOWNLOAD_ERROR,
+  PARSING_ERROR,
+};
+
+enum class DoodleType {
+  UNKNOWN,
+  SIMPLE,
+  RANDOM,
+  VIDEO,
+  INTERACTIVE,
+  INLINE_INTERACTIVE,
+  SLIDESHOW,
+};
+
+// Information about a Doodle image. If the image is invalid, the |url| will be
+// empty and invalid. By default the dimensions are 0.
+struct DoodleImage {
+  DoodleImage();
+  ~DoodleImage();
+
+  GURL url;
+  int height;
+  int width;
+  bool is_animated_gif;
+  bool is_cta;
+
+  // Copying and assignment allowed.
+};
+
+// All information about a current doodle that can be fetched from the remote
+// end. By default, all URLs are empty and therefore invalid.
+struct DoodleConfig {
+  DoodleConfig();
+  DoodleConfig(const DoodleConfig& config);  // = default;
+  ~DoodleConfig();
+
+  DoodleType doodle_type;
+  std::string alt_text;
+  std::string interactive_html;
+
+  base::Time expiry_date;
+  GURL search_url;
+  GURL target_url;
+  GURL fullpage_interactive_url;
+
+  DoodleImage large_image;
+  DoodleImage large_cta_image;
+  DoodleImage transparent_large_image;
+};
+
+}  // namespace doodle
+
+#endif  // COMPONENTS_DOODLE_DOODLE_TYPES_H_
diff --git a/components/drive/service/drive_api_service.cc b/components/drive/service/drive_api_service.cc
index df82a503..b630803b 100644
--- a/components/drive/service/drive_api_service.cc
+++ b/components/drive/service/drive_api_service.cc
@@ -258,7 +258,8 @@
     : oauth2_token_service_(oauth2_token_service),
       url_request_context_getter_(url_request_context_getter),
       blocking_task_runner_(blocking_task_runner),
-      url_generator_(base_url, base_thumbnail_url),
+      url_generator_(base_url, base_thumbnail_url,
+                     google_apis::GetTeamDrivesIntegrationSwitch()),
       custom_user_agent_(custom_user_agent) {
 }
 
diff --git a/components/drive/service/drive_api_service_unittest.cc b/components/drive/service/drive_api_service_unittest.cc
index 5d03280..a349671 100644
--- a/components/drive/service/drive_api_service_unittest.cc
+++ b/components/drive/service/drive_api_service_unittest.cc
@@ -37,7 +37,8 @@
 
 TEST(DriveAPIServiceTest, BatchRequestConfiguratorWithAuthFailure) {
   const GURL test_base_url("http://localhost/");
-  google_apis::DriveApiUrlGenerator url_generator(test_base_url, test_base_url);
+  google_apis::DriveApiUrlGenerator url_generator(test_base_url, test_base_url,
+      google_apis::TEAM_DRIVES_INTEGRATION_DISABLED);
   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
       new base::TestSimpleTaskRunner();
   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 0fc3abc..024b5eb 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -155,6 +155,8 @@
 
 test("exo_unittests") {
   sources = [
+    "../../ash/test/ash_test_suite.cc",
+    "../../ash/test/ash_test_suite.h",
     "test/run_all_unittests.cc",
   ]
 
@@ -166,6 +168,10 @@
     "//base/test:test_support",
     "//device/gamepad:test_helpers",
     "//mojo/edk/embedder:headers",
+    "//testing/gtest",
+    "//ui/aura",
+    "//ui/base",
+    "//ui/gl:test_support",
   ]
 
   data_deps = [
diff --git a/components/gcm_driver/gcm_channel_status_request.cc b/components/gcm_driver/gcm_channel_status_request.cc
index 43c90ee..b91b445 100644
--- a/components/gcm_driver/gcm_channel_status_request.cc
+++ b/components/gcm_driver/gcm_channel_status_request.cc
@@ -14,6 +14,7 @@
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
 #include "url/gurl.h"
@@ -67,8 +68,42 @@
      NOTREACHED();
   }
 
-  url_fetcher_ =
-      net::URLFetcher::Create(request_url, net::URLFetcher::POST, this);
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("gcm_channel_status_request", R"(
+        semantics {
+          sender: "GCM Driver"
+          description:
+            "Google Chrome interacts with Google Cloud Messaging to receive "
+            "push messages for various browser features, as well as on behalf "
+            "of websites and extensions. The channel status request "
+            "periodically confirms with Google servers whether the feature "
+            "should be enabled."
+          trigger:
+            "Periodically when Chrome has established an active Google Cloud "
+            "Messaging subscription. The first request will be issued a minute "
+            "after the first subscription activates. Subsequent requests will "
+            "be issued each hour with a jitter of 15 minutes. Google can "
+            "adjust this interval when it deems necessary."
+          data:
+            "A user agent string containing the Chrome version, channel and "
+            "platform will be sent to the server. No user identifier is sent "
+            "along with the request."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: false
+          setting:
+            "Support for interacting with Google Cloud Messaging is enabled by "
+            "default, and there is no configuration option to completely "
+            "disable it. Websites wishing to receive push messages must "
+            "acquire express permission from the user for the 'Notification' "
+            "permission."
+          policy_exception_justification:
+            "Not implemented, considered not useful."
+        })");
+
+  url_fetcher_ = net::URLFetcher::Create(request_url, net::URLFetcher::POST,
+                                         this, traffic_annotation);
   data_use_measurement::DataUseUserData::AttachToFetcher(
       url_fetcher_.get(), data_use_measurement::DataUseUserData::GCM_DRIVER);
   url_fetcher_->SetRequestContext(request_context_getter_.get());
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index 566202b..6e443ab3 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -31,6 +31,7 @@
 #include "components/variations/variations_associated_data.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
 #include "base/json/json_reader.h"
@@ -306,7 +307,28 @@
 }
 
 void PopularSitesImpl::FetchPopularSites() {
-  fetcher_ = URLFetcher::Create(pending_url_, URLFetcher::GET, this);
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("popular_sites_fetch", R"(
+        semantics {
+          sender: "Popular Sites New Tab Fetch"
+          description:
+            "Google Chrome may display a list of regionally-popular web sites "
+            "on the New Tab Page. This service fetches the list of these sites."
+          trigger:
+            "Once per day, unless no popular web sites are required because "
+            "the New Tab Page is filled with suggestions based on the user's "
+            "browsing history."
+          data: "A two letter country code based on the user's location."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: false
+          setting: "This feature cannot be disabled in settings."
+          policy_exception_justification:
+            "Not implemented, considered not useful."
+        })");
+  fetcher_ = URLFetcher::Create(pending_url_, URLFetcher::GET, this,
+                                traffic_annotation);
   data_use_measurement::DataUseUserData::AttachToFetcher(
       fetcher_.get(), data_use_measurement::DataUseUserData::NTP_TILES);
   fetcher_->SetRequestContext(download_context_);
diff --git a/components/payments/BUILD.gn b/components/payments/BUILD.gn
index 3895da56..46f08096 100644
--- a/components/payments/BUILD.gn
+++ b/components/payments/BUILD.gn
@@ -79,6 +79,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "address_normalizer_unittest.cc",
     "currency_formatter_unittest.cc",
     "payments_validators_test.cc",
   ]
@@ -86,7 +87,10 @@
   deps = [
     ":payment_validation",
     "//base",
+    "//base/test:test_support",
+    "//components/autofill/core/browser",
     "//testing/gtest",
     "//third_party/icu:icu",
+    "//third_party/libaddressinput:test_support",
   ]
 }
diff --git a/components/payments/address_normalizer.cc b/components/payments/address_normalizer.cc
index f8dd35a..48866dd 100644
--- a/components/payments/address_normalizer.cc
+++ b/components/payments/address_normalizer.cc
@@ -7,7 +7,10 @@
 #include <memory>
 #include <utility>
 
+#include "base/cancelable_callback.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/autofill/core/browser/address_i18n.h"
 #include "third_party/libaddressinput/chromium/chrome_address_validator.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
@@ -28,21 +31,39 @@
   // The |delegate| and |address_validator| need to outlive this Request.
   AddressNormalizationRequest(const AutofillProfile& profile,
                               const std::string& region_code,
+                              int timeout_seconds,
                               AddressNormalizer::Delegate* delegate,
                               autofill::AddressValidator* address_validator)
       : profile_(profile),
         region_code_(region_code),
         delegate_(delegate),
-        address_validator_(address_validator) {}
+        address_validator_(address_validator),
+        has_responded_(false),
+        on_timeout_(
+            base::Bind(&::payments::AddressNormalizationRequest::OnRulesLoaded,
+                       base::Unretained(this),
+                       false)) {
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, on_timeout_.callback(),
+        base::TimeDelta::FromSeconds(timeout_seconds));
+  }
 
   ~AddressNormalizationRequest() override {}
 
   void OnRulesLoaded(bool success) override {
+    on_timeout_.Cancel();
+
+    // Check if the timeout happened before the rules were loaded.
+    if (has_responded_)
+      return;
+    has_responded_ = true;
+
     if (!success) {
       delegate_->OnCouldNotNormalize(profile_);
       return;
     }
 
+    // The rules should be loaded.
     DCHECK(address_validator_->AreRulesLoadedForRegion(region_code_));
 
     // Create the AddressData from the profile.
@@ -70,6 +91,9 @@
   AddressNormalizer::Delegate* delegate_;
   autofill::AddressValidator* address_validator_;
 
+  bool has_responded_;
+  base::CancelableCallback<void()> on_timeout_;
+
   DISALLOW_COPY_AND_ASSIGN(AddressNormalizationRequest);
 };
 
@@ -93,10 +117,14 @@
 void AddressNormalizer::StartAddressNormalization(
     const AutofillProfile& profile,
     const std::string& region_code,
+    int timeout_seconds,
     AddressNormalizer::Delegate* requester) {
+  DCHECK(timeout_seconds >= 0);
+
   std::unique_ptr<AddressNormalizationRequest> request(
-      new AddressNormalizationRequest(profile, region_code, requester,
-                                      &address_validator_));
+      base::MakeUnique<AddressNormalizationRequest>(profile, region_code,
+                                                    timeout_seconds, requester,
+                                                    &address_validator_));
 
   // Check if the rules are already loaded.
   if (AreRulesLoadedForRegion(region_code)) {
@@ -114,6 +142,10 @@
     }
 
     it->second.push_back(std::move(request));
+
+    // Start loading the rules for that region. If the rules were already in the
+    // process of being loaded, this call will do nothing.
+    LoadRulesForRegion(region_code);
   }
 }
 
diff --git a/components/payments/address_normalizer.h b/components/payments/address_normalizer.h
index d2f24c5..34cac3c 100644
--- a/components/payments/address_normalizer.h
+++ b/components/payments/address_normalizer.h
@@ -6,7 +6,6 @@
 #define COMPONENTS_PAYMENTS_ADDRESS_NORMALIZER_H_
 
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "third_party/libaddressinput/chromium/chrome_address_validator.h"
 
@@ -15,8 +14,7 @@
 namespace payments {
 
 // A class used to normalize addresses.
-class AddressNormalizer : public autofill::LoadRulesListener,
-                          public base::SupportsWeakPtr<AddressNormalizer> {
+class AddressNormalizer : public autofill::LoadRulesListener {
  public:
   // The interface for the normalization delegates.
   class Delegate {
@@ -43,7 +41,7 @@
   ~AddressNormalizer() override;
 
   // Start loading the validation rules for the specified |region_code|.
-  void LoadRulesForRegion(const std::string& region_code);
+  virtual void LoadRulesForRegion(const std::string& region_code);
 
   // Returns whether the rules for the specified |region_code| have finished
   // loading.
@@ -51,9 +49,15 @@
 
   // Starts the normalization of the |profile| based on the |region_code|. The
   // normalized profile will be returned to the |requester| possibly
-  // asynchronously.
+  // asynchronously. If the normalization is not completed in |timeout_seconds|
+  // the requester will be informed and the request cancelled. This value should
+  // be greater or equal to 0, for which it means that the normalization should
+  // happen synchronously, or not at all if the rules are not already loaded.
+  // Will start loading the rules for the |region_code| if they had not started
+  // loading.
   void StartAddressNormalization(const autofill::AutofillProfile& profile,
                                  const std::string& region_code,
+                                 int timeout_seconds,
                                  Delegate* requester);
 
  private:
diff --git a/components/payments/address_normalizer_unittest.cc b/components/payments/address_normalizer_unittest.cc
new file mode 100644
index 0000000..58c268b4
--- /dev/null
+++ b/components/payments/address_normalizer_unittest.cc
@@ -0,0 +1,184 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/payments/address_normalizer.h"
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_scheduler.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
+#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
+#include "third_party/libaddressinput/src/cpp/test/testdata_source.h"
+
+namespace payments {
+namespace {
+
+using ::i18n::addressinput::NullStorage;
+using ::i18n::addressinput::Source;
+using ::i18n::addressinput::Storage;
+using ::i18n::addressinput::TestdataSource;
+
+// The requester of normalization for this test.
+class NormalizationDelegate : public AddressNormalizer::Delegate {
+ public:
+  NormalizationDelegate()
+      : normalized_called_(false), not_normalized_called_(false) {}
+
+  ~NormalizationDelegate() override {}
+
+  void OnAddressNormalized(
+      const autofill::AutofillProfile& normalized_profile) override {
+    normalized_called_ = true;
+  }
+
+  void OnCouldNotNormalize(const autofill::AutofillProfile& profile) override {
+    not_normalized_called_ = true;
+  }
+
+  bool normalized_called() { return normalized_called_; }
+
+  bool not_normalized_called() { return not_normalized_called_; }
+
+ private:
+  bool normalized_called_;
+  bool not_normalized_called_;
+};
+
+// Used to load region rules for this test.
+class ChromiumTestdataSource : public TestdataSource {
+ public:
+  ChromiumTestdataSource() : TestdataSource(true) {}
+
+  ~ChromiumTestdataSource() override {}
+
+  // For this test, only load the rules for the "US".
+  void Get(const std::string& key, const Callback& data_ready) const override {
+    data_ready(
+        true, key,
+        new std::string("{\"data/US\": "
+                        "{\"id\":\"data/US\",\"key\":\"US\",\"name\":\"UNITED "
+                        "STATES\",\"lang\":\"en\",\"languages\":\"en\"}}"));
+  }
+};
+
+// A test subclass of the AddressNormalizer. Used to simulate rules not being
+// loaded.
+class TestAddressNormalizer : public AddressNormalizer {
+ public:
+  TestAddressNormalizer(std::unique_ptr<i18n::addressinput::Source> source,
+                        std::unique_ptr<i18n::addressinput::Storage> storage)
+      : AddressNormalizer(std::move(source), std::move(storage)),
+        should_load_rules_(true) {}
+
+  ~TestAddressNormalizer() override {}
+
+  void ShouldLoadRules(bool should_load_rules) {
+    should_load_rules_ = should_load_rules;
+  }
+
+  void LoadRulesForRegion(const std::string& region_code) override {
+    if (should_load_rules_) {
+      AddressNormalizer::LoadRulesForRegion(region_code);
+    }
+  }
+
+ private:
+  bool should_load_rules_;
+};
+
+}  // namespace
+
+class AddressNormalizerTest : public testing::Test {
+ protected:
+  AddressNormalizerTest()
+      : normalizer_(new TestAddressNormalizer(
+            std::unique_ptr<Source>(new ChromiumTestdataSource),
+            std::unique_ptr<Storage>(new NullStorage))) {}
+
+  ~AddressNormalizerTest() override {}
+
+  const std::unique_ptr<TestAddressNormalizer> normalizer_;
+
+  base::test::ScopedTaskScheduler scoped_task_scheduler_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AddressNormalizerTest);
+};
+
+// Tests that rules are not loaded by default.
+TEST_F(AddressNormalizerTest, AreRulesLoadedForRegion_NotLoaded) {
+  EXPECT_FALSE(normalizer_->AreRulesLoadedForRegion("US"));
+}
+
+// Tests that the rules are loaded correctly.
+TEST_F(AddressNormalizerTest, AreRulesLoadedForRegion_Loaded) {
+  normalizer_->LoadRulesForRegion("US");
+  EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion("US"));
+}
+
+// Tests that if the rules are loaded before the normalization is started, the
+// normalized profile will be returned to the delegate synchronously.
+TEST_F(AddressNormalizerTest, StartNormalization_RulesLoaded) {
+  NormalizationDelegate delegate;
+  AutofillProfile profile;
+
+  // Load the rules.
+  normalizer_->LoadRulesForRegion("US");
+  EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion("US"));
+
+  // Start the normalization.
+  normalizer_->StartAddressNormalization(profile, "US", 0, &delegate);
+
+  // Since the rules are already loaded, the address should be normalized
+  // synchronously.
+  EXPECT_TRUE(delegate.normalized_called());
+  EXPECT_FALSE(delegate.not_normalized_called());
+}
+
+// Tests that if the rules are not loaded before the normalization and cannot be
+// loaded after, the address will not be normalized and the delegate will be
+// notified.
+TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillNotLoad) {
+  NormalizationDelegate delegate;
+  AutofillProfile profile;
+
+  // Make sure the rules will not be loaded in the StartAddressNormalization
+  // call.
+  normalizer_->ShouldLoadRules(false);
+
+  // Start the normalization.
+  normalizer_->StartAddressNormalization(profile, "US", 0, &delegate);
+
+  // Let the timeout execute.
+  base::RunLoop().RunUntilIdle();
+
+  // Since the rules are never loaded and the timeout is 0, the delegate should
+  // get notified that the address could not be normalized.
+  EXPECT_FALSE(delegate.normalized_called());
+  EXPECT_TRUE(delegate.not_normalized_called());
+}
+
+// Tests that if the rules are not loaded before the call to
+// StartAddressNormalization, they will be loaded in the call.
+TEST_F(AddressNormalizerTest, StartNormalization_RulesNotLoaded_WillLoad) {
+  NormalizationDelegate delegate;
+  AutofillProfile profile;
+
+  // Start the normalization.
+  normalizer_->StartAddressNormalization(profile, "US", 0, &delegate);
+
+  // Even if the rules are not loaded before the call to
+  // StartAddressNormalization, they should get loaded in the call. Since our
+  // test source is synchronous, the normalization will happen synchronously
+  // too.
+  EXPECT_TRUE(normalizer_->AreRulesLoadedForRegion("US"));
+  EXPECT_TRUE(delegate.normalized_called());
+  EXPECT_FALSE(delegate.not_normalized_called());
+}
+
+}  // namespace payments
\ No newline at end of file
diff --git a/components/payments_strings.grdp b/components/payments_strings.grdp
index 21e74fa..a1d35c8 100644
--- a/components/payments_strings.grdp
+++ b/components/payments_strings.grdp
@@ -129,9 +129,6 @@
   <message name="IDS_PAYMENTS_NAME_ON_CARD_REQUIRED" desc="The label to indicate name on card is required for payment card." formatter_data="android_java">
     Name on card required
   </message>
-  <message name="IDS_PAYMENTS_CARD_NUMBER_INVALID" desc="The label to indicate payment card number is invalid." formatter_data="android_java">
-    Card number invalid
-  </message>
   <message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info." formatter_data="android_java">
     More information required
   </message>
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store.cc b/components/policy/core/common/cloud/component_cloud_policy_store.cc
index 93617d8..29c8dd4 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_store.cc
@@ -289,6 +289,10 @@
     LOG(ERROR) << "Bad policy type";
     return false;
   }
+  if (ns.component_id.empty()) {
+    LOG(ERROR) << "Empty component id";
+    return false;
+  }
 
   if (username_.empty() || dm_token_.empty() || device_id_.empty() ||
       public_key_.empty() || public_key_version_ == -1) {
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc b/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc
index 9798ea0..21ecc43 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_store_unittest.cc
@@ -241,6 +241,13 @@
                                       nullptr /* payload */));
 }
 
+TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyEmptyComponentId) {
+  builder_.policy_data().set_settings_entity_id(std::string());
+  EXPECT_FALSE(store_->ValidatePolicy(
+      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, std::string()),
+      CreateResponse(), nullptr /* policy_data */, nullptr /* payload */));
+}
+
 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongPublicKey) {
   // Test against a policy signed with a wrong key.
   builder_.SetSigningKey(*ComponentPolicyBuilder::CreateTestOtherSigningKey());
diff --git a/components/policy/core/common/cloud/component_cloud_policy_updater_unittest.cc b/components/policy/core/common/cloud/component_cloud_policy_updater_unittest.cc
index 6e0834e..e7a28e0 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_updater_unittest.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_updater_unittest.cc
@@ -289,6 +289,32 @@
   EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
 }
 
+TEST_F(ComponentCloudPolicyUpdaterTest, PolicyFetchResponseEmptyComponentId) {
+  // Submit a policy fetch response having an empty component ID.
+  builder_.policy_data().set_settings_entity_id(std::string());
+  updater_->UpdateExternalPolicy(
+      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, std::string()),
+      CreateResponse());
+
+  task_runner_->RunUntilIdle();
+
+  // Verify that the policy fetch response has been ignored.
+  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
+
+  // Submit a policy fetch response having an empty component ID with empty data
+  // fields, requesting the deletion of policy.
+  builder_.payload().clear_download_url();
+  builder_.payload().clear_secure_hash();
+  updater_->UpdateExternalPolicy(
+      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, std::string()),
+      CreateResponse());
+
+  task_runner_->RunUntilIdle();
+
+  // Verify that the policy fetch response has been ignored.
+  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
+}
+
 TEST_F(ComponentCloudPolicyUpdaterTest, AlreadyCached) {
   // Cache policy for an extension.
   builder_.Build();
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index 12b21a1..7711de3 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -41,14 +41,6 @@
   return rate == 1 || (rate > 0 && base::RandDouble() < rate);
 }
 
-bool NavigationIsPageReload(const GURL& url,
-                            const content::Referrer& referrer,
-                            ui::PageTransition transition) {
-  return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD) ||
-         // Some pages 'reload' from JavaScript by navigating to themselves.
-         url == referrer.url;
-}
-
 }  // namespace
 
 // static
@@ -70,12 +62,23 @@
       web_contents->GetUserData(kWebContentsUserDataKey));
 }
 
+// static
+bool ContentSubresourceFilterDriverFactory::NavigationIsPageReload(
+    const GURL& url,
+    const content::Referrer& referrer,
+    ui::PageTransition transition) {
+  return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD) ||
+         // Some pages 'reload' from JavaScript by navigating to themselves.
+         url == referrer.url;
+}
+
 ContentSubresourceFilterDriverFactory::ContentSubresourceFilterDriverFactory(
     content::WebContents* web_contents,
     std::unique_ptr<SubresourceFilterClient> client)
     : content::WebContentsObserver(web_contents),
       client_(std::move(client)),
       activation_level_(ActivationLevel::DISABLED),
+      activation_decision_(ActivationDecision::UNKNOWN),
       measure_performance_(false) {}
 
 ContentSubresourceFilterDriverFactory::
@@ -137,33 +140,42 @@
     whitelisted_hosts_.insert(url.host());
 }
 
-bool ContentSubresourceFilterDriverFactory::ShouldActivateForMainFrameURL(
+ContentSubresourceFilterDriverFactory::ActivationDecision
+ContentSubresourceFilterDriverFactory::ComputeActivationDecisionForMainFrameURL(
     const GURL& url) const {
-  switch (GetCurrentActivationScope()) {
+  if (GetMaximumActivationLevel() == ActivationLevel::DISABLED)
+    return ActivationDecision::ACTIVATION_DISABLED;
+
+  ActivationScope scope = GetCurrentActivationScope();
+  if (scope == ActivationScope::NO_SITES)
+    return ActivationDecision::ACTIVATION_DISABLED;
+
+  if (!url.SchemeIsHTTPOrHTTPS())
+    return ActivationDecision::UNSUPPORTED_SCHEME;
+  if (IsWhitelisted(url))
+    return ActivationDecision::URL_WHITELISTED;
+
+  switch (scope) {
     case ActivationScope::ALL_SITES:
-      return url.SchemeIsHTTPOrHTTPS() && !IsWhitelisted(url);
+      return ActivationDecision::ACTIVATED;
     case ActivationScope::ACTIVATION_LIST:
       // The logic to ensure only http/https URLs are activated lives in
       // AddActivationListMatch to ensure the activation list only has relevant
       // entries.
       DCHECK(url.SchemeIsHTTPOrHTTPS() ||
              !DidURLMatchCurrentActivationList(url));
-      return DidURLMatchCurrentActivationList(url) && !IsWhitelisted(url);
+      return DidURLMatchCurrentActivationList(url)
+                 ? ActivationDecision::ACTIVATED
+                 : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED;
     default:
-      return false;
+      return ActivationDecision::ACTIVATION_DISABLED;
   }
 }
 
 void ContentSubresourceFilterDriverFactory::ActivateForFrameHostIfNeeded(
     content::RenderFrameHost* render_frame_host,
-    const GURL& url,
-    bool failed_navigation) {
-  // PlzNavigate: For failed navigations, ReadyToCommitNavigation is still
-  // called, so we end up here; but there is no longer a failed provisional load
-  // on the renderer side, so an activation message sent from here would turn on
-  // filtering for the subsequent error page load. This is probably harmless,
-  // but not sending an activation message is even cleaner.
-  if (activation_level_ != ActivationLevel::DISABLED && !failed_navigation) {
+    const GURL& url) {
+  if (activation_level_ != ActivationLevel::DISABLED) {
     render_frame_host->Send(
         new SubresourceFilterMsg_ActivateForNextCommittedLoad(
             render_frame_host->GetRoutingID(), activation_level_,
@@ -189,6 +201,7 @@
 void ContentSubresourceFilterDriverFactory::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
   if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage()) {
+    activation_decision_ = ActivationDecision::UNKNOWN;
     ResetActivationState();
     navigation_chain_.push_back(navigation_handle->GetURL());
     client_->ToggleNotificationVisibility(false);
@@ -205,14 +218,20 @@
 void ContentSubresourceFilterDriverFactory::ReadyToCommitNavigation(
     content::NavigationHandle* navigation_handle) {
   DCHECK(!navigation_handle->IsSamePage());
+
+  // ReadyToCommitNavigation with browser-side navigation disabled is not called
+  // in production code for failed navigations (e.g. network errors). We don't
+  // want to activate on these pages, so we bail early to guarantee consistent
+  // behavior regardless of whether browser-side navigation is enabled.
+  if (navigation_handle->GetNetErrorCode() != net::OK)
+    return;
+
   content::RenderFrameHost* render_frame_host =
       navigation_handle->GetRenderFrameHost();
   GURL url = navigation_handle->GetURL();
   const content::Referrer& referrer = navigation_handle->GetReferrer();
   ui::PageTransition transition = navigation_handle->GetPageTransition();
-  ReadyToCommitNavigationInternal(
-      render_frame_host, url, referrer, transition,
-      navigation_handle->GetNetErrorCode() != net::OK);
+  ReadyToCommitNavigationInternal(render_frame_host, url, referrer, transition);
 }
 
 void ContentSubresourceFilterDriverFactory::DidFinishLoad(
@@ -274,10 +293,9 @@
     content::RenderFrameHost* render_frame_host,
     const GURL& url,
     const content::Referrer& referrer,
-    ui::PageTransition transition,
-    bool failed_navigation) {
+    ui::PageTransition transition) {
   if (render_frame_host->GetParent()) {
-    ActivateForFrameHostIfNeeded(render_frame_host, url, failed_navigation);
+    ActivateForFrameHostIfNeeded(render_frame_host, url);
     return;
   }
 
@@ -289,7 +307,9 @@
     AddHostOfURLToWhitelistSet(url);
   }
 
-  if (!ShouldActivateForMainFrameURL(url)) {
+  activation_decision_ = ComputeActivationDecisionForMainFrameURL(url);
+  DCHECK(activation_decision_ != ActivationDecision::UNKNOWN);
+  if (activation_decision_ != ActivationDecision::ACTIVATED) {
     ResetActivationState();
     return;
   }
@@ -297,7 +317,7 @@
   activation_level_ = GetMaximumActivationLevel();
   measure_performance_ = activation_level_ != ActivationLevel::DISABLED &&
                          ShouldMeasurePerformanceForPageLoad();
-  ActivateForFrameHostIfNeeded(render_frame_host, url, failed_navigation);
+  ActivateForFrameHostIfNeeded(render_frame_host, url);
 }
 
 bool ContentSubresourceFilterDriverFactory::DidURLMatchCurrentActivationList(
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index 06e8544da..ee1abda 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -46,12 +46,44 @@
     : public base::SupportsUserData::Data,
       public content::WebContentsObserver {
  public:
+  // NOTE: ActivationDecision backs a UMA histogram, so it is append-only.
+  enum class ActivationDecision {
+    // The activation decision is unknown, or not known yet.
+    UNKNOWN,
+
+    // Subresource filtering was activated.
+    ACTIVATED,
+
+    // Did not activate because subresource filtering was disabled.
+    ACTIVATION_DISABLED,
+
+    // Did not activate because the main frame document URL had an unsupported
+    // scheme.
+    UNSUPPORTED_SCHEME,
+
+    // Did not activate because the main frame document URL was whitelisted.
+    URL_WHITELISTED,
+
+    // Did not activate because the main frame document URL did not match the
+    // activation list.
+    ACTIVATION_LIST_NOT_MATCHED,
+
+    // Max value for enum.
+    ACTIVATION_DECISION_MAX
+  };
+
   static void CreateForWebContents(
       content::WebContents* web_contents,
       std::unique_ptr<SubresourceFilterClient> client);
   static ContentSubresourceFilterDriverFactory* FromWebContents(
       content::WebContents* web_contents);
 
+  // Whether the |url|, |referrer|, and |transition| are considered to be
+  // associated with a page reload.
+  static bool NavigationIsPageReload(const GURL& url,
+                                     const content::Referrer& referrer,
+                                     ui::PageTransition transition);
+
   explicit ContentSubresourceFilterDriverFactory(
       content::WebContents* web_contents,
       std::unique_ptr<SubresourceFilterClient> client);
@@ -75,6 +107,12 @@
   // Reloads the page and inserts the host of its URL to the whitelist.
   void OnReloadRequested();
 
+  // Returns the |ActivationDecision| for the current main frame
+  // document.
+  ActivationDecision GetActivationDecisionForLastCommittedPageLoad() const {
+    return activation_decision_;
+  }
+
  private:
   friend class ContentSubresourceFilterDriverFactoryTest;
   friend class safe_browsing::SafeBrowsingServiceTest;
@@ -99,12 +137,12 @@
   bool OnMessageReceived(const IPC::Message& message,
                          content::RenderFrameHost* render_frame_host) override;
 
-  // Checks base on the value of |urr| and current activation scope if
+  // Checks base on the value of |url| and current activation scope if
   // activation signal should be sent.
-  bool ShouldActivateForMainFrameURL(const GURL& url) const;
+  ActivationDecision ComputeActivationDecisionForMainFrameURL(
+      const GURL& url) const;
   void ActivateForFrameHostIfNeeded(content::RenderFrameHost* render_frame_host,
-                                    const GURL& url,
-                                    bool failed_navigation);
+                                    const GURL& url);
 
   // Internal implementation of ReadyToCommitNavigation which doesn't use
   // NavigationHandle to ease unit tests.
@@ -112,8 +150,7 @@
       content::RenderFrameHost* render_frame_host,
       const GURL& url,
       const content::Referrer& referrer,
-      ui::PageTransition page_transition,
-      bool failed_navigation);
+      ui::PageTransition page_transition);
 
   bool DidURLMatchCurrentActivationList(const GURL& url) const;
 
@@ -125,6 +162,7 @@
   HostPathSet whitelisted_hosts_;
 
   ActivationLevel activation_level_;
+  ActivationDecision activation_decision_;
   bool measure_performance_;
 
   // The URLs in the navigation chain.
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
index e0312a7..7bdebd6 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -24,6 +24,9 @@
 
 namespace subresource_filter {
 
+using ActivationDecision =
+    ContentSubresourceFilterDriverFactory::ActivationDecision;
+
 namespace {
 
 const char kExampleUrlWithParams[] = "https://example.com/soceng?q=engsoc";
@@ -56,84 +59,98 @@
 };
 
 struct ActivationListTestData {
-  bool expected_activation;
+  ActivationDecision expected_activation_decision;
   const char* const activation_list;
   safe_browsing::SBThreatType threat_type;
   safe_browsing::ThreatPatternType threat_type_metadata;
 };
 
 const ActivationListTestData kActivationListTestData[] = {
-    {false, "", safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED, "",
+     safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::NONE},
-    {false, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::MALWARE_LANDING},
-    {false, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::MALWARE_DISTRIBUTION},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_API_ABUSE,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_BLACKLISTED_RESOURCE,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_BINARY_MALWARE_URL,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_UNWANTED,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {false, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_SAFE,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
-    {true, subresource_filter::kActivationListPhishingInterstitial,
+    {ActivationDecision::ACTIVATED,
+     subresource_filter::kActivationListPhishingInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::NONE},
-    {true, subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
+    {ActivationDecision::ACTIVATED,
+     subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
 };
 
 struct ActivationScopeTestData {
-  bool expected_activation;
+  ActivationDecision expected_activation_decision;
   bool url_matches_activation_list;
   const char* const activation_scope;
 };
 
 const ActivationScopeTestData kActivationScopeTestData[] = {
-    {true /* expected_activation */, false /* url_matches_activation_list */,
+    {ActivationDecision::ACTIVATED, false /* url_matches_activation_list */,
      kActivationScopeAllSites},
-    {true /* expected_activation */, true /* url_matches_activation_list */,
+    {ActivationDecision::ACTIVATED, true /* url_matches_activation_list */,
      kActivationScopeAllSites},
-    {false /* expected_activation */, true /* url_matches_activation_list */,
-     kActivationScopeNoSites},
-    {true /* expected_activation */, true /* url_matches_activation_list */,
+    {ActivationDecision::ACTIVATION_DISABLED,
+     true /* url_matches_activation_list */, kActivationScopeNoSites},
+    {ActivationDecision::ACTIVATED, true /* url_matches_activation_list */,
      kActivationScopeActivationList},
-    {false /* expected_activation */, false /* url_matches_activation_list */,
-     kActivationScopeActivationList},
+    {ActivationDecision::ACTIVATION_LIST_NOT_MATCHED,
+     false /* url_matches_activation_list */, kActivationScopeActivationList},
 };
 
 struct ActivationLevelTestData {
-  bool expected_activation;
+  ActivationDecision expected_activation_decision;
   const char* const activation_level;
 };
 
 const ActivationLevelTestData kActivationLevelTestData[] = {
-    {true /* expected_activation */, kActivationLevelDryRun},
-    {true /* expected_activation */, kActivationLevelEnabled},
-    {false /* expected_activation */, kActivationLevelDisabled},
+    {ActivationDecision::ACTIVATED, kActivationLevelDryRun},
+    {ActivationDecision::ACTIVATED, kActivationLevelEnabled},
+    {ActivationDecision::ACTIVATION_DISABLED, kActivationLevelDisabled},
 };
 
 class MockSubresourceFilterClient : public SubresourceFilterClient {
@@ -202,8 +219,8 @@
     // TODO(crbug.com/688393): Once WCO::ReadyToCommitNavigation is invoked
     // consistently for tests in PlzNavigate and non-PlzNavigate, remove this.
     if (!content::IsBrowserSideNavigationEnabled()) {
-      factory()->ReadyToCommitNavigationInternal(rfh, url, referrer, transition,
-                                                 false /* failed_navigation */);
+      factory()->ReadyToCommitNavigationInternal(rfh, url, referrer,
+                                                 transition);
     }
     content::RenderFrameHostTester::For(rfh)->SimulateNavigationCommit(url);
   }
@@ -216,7 +233,9 @@
       const content::Referrer& referrer,
       ui::PageTransition transition,
       RedirectChainMatchPattern expected_pattern,
-      bool expected_activation) {
+      ActivationDecision expected_activation_decision) {
+    const bool expected_activation =
+        expected_activation_decision == ActivationDecision::ACTIVATED;
     base::HistogramTester tester;
     EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1);
     content::RenderFrameHostTester* rfh_tester =
@@ -242,6 +261,8 @@
     SimulateNavigationCommit(main_rfh(), navigation_chain.back(), referrer,
                              transition);
     ExpectActivationSignalForFrame(main_rfh(), expected_activation);
+    EXPECT_EQ(expected_activation_decision,
+              factory()->GetActivationDecisionForLastCommittedPageLoad());
 
     if (expected_pattern != EMPTY) {
       EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName),
@@ -277,24 +298,27 @@
       const content::Referrer& referrer,
       ui::PageTransition transition,
       RedirectChainMatchPattern expected_pattern,
-      bool expected_activation) {
+      ActivationDecision expected_activation_decision) {
+    const bool expected_activation =
+        expected_activation_decision == ActivationDecision::ACTIVATED;
     BlacklistURLWithRedirectsNavigateAndCommit(
         blacklisted_urls, navigation_chain, threat_type, threat_type_metadata,
-        referrer, transition, expected_pattern, expected_activation);
+        referrer, transition, expected_pattern, expected_activation_decision);
 
     NavigateAndCommitSubframe(GURL(kExampleLoginUrl), expected_activation);
   }
 
-  void NavigateAndExpectActivation(const std::vector<bool>& blacklisted_urls,
-                                   const std::vector<GURL>& navigation_chain,
-                                   RedirectChainMatchPattern expected_pattern,
-                                   bool expected_activation) {
+  void NavigateAndExpectActivation(
+      const std::vector<bool>& blacklisted_urls,
+      const std::vector<GURL>& navigation_chain,
+      RedirectChainMatchPattern expected_pattern,
+      ActivationDecision expected_activation_decision) {
     NavigateAndExpectActivation(
         blacklisted_urls, navigation_chain,
         safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
         safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS,
         content::Referrer(), ui::PAGE_TRANSITION_LINK, expected_pattern,
-        expected_activation);
+        expected_activation_decision);
   }
 
   void EmulateDidDisallowFirstSubresourceMessage() {
@@ -319,9 +343,10 @@
     ::testing::Mock::VerifyAndClearExpectations(client());
   }
 
-  void EmulateInPageNavigation(const std::vector<bool>& blacklisted_urls,
-                               RedirectChainMatchPattern expected_pattern,
-                               bool expected_activation) {
+  void EmulateInPageNavigation(
+      const std::vector<bool>& blacklisted_urls,
+      RedirectChainMatchPattern expected_pattern,
+      ActivationDecision expected_activation_decision) {
     // This test examines the navigation with the following sequence of events:
     //   DidStartProvisional(main, "example.com")
     //   ReadyToCommitNavigation(“example.com”)
@@ -331,7 +356,7 @@
     //   DidCommitProvisional(main, "example.com#ref")
 
     NavigateAndExpectActivation(blacklisted_urls, {GURL(kExampleUrl)},
-                                expected_pattern, expected_activation);
+                                expected_pattern, expected_activation_decision);
     EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
     content::RenderFrameHostTester::For(main_rfh())
         ->SimulateNavigationCommit(GURL(kExampleUrl));
@@ -401,10 +426,10 @@
       kActivationListSocialEngineeringAdsInterstitial);
   const GURL url(kExampleUrlWithParams);
   NavigateAndExpectActivation({true}, {url}, EMPTY,
-                              false /* expected_activation */);
+                              ActivationDecision::ACTIVATION_DISABLED);
   factory()->AddHostOfURLToWhitelistSet(url);
   NavigateAndExpectActivation({true}, {url}, EMPTY,
-                              false /* expected_activation */);
+                              ActivationDecision::ACTIVATION_DISABLED);
 }
 
 TEST_F(ContentSubresourceFilterDriverFactoryTest, NoActivationWhenNoMatch) {
@@ -414,7 +439,7 @@
       kActivationScopeActivationList,
       kActivationListSocialEngineeringAdsInterstitial);
   NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY,
-                              false /* should_prompt */);
+                              ActivationDecision::ACTIVATION_LIST_NOT_MATCHED);
 }
 
 TEST_F(ContentSubresourceFilterDriverFactoryTest,
@@ -425,7 +450,7 @@
   testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
       base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationLevelEnabled,
       kActivationScopeAllSites);
-  EmulateInPageNavigation({false}, EMPTY, true /* expected_activation */);
+  EmulateInPageNavigation({false}, EMPTY, ActivationDecision::ACTIVATED);
 }
 
 TEST_F(ContentSubresourceFilterDriverFactoryTest,
@@ -436,7 +461,7 @@
       kActivationScopeActivationList,
       kActivationListSocialEngineeringAdsInterstitial);
   EmulateInPageNavigation({true}, NO_REDIRECTS_HIT,
-                          true /* expected_activation */);
+                          ActivationDecision::ACTIVATED);
 }
 
 TEST_F(ContentSubresourceFilterDriverFactoryTest,
@@ -448,7 +473,7 @@
       kActivationListSocialEngineeringAdsInterstitial,
       "1" /* performance_measurement_rate */);
   EmulateInPageNavigation({true}, NO_REDIRECTS_HIT,
-                          true /* expected_activation */);
+                          ActivationDecision::ACTIVATED);
 }
 
 TEST_F(ContentSubresourceFilterDriverFactoryTest, FailedNavigation) {
@@ -458,7 +483,7 @@
       kActivationScopeAllSites);
   const GURL url(kExampleUrl);
   NavigateAndExpectActivation({false}, {url}, EMPTY,
-                              true /* expected_activation */);
+                              ActivationDecision::ACTIVATED);
   EmulateFailedNavigationAndExpectNoActivation(url);
 }
 
@@ -472,51 +497,66 @@
     std::vector<bool> blacklisted_urls;
     std::vector<GURL> navigation_chain;
     RedirectChainMatchPattern hit_expected_pattern;
-    bool expected_activation;
+    ActivationDecision expected_activation_decision;
   } kRedirectRedirectChainMatchPatternTestData[] = {
-      {{false}, {GURL(kUrlA)}, EMPTY, false},
-      {{true}, {GURL(kUrlA)}, NO_REDIRECTS_HIT, true},
-      {{false, false}, {GURL(kUrlA), GURL(kUrlB)}, EMPTY, false},
-      {{false, true}, {GURL(kUrlA), GURL(kUrlB)}, F0M0L1, true},
-      {{true, false}, {GURL(kUrlA), GURL(kUrlB)}, F1M0L0, false},
-      {{true, true}, {GURL(kUrlA), GURL(kUrlB)}, F1M0L1, true},
+      {{false},
+       {GURL(kUrlA)},
+       EMPTY,
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
+      {{true}, {GURL(kUrlA)}, NO_REDIRECTS_HIT, ActivationDecision::ACTIVATED},
+      {{false, false},
+       {GURL(kUrlA), GURL(kUrlB)},
+       EMPTY,
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
+      {{false, true},
+       {GURL(kUrlA), GURL(kUrlB)},
+       F0M0L1,
+       ActivationDecision::ACTIVATED},
+      {{true, false},
+       {GURL(kUrlA), GURL(kUrlB)},
+       F1M0L0,
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
+      {{true, true},
+       {GURL(kUrlA), GURL(kUrlB)},
+       F1M0L1,
+       ActivationDecision::ACTIVATED},
 
       {{false, false, false},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        EMPTY,
-       false},
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
       {{false, false, true},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F0M0L1,
-       true},
+       ActivationDecision::ACTIVATED},
       {{false, true, false},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F0M1L0,
-       false},
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
       {{false, true, true},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F0M1L1,
-       true},
+       ActivationDecision::ACTIVATED},
       {{true, false, false},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F1M0L0,
-       false},
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
       {{true, false, true},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F1M0L1,
-       true},
+       ActivationDecision::ACTIVATED},
       {{true, true, false},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F1M1L0,
-       false},
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
       {{true, true, true},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)},
        F1M1L1,
-       true},
+       ActivationDecision::ACTIVATED},
       {{false, true, false, false},
        {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC), GURL(kUrlD)},
        F0M1L0,
-       false},
+       ActivationDecision::ACTIVATION_LIST_NOT_MATCHED},
   };
 
   for (size_t i = 0U; i < arraysize(kRedirectRedirectChainMatchPatternTestData);
@@ -527,9 +567,10 @@
         safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
         safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS,
         content::Referrer(), ui::PAGE_TRANSITION_LINK,
-        test_data.hit_expected_pattern, test_data.expected_activation);
-    NavigateAndExpectActivation({false}, {GURL("https://dummy.com")}, EMPTY,
-                                false);
+        test_data.hit_expected_pattern, test_data.expected_activation_decision);
+    NavigateAndExpectActivation(
+        {false}, {GURL("https://dummy.com")}, EMPTY,
+        ActivationDecision::ACTIVATION_LIST_NOT_MATCHED);
   }
 }
 
@@ -540,7 +581,7 @@
       kActivationScopeAllSites);
 
   NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY,
-                              true /* expected_activation */);
+                              ActivationDecision::ACTIVATED);
   EXPECT_CALL(*client(), ToggleNotificationVisibility(true)).Times(1);
   EmulateDidDisallowFirstSubresourceMessage();
 }
@@ -555,7 +596,7 @@
       "true" /* suppress_notifications */);
 
   NavigateAndExpectActivation({false}, {GURL(kExampleUrl)}, EMPTY,
-                              true /* expected_activation */);
+                              ActivationDecision::ACTIVATED);
   EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0);
   EmulateDidDisallowFirstSubresourceMessage();
 }
@@ -570,14 +611,16 @@
   const struct {
     content::Referrer referrer;
     ui::PageTransition transition;
-    bool expect_activation;
+    ActivationDecision expected_activation_decision;
   } kTestCases[] = {
-      {content::Referrer(), ui::PAGE_TRANSITION_LINK, true},
+      {content::Referrer(), ui::PAGE_TRANSITION_LINK,
+       ActivationDecision::ACTIVATED},
       {content::Referrer(GURL(kUrlA), blink::WebReferrerPolicyDefault),
-       ui::PAGE_TRANSITION_LINK, true},
+       ui::PAGE_TRANSITION_LINK, ActivationDecision::ACTIVATED},
       {content::Referrer(GURL(kExampleUrl), blink::WebReferrerPolicyDefault),
-       ui::PAGE_TRANSITION_LINK, false},
-      {content::Referrer(), ui::PAGE_TRANSITION_RELOAD, false}};
+       ui::PAGE_TRANSITION_LINK, ActivationDecision::URL_WHITELISTED},
+      {content::Referrer(), ui::PAGE_TRANSITION_RELOAD,
+       ActivationDecision::URL_WHITELISTED}};
 
   for (const auto& test_case : kTestCases) {
     SCOPED_TRACE(::testing::Message("referrer = \"")
@@ -596,11 +639,11 @@
         safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
         safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS,
         test_case.referrer, test_case.transition, EMPTY,
-        test_case.expect_activation);
+        test_case.expected_activation_decision);
     // Verify that if the first URL failed to activate, subsequent same-origin
     // navigations also fail to activate.
     NavigateAndExpectActivation({false}, {GURL(kExampleUrlWithParams)}, EMPTY,
-                                test_case.expect_activation);
+                                test_case.expected_activation_decision);
   }
 }
 
@@ -615,11 +658,13 @@
 
   const GURL url(kExampleUrlWithParams);
   NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT,
-                              test_data.expected_activation);
+                              test_data.expected_activation_decision);
   factory()->AddHostOfURLToWhitelistSet(url);
-  NavigateAndExpectActivation({true}, {GURL(kExampleUrlWithParams)},
-                              NO_REDIRECTS_HIT,
-                              false /* expected_activation */);
+  NavigateAndExpectActivation(
+      {true}, {GURL(kExampleUrlWithParams)}, NO_REDIRECTS_HIT,
+      GetMaximumActivationLevel() == ActivationLevel::DISABLED
+          ? ActivationDecision::ACTIVATION_DISABLED
+          : ActivationDecision::URL_WHITELISTED);
 }
 
 TEST_P(ContentSubresourceFilterDriverFactoryThreatTypeTest,
@@ -635,12 +680,14 @@
   const GURL test_url("https://example.com/nonsoceng?q=engsocnon");
   std::vector<GURL> navigation_chain;
 
+  const bool expected_activation =
+      test_data.expected_activation_decision == ActivationDecision::ACTIVATED;
   NavigateAndExpectActivation(
       {false, false, false, true},
       {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC), test_url}, test_data.threat_type,
       test_data.threat_type_metadata, content::Referrer(),
-      ui::PAGE_TRANSITION_LINK, test_data.expected_activation ? F0M0L1 : EMPTY,
-      test_data.expected_activation);
+      ui::PAGE_TRANSITION_LINK, expected_activation ? F0M0L1 : EMPTY,
+      test_data.expected_activation_decision);
 };
 
 TEST_P(ContentSubresourceFilterDriverFactoryActivationScopeTest,
@@ -658,12 +705,15 @@
       test_data.url_matches_activation_list ? NO_REDIRECTS_HIT : EMPTY;
   NavigateAndExpectActivation({test_data.url_matches_activation_list},
                               {test_url}, expected_pattern,
-                              test_data.expected_activation);
+                              test_data.expected_activation_decision);
   if (test_data.url_matches_activation_list) {
     factory()->AddHostOfURLToWhitelistSet(test_url);
-    NavigateAndExpectActivation({test_data.url_matches_activation_list},
-                                {GURL(kExampleUrlWithParams)}, expected_pattern,
-                                false /* expected_activation */);
+    NavigateAndExpectActivation(
+        {test_data.url_matches_activation_list}, {GURL(kExampleUrlWithParams)},
+        expected_pattern,
+        GetCurrentActivationScope() == ActivationScope::NO_SITES
+            ? ActivationDecision::ACTIVATION_DISABLED
+            : ActivationDecision::URL_WHITELISTED);
   }
 };
 
@@ -686,9 +736,11 @@
   for (const auto url : unsupported_urls) {
     SCOPED_TRACE(url);
     RedirectChainMatchPattern expected_pattern = EMPTY;
-    NavigateAndExpectActivation({test_data.url_matches_activation_list},
-                                {GURL(url)}, expected_pattern,
-                                false /* expected_activation */);
+    NavigateAndExpectActivation(
+        {test_data.url_matches_activation_list}, {GURL(url)}, expected_pattern,
+        GetCurrentActivationScope() == ActivationScope::NO_SITES
+            ? ActivationDecision::ACTIVATION_DISABLED
+            : ActivationDecision::UNSUPPORTED_SCHEME);
   }
   for (const auto url : supported_urls) {
     SCOPED_TRACE(url);
@@ -696,7 +748,7 @@
         test_data.url_matches_activation_list ? NO_REDIRECTS_HIT : EMPTY;
     NavigateAndExpectActivation({test_data.url_matches_activation_list},
                                 {GURL(url)}, expected_pattern,
-                                test_data.expected_activation);
+                                test_data.expected_activation_decision);
   }
 };
 
diff --git a/components/url_formatter/elide_url_unittest.cc b/components/url_formatter/elide_url_unittest.cc
index e8a9201..e92df4e 100644
--- a/components/url_formatter/elide_url_unittest.cc
+++ b/components/url_formatter/elide_url_unittest.cc
@@ -20,20 +20,11 @@
 #include "ui/gfx/text_utils.h"  // nogncheck
 #endif
 
-#if defined(OS_IOS)
-#include "base/ios/ios_util.h"
-#endif
-
 namespace {
 
 struct Testcase {
   const std::string input;
   const std::string output;
-  enum SupportedPlatforms {
-    ALL = 0,
-    NO_IOS9_OR_LATER,
-    NO_IOS,
-  } platforms;
 };
 
 #if !defined(OS_ANDROID)
@@ -187,37 +178,29 @@
 TEST(TextEliderTest, TestHostEliding) {
   const std::string kEllipsisStr(gfx::kEllipsis);
   Testcase testcases[] = {
-      {"http://google.com", "google.com"},
-      // iOS width calculations are off by a letter from other platforms for
-      // strings with too many kerned letters on the default font set.
-      // TODO(rohitrao): Fix secure_display::ElideHost for iOS
-      // (crbug.com/517604).
-      {"http://subdomain.google.com", kEllipsisStr + ".google.com",
-       Testcase::NO_IOS9_OR_LATER},
-      {"http://reallyreallyreallylongdomainname.com",
-       "reallyreallyreallylongdomainname.com"},
-      {"http://a.b.c.d.e.f.com", kEllipsisStr + "f.com",
-       Testcase::NO_IOS9_OR_LATER},
-      {"http://foo", "foo"},
-      {"http://foo.bar", "foo.bar"},
-      {"http://subdomain.foo.bar", kEllipsisStr + "in.foo.bar",
-       Testcase::NO_IOS9_OR_LATER},
-      {"http://subdomain.reallylongdomainname.com",
-       kEllipsisStr + "ain.reallylongdomainname.com", Testcase::NO_IOS},
-      {"http://a.b.c.d.e.f.com", kEllipsisStr + ".e.f.com", Testcase::NO_IOS},
-      // IDN - Greek alpha.beta.gamma.delta.epsilon.zeta.com
-      {"http://xn--mxa.xn--nxa.xn--oxa.xn--pxa.xn--qxa.xn--rxa.com",
-       kEllipsisStr + ".\xCE\xB5.\xCE\xB6.com", Testcase::NO_IOS},
+    {"http://google.com", "google.com"},
+    {"http://reallyreallyreallylongdomainname.com",
+     "reallyreallyreallylongdomainname.com"},
+    {"http://foo", "foo"},
+    {"http://foo.bar", "foo.bar"},
+#if !defined(OS_IOS)
+    // iOS width calculations are off by a letter from other platforms for
+    // strings with too many kerned letters on the default font set.
+    // TODO(rohitrao): Fix secure_display::ElideHost for iOS
+    // (crbug.com/517604).
+    {"http://subdomain.google.com", kEllipsisStr + ".google.com"},
+    {"http://a.b.c.d.e.f.com", kEllipsisStr + "f.com"},
+    {"http://subdomain.foo.bar", kEllipsisStr + "in.foo.bar"},
+    {"http://subdomain.reallylongdomainname.com",
+     kEllipsisStr + "ain.reallylongdomainname.com"},
+    {"http://a.b.c.d.e.f.com", kEllipsisStr + ".e.f.com"},
+    // IDN - Greek alpha.beta.gamma.delta.epsilon.zeta.com
+    {"http://xn--mxa.xn--nxa.xn--oxa.xn--pxa.xn--qxa.xn--rxa.com",
+     kEllipsisStr + ".\xCE\xB5.\xCE\xB6.com"},
+#endif  // !defined(OS_IOS)
   };
 
   for (size_t i = 0; i < arraysize(testcases); ++i) {
-#if defined(OS_IOS)
-    if (testcases[i].platforms == Testcase::NO_IOS ||
-        (testcases[i].platforms == Testcase::NO_IOS9_OR_LATER &&
-         base::ios::IsRunningOnIOS9OrLater())) {
-      continue;
-    }
-#endif
     const float available_width = gfx::GetStringWidthF(
         base::UTF8ToUTF16(testcases[i].output), gfx::FontList());
     EXPECT_EQ(base::UTF8ToUTF16(testcases[i].output),
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 9eef6fcf..51ca75f 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -214,8 +214,6 @@
     "accessibility/accessibility_ui.h",
     "accessibility/ax_platform_position.cc",
     "accessibility/ax_platform_position.h",
-    "accessibility/ax_tree_id_registry.cc",
-    "accessibility/ax_tree_id_registry.h",
     "accessibility/browser_accessibility.cc",
     "accessibility/browser_accessibility.h",
     "accessibility/browser_accessibility_cocoa.h",
@@ -1091,6 +1089,8 @@
     "renderer_host/input/touch_event_queue.h",
     "renderer_host/input/touch_selection_controller_client_aura.cc",
     "renderer_host/input/touch_selection_controller_client_aura.h",
+    "renderer_host/input/touch_timeout_handler.cc",
+    "renderer_host/input/touch_timeout_handler.h",
     "renderer_host/input/touchpad_tap_suppression_controller.cc",
     "renderer_host/input/touchpad_tap_suppression_controller.h",
     "renderer_host/input/touchscreen_tap_suppression_controller.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 48f3f8d..cdf77cb 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -64,6 +64,7 @@
   "+third_party/WebKit/public/platform/WebCursorInfo.h",
   "+third_party/WebKit/public/platform/WebDisplayMode.h",
   "+third_party/WebKit/public/platform/WebDragOperation.h",
+  "+third_party/WebKit/public/platform/WebFeaturePolicy.h",
   "+third_party/WebKit/public/platform/WebFocusType.h",
   "+third_party/WebKit/public/platform/WebGamepad.h",
   "+third_party/WebKit/public/platform/WebGamepads.h",
diff --git a/content/browser/accessibility/ax_platform_position.h b/content/browser/accessibility/ax_platform_position.h
index d244f41e..a55832f 100644
--- a/content/browser/accessibility/ax_platform_position.h
+++ b/content/browser/accessibility/ax_platform_position.h
@@ -10,14 +10,14 @@
 #include <vector>
 
 #include "base/strings/string16.h"
-#include "content/browser/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_position.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
 
 namespace content {
 
 class BrowserAccessibility;
 
-using AXTreeID = content::AXTreeIDRegistry::AXTreeID;
+using AXTreeID = ui::AXTreeIDRegistry::AXTreeID;
 
 class AXPlatformPosition
     : public ui::AXPosition<AXPlatformPosition, BrowserAccessibility> {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 930502b..a0579ca 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -32,8 +32,10 @@
 using AXPlatformPositionInstance =
     content::AXPlatformPosition::AXPositionInstance;
 using AXPlatformRange = ui::AXRange<AXPlatformPositionInstance::element_type>;
+using AXTextMarkerRangeRef = CFTypeRef;
+using AXTextMarkerRef = CFTypeRef;
+using StringAttribute = ui::AXStringAttribute;
 using content::AXPlatformPosition;
-using content::AXTreeIDRegistry;
 using content::AccessibilityMatchPredicate;
 using content::BrowserAccessibility;
 using content::BrowserAccessibilityDelegate;
@@ -42,9 +44,7 @@
 using content::ContentClient;
 using content::OneShotAccessibilityTreeSearch;
 using ui::AXNodeData;
-using StringAttribute = ui::AXStringAttribute;
-using AXTextMarkerRef = CFTypeRef;
-using AXTextMarkerRangeRef = CFTypeRef;
+using ui::AXTreeIDRegistry;
 
 namespace {
 
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index ad4e430..971e831 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -5,6 +5,7 @@
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 
 #include <stddef.h>
+#include <utility>
 
 #include "base/logging.h"
 #include "build/build_config.h"
@@ -39,8 +40,8 @@
 }  // namespace
 
 // Map from AXTreeID to BrowserAccessibilityManager
-using AXTreeIDMap =
-    base::hash_map<AXTreeIDRegistry::AXTreeID, BrowserAccessibilityManager*>;
+using AXTreeIDMap = base::hash_map<ui::AXTreeIDRegistry::AXTreeID,
+                                   BrowserAccessibilityManager*>;
 base::LazyInstance<AXTreeIDMap> g_ax_tree_id_map = LAZY_INSTANCE_INITIALIZER;
 
 // A function to call when focus changes, for testing only.
@@ -116,7 +117,7 @@
 
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::FromID(
-    AXTreeIDRegistry::AXTreeID ax_tree_id) {
+    ui::AXTreeIDRegistry::AXTreeID ax_tree_id) {
   AXTreeIDMap* ax_tree_id_map = g_ax_tree_id_map.Pointer();
   auto iter = ax_tree_id_map->find(ax_tree_id);
   return iter == ax_tree_id_map->end() ? nullptr : iter->second;
@@ -133,7 +134,7 @@
       last_focused_node_(nullptr),
       last_focused_manager_(nullptr),
       connected_to_parent_tree_node_(false),
-      ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
+      ax_tree_id_(ui::AXTreeIDRegistry::kNoAXTreeID),
       parent_node_id_from_parent_tree_(0) {
   tree_->SetDelegate(this);
 }
@@ -149,7 +150,7 @@
       osk_state_(OSK_ALLOWED),
       last_focused_node_(nullptr),
       last_focused_manager_(nullptr),
-      ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
+      ax_tree_id_(ui::AXTreeIDRegistry::kNoAXTreeID),
       parent_node_id_from_parent_tree_(0) {
   tree_->SetDelegate(this);
   Initialize(initial_tree);
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 1eae5fa..b87ada2 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -15,7 +15,6 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "content/browser/accessibility/ax_platform_position.h"
-#include "content/browser/accessibility/ax_tree_id_registry.h"
 #include "content/browser/accessibility/browser_accessibility_event.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/ax_event_notification_details.h"
@@ -24,6 +23,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_range.h"
 #include "ui/accessibility/ax_serializable_tree.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_tree_update.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -118,7 +118,7 @@
       BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
 
   static BrowserAccessibilityManager* FromID(
-      AXTreeIDRegistry::AXTreeID ax_tree_id);
+      ui::AXTreeIDRegistry::AXTreeID ax_tree_id);
 
   ~BrowserAccessibilityManager() override;
 
@@ -325,7 +325,7 @@
       int end_offset);
 
   // Accessors.
-  AXTreeIDRegistry::AXTreeID ax_tree_id() const { return ax_tree_id_; }
+  ui::AXTreeIDRegistry::AXTreeID ax_tree_id() const { return ax_tree_id_; }
 
   // AXTreeDelegate implementation.
   void OnNodeDataWillChange(ui::AXTree* tree,
@@ -460,13 +460,14 @@
   bool connected_to_parent_tree_node_;
 
   // The global ID of this accessibility tree.
-  AXTreeIDRegistry::AXTreeID ax_tree_id_;
+  ui::AXTreeIDRegistry::AXTreeID ax_tree_id_;
 
   // If this tree has a parent tree, this is the cached ID of the parent
   // node within that parent tree. It's computed as needed and cached for
   // speed so that it can be accessed quickly if it hasn't changed.
   int parent_node_id_from_parent_tree_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager);
 };
 
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 713812a..ffe7e05 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -103,6 +103,9 @@
 namespace {
 
 const int kNumRetriesBeforeSoftwareFallback = 4;
+// The client_id used here should not conflict with the client_id generated
+// from RenderWidgetHostImpl.
+constexpr uint32_t kDefaultClientId = 0u;
 
 bool IsUsingMus() {
   return service_manager::ServiceManagerIsRemote();
@@ -175,7 +178,8 @@
 };
 
 GpuProcessTransportFactory::GpuProcessTransportFactory()
-    : task_graph_runner_(new cc::SingleThreadTaskGraphRunner),
+    : frame_sink_id_allocator_(kDefaultClientId),
+      task_graph_runner_(new cc::SingleThreadTaskGraphRunner),
       callback_factory_(this) {
   cc::SetClientNameForMetrics("Browser");
 
@@ -689,12 +693,7 @@
 }
 
 cc::FrameSinkId GpuProcessTransportFactory::AllocateFrameSinkId() {
-  // The FrameSinkId generated here must be unique with
-  // RenderWidgetHostViewAura's
-  // and RenderWidgetHostViewMac's FrameSinkId allocation.
-  // TODO(crbug.com/685777): Centralize allocation in one place for easier
-  // maintenance.
-  return cc::FrameSinkId(0, next_sink_id_++);
+  return frame_sink_id_allocator_.NextFrameSinkId();
 }
 
 void GpuProcessTransportFactory::SetDisplayVisible(ui::Compositor* compositor,
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index 4024c07b..a7f646bc 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -16,6 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
+#include "cc/surfaces/frame_sink_id_allocator.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "ui/compositor/compositor.h"
@@ -103,7 +104,7 @@
   SharedVulkanContextProvider();
 
   std::unique_ptr<cc::SurfaceManager> surface_manager_;
-  uint32_t next_sink_id_ = 1u;
+  cc::FrameSinkIdAllocator frame_sink_id_allocator_;
 
 #if defined(OS_WIN)
   // Used by output surface, stored in PerCompositorData.
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 243fd2d..12d723b 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -228,6 +228,7 @@
 }
 
 Response PageHandler::Navigate(const std::string& url,
+                               Maybe<std::string> referrer,
                                Page::FrameId* frame_id) {
   GURL gurl(url);
   if (!gurl.is_valid())
@@ -237,8 +238,10 @@
   if (!web_contents)
     return Response::InternalError();
 
-  web_contents->GetController()
-      .LoadURL(gurl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+  web_contents->GetController().LoadURL(
+      gurl,
+      Referrer(GURL(referrer.fromMaybe("")), blink::WebReferrerPolicyDefault),
+      ui::PAGE_TRANSITION_TYPED, std::string());
   return Response::FallThrough();
 }
 
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index c366e1532..4efbdbd 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -59,7 +59,9 @@
 
   Response Reload(Maybe<bool> bypassCache,
                   Maybe<std::string> script_to_evaluate_on_load) override;
-  Response Navigate(const std::string& url, Page::FrameId* frame_id) override;
+  Response Navigate(const std::string& url,
+                    Maybe<std::string> referrer,
+                    Page::FrameId* frame_id) override;
   Response StopLoading() override;
 
   using NavigationEntries = protocol::Array<Page::NavigationEntry>;
diff --git a/content/browser/download/docs/save-page-as.md b/content/browser/download/docs/save-page-as.md
index 223b815..8b170ef6 100644
--- a/content/browser/download/docs/save-page-as.md
+++ b/content/browser/download/docs/save-page-as.md
@@ -101,7 +101,7 @@
           `SavePackage::OnMHTMLGenerated`.
 
 Note: MHTML format is by default disabled in Save-Page-As UI on Windows, MacOS
-and Linux (it is the default on ChromeOS), but for testing this can be easily
+and Linux (it is the default on Chrome OS), but for testing this can be easily
 changed using `--save-page-as-mhtml` command line switch.
 
 
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 9d441ba..690241b 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -1101,6 +1101,12 @@
     new_entry = GetLastCommittedEntry()->CloneAndReplace(
         frame_entry, true, rfh->frame_tree_node(),
         delegate_->GetFrameTree()->root());
+    if (new_entry->GetURL().GetOrigin() != params.url.GetOrigin()) {
+      // TODO(jam): we had one report of this with a URL that was redirecting to
+      // only tildes. Until we understand that better, don't copy the cert in
+      // this case.
+      new_entry->GetSSL() = SSLStatus();
+    }
 
     // We expect |frame_entry| to be owned by |new_entry|.  This should never
     // fail, because it's the main frame.
@@ -1212,6 +1218,8 @@
     // meanwhile and no new page was created. We are stuck at the last committed
     // entry.
     entry = GetLastCommittedEntry();
+    CHECK(!is_in_page);
+    entry->GetSSL() = handle->ssl_status();
   } else if (params.nav_entry_id) {
     // This is a browser-initiated navigation (back/forward/reload).
     entry = GetEntryWithUniqueID(params.nav_entry_id);
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index a5459d6..9195f118 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -108,6 +108,7 @@
       is_stream_(false),
       started_from_context_menu_(started_from_context_menu),
       reload_type_(ReloadType::NONE),
+      restore_type_(RestoreType::NONE),
       navigation_type_(NAVIGATION_TYPE_UNKNOWN),
       weak_factory_(this) {
   DCHECK(!navigation_start.is_null());
@@ -130,8 +131,10 @@
       nav_entry = nav_controller->GetPendingEntry();
     }
 
-    if (nav_entry)
+    if (nav_entry) {
       reload_type_ = nav_entry->reload_type();
+      restore_type_ = nav_entry->restore_type();
+    }
   }
 
   if (!IsRendererDebugURL(url_))
@@ -452,6 +455,10 @@
   return reload_type_;
 }
 
+RestoreType NavigationHandleImpl::GetRestoreType() {
+  return restore_type_;
+}
+
 NavigationData* NavigationHandleImpl::GetNavigationData() {
   return navigation_data_.get();
 }
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index cb339d9b..ed4dc61 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -25,6 +25,7 @@
 #include "content/public/browser/navigation_data.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/navigation_type.h"
+#include "content/public/browser/restore_type.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/common/request_context_type.h"
 #include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
@@ -145,6 +146,7 @@
   const GURL& GetSearchableFormURL() override;
   const std::string& GetSearchableFormEncoding() override;
   ReloadType GetReloadType() override;
+  RestoreType GetRestoreType() override;
   const GlobalRequestID& GetGlobalRequestID() override;
 
   NavigationData* GetNavigationData() override;
@@ -487,6 +489,9 @@
   // Stores the reload type, or NONE if it's not a reload.
   ReloadType reload_type_;
 
+  // Stores the restore type, or NONE it it's not a restore.
+  RestoreType restore_type_;
+
   GURL searchable_form_url_;
   std::string searchable_form_encoding_;
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 263a9475..b39ba86 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -11,6 +11,7 @@
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
+#include "content/browser/frame_host/debug_urls.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/navigation_controller_impl.h"
@@ -552,8 +553,33 @@
   DCHECK(state_ == STARTED || state_ == RESPONSE_STARTED);
   state_ = FAILED;
   navigation_handle_->set_net_error_code(static_cast<net::Error>(net_error));
-  frame_tree_node_->navigator()->FailedNavigation(
-      frame_tree_node_, has_stale_copy_in_cache, net_error);
+
+  // With PlzNavigate, debug URLs will give a failed navigation because the
+  // WebUI backend won't find a handler for them. They will be processed in the
+  // renderer, however do not discard the pending entry so that the URL bar
+  // shows them correctly.
+  if (!IsRendererDebugURL(common_params_.url)) {
+    frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(
+        navigation_handle_.get());
+  }
+
+  // If the request was canceled by the user do not show an error page.
+  if (net_error == net::ERR_ABORTED) {
+    frame_tree_node_->ResetNavigationRequest(false);
+    return;
+  }
+
+  // Select an appropriate renderer to show the error page.
+  RenderFrameHostImpl* render_frame_host =
+      frame_tree_node_->render_manager()->GetFrameHostForNavigation(*this);
+  NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(render_frame_host,
+                                                           common_params_.url);
+
+  TransferNavigationHandleOwnership(render_frame_host);
+  render_frame_host->navigation_handle()->ReadyToCommitNavigation(
+      render_frame_host);
+  render_frame_host->FailedNavigation(common_params_, request_params_,
+                                      has_stale_copy_in_cache, net_error);
 }
 
 void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp) {
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index d322c01..5f0a059 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -157,15 +157,6 @@
                                  const BeginNavigationParams& begin_params);
 
   // PlzNavigate
-  // Called when a NavigationRequest for |frame_tree_node| failed. An
-  // appropriate RenderFrameHost should be selected and asked to show an error
-  // page. |has_stale_copy_in_cache| is true if there is a stale copy of the
-  // unreachable page in cache.
-  virtual void FailedNavigation(FrameTreeNode* frame_tree_node,
-                                bool has_stale_copy_in_cache,
-                                int error_code) {}
-
-  // PlzNavigate
   // Cancel a NavigationRequest for |frame_tree_node|. Called when
   // |frame_tree_node| is destroyed.
   virtual void CancelNavigation(FrameTreeNode* frame_tree_node) {}
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index b9e03c5..72bbe28 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -1040,43 +1040,6 @@
 }
 
 // PlzNavigate
-void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node,
-                                     bool has_stale_copy_in_cache,
-                                     int error_code) {
-  CHECK(IsBrowserSideNavigationEnabled());
-
-  NavigationRequest* navigation_request = frame_tree_node->navigation_request();
-  DCHECK(navigation_request);
-
-  // With PlzNavigate, debug URLs will give a failed navigation because the
-  // WebUI backend won't find a handler for them. They will be processed in the
-  // renderer, however do not discard the pending entry so that the URL bar
-  // shows them correctly.
-  if (!IsRendererDebugURL(navigation_request->navigation_handle()->GetURL()))
-    DiscardPendingEntryIfNeeded(navigation_request->navigation_handle());
-
-  // If the request was canceled by the user do not show an error page.
-  if (error_code == net::ERR_ABORTED) {
-    frame_tree_node->ResetNavigationRequest(false);
-    return;
-  }
-
-  // Select an appropriate renderer to show the error page.
-  RenderFrameHostImpl* render_frame_host =
-      frame_tree_node->render_manager()->GetFrameHostForNavigation(
-          *navigation_request);
-  CheckWebUIRendererDoesNotDisplayNormalURL(
-      render_frame_host, navigation_request->common_params().url);
-
-  navigation_request->TransferNavigationHandleOwnership(render_frame_host);
-  render_frame_host->navigation_handle()->ReadyToCommitNavigation(
-      render_frame_host);
-  render_frame_host->FailedNavigation(navigation_request->common_params(),
-                                      navigation_request->request_params(),
-                                      has_stale_copy_in_cache, error_code);
-}
-
-// PlzNavigate
 void NavigatorImpl::CancelNavigation(FrameTreeNode* frame_tree_node) {
   CHECK(IsBrowserSideNavigationEnabled());
   frame_tree_node->ResetNavigationRequest(false);
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index 8d3de3b..c461bcf 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -88,9 +88,6 @@
   void OnBeginNavigation(FrameTreeNode* frame_tree_node,
                          const CommonNavigationParams& common_params,
                          const BeginNavigationParams& begin_params) override;
-  void FailedNavigation(FrameTreeNode* frame_tree_node,
-                        bool has_stale_copy_in_cache,
-                        int error_code) override;
   void LogResourceRequestTime(base::TimeTicks timestamp,
                               const GURL& url) override;
   void LogBeforeUnloadTime(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 4bfe8a7..9677e350 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -17,7 +17,6 @@
 #include "base/process/kill.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/ax_tree_id_registry.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/bluetooth/web_bluetooth_service_impl.h"
@@ -109,6 +108,7 @@
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_tree_update.h"
 #include "ui/gfx/geometry/quad_f.h"
 #include "url/gurl.h"
@@ -298,10 +298,10 @@
 
 // static
 RenderFrameHostImpl* RenderFrameHostImpl::FromAXTreeID(
-    AXTreeIDRegistry::AXTreeID ax_tree_id) {
+    ui::AXTreeIDRegistry::AXTreeID ax_tree_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  AXTreeIDRegistry::FrameID frame_id =
-      AXTreeIDRegistry::GetInstance()->GetFrameID(ax_tree_id);
+  ui::AXTreeIDRegistry::FrameID frame_id =
+      ui::AXTreeIDRegistry::GetInstance()->GetFrameID(ax_tree_id);
   return RenderFrameHostImpl::FromID(frame_id.first, frame_id.second);
 }
 
@@ -336,7 +336,7 @@
       nav_entry_id_(0),
       accessibility_reset_token_(0),
       accessibility_reset_count_(0),
-      browser_plugin_embedder_ax_tree_id_(AXTreeIDRegistry::kNoAXTreeID),
+      browser_plugin_embedder_ax_tree_id_(ui::AXTreeIDRegistry::kNoAXTreeID),
       no_create_browser_accessibility_manager_for_testing_(false),
       web_ui_type_(WebUI::kNoWebUI),
       pending_web_ui_type_(WebUI::kNoWebUI),
@@ -457,8 +457,8 @@
   return routing_id_;
 }
 
-AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::GetAXTreeID() {
-  return AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID(
+ui::AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::GetAXTreeID() {
+  return ui::AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID(
       GetProcess()->GetID(), routing_id_);
 }
 
@@ -3235,7 +3235,7 @@
          (delegate_->GetAsWebContents() == nullptr);
 }
 
-AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::RoutingIDToAXTreeID(
+ui::AXTreeIDRegistry::AXTreeID RenderFrameHostImpl::RoutingIDToAXTreeID(
     int routing_id) {
   RenderFrameHostImpl* rfh = nullptr;
   RenderFrameProxyHost* rfph = RenderFrameProxyHost::FromID(
@@ -3254,23 +3254,22 @@
         rfh->frame_tree_node()->frame_tree() !=
             frame_tree_node()->frame_tree()) {
       AccessibilityFatalError();
-      return AXTreeIDRegistry::kNoAXTreeID;
+      return ui::AXTreeIDRegistry::kNoAXTreeID;
     }
   }
 
   if (!rfh)
-    return AXTreeIDRegistry::kNoAXTreeID;
+    return ui::AXTreeIDRegistry::kNoAXTreeID;
 
   return rfh->GetAXTreeID();
 }
 
-AXTreeIDRegistry::AXTreeID
-RenderFrameHostImpl::BrowserPluginInstanceIDToAXTreeID(
-    int instance_id) {
+ui::AXTreeIDRegistry::AXTreeID
+RenderFrameHostImpl::BrowserPluginInstanceIDToAXTreeID(int instance_id) {
   RenderFrameHostImpl* guest = static_cast<RenderFrameHostImpl*>(
       delegate()->GetGuestByInstanceID(this, instance_id));
   if (!guest)
-    return AXTreeIDRegistry::kNoAXTreeID;
+    return ui::AXTreeIDRegistry::kNoAXTreeID;
 
   // Create a mapping from the guest to its embedder's AX Tree ID, and
   // explicitly update the guest to propagate that mapping immediately.
@@ -3321,7 +3320,7 @@
   if (src.parent_routing_id != -1)
     dst->parent_tree_id = RoutingIDToAXTreeID(src.parent_routing_id);
 
-  if (browser_plugin_embedder_ax_tree_id_ != AXTreeIDRegistry::kNoAXTreeID)
+  if (browser_plugin_embedder_ax_tree_id_ != ui::AXTreeIDRegistry::kNoAXTreeID)
     dst->parent_tree_id = browser_plugin_embedder_ax_tree_id_;
 
   // If this is not the root frame tree node, we're done.
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index b1e92c0..597b989 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -131,13 +131,13 @@
 
   static RenderFrameHostImpl* FromID(int process_id, int routing_id);
   static RenderFrameHostImpl* FromAXTreeID(
-      AXTreeIDRegistry::AXTreeID ax_tree_id);
+      ui::AXTreeIDRegistry::AXTreeID ax_tree_id);
 
   ~RenderFrameHostImpl() override;
 
   // RenderFrameHost
   int GetRoutingID() override;
-  AXTreeIDRegistry::AXTreeID GetAXTreeID() override;
+  ui::AXTreeIDRegistry::AXTreeID GetAXTreeID() override;
   SiteInstanceImpl* GetSiteInstance() override;
   RenderProcessHost* GetProcess() override;
   RenderWidgetHostView* GetView() override;
@@ -498,7 +498,7 @@
 
   // Set the AX tree ID of the embedder RFHI, if this is a browser plugin guest.
   void set_browser_plugin_embedder_ax_tree_id(
-      AXTreeIDRegistry::AXTreeID ax_tree_id) {
+      ui::AXTreeIDRegistry::AXTreeID ax_tree_id) {
     browser_plugin_embedder_ax_tree_id_ = ax_tree_id;
   }
 
@@ -823,11 +823,12 @@
 
   // Map a routing ID from a frame in the same frame tree to a globally
   // unique AXTreeID.
-  AXTreeIDRegistry::AXTreeID RoutingIDToAXTreeID(int routing_id);
+  ui::AXTreeIDRegistry::AXTreeID RoutingIDToAXTreeID(int routing_id);
 
   // Map a browser plugin instance ID to the AXTreeID of the plugin's
   // main frame.
-  AXTreeIDRegistry::AXTreeID BrowserPluginInstanceIDToAXTreeID(int routing_id);
+  ui::AXTreeIDRegistry::AXTreeID BrowserPluginInstanceIDToAXTreeID(
+      int routing_id);
 
   // Convert the content-layer-specific AXContentNodeData to a general-purpose
   // AXNodeData structure.
@@ -1057,7 +1058,7 @@
   AXContentTreeData ax_content_tree_data_;
 
   // The AX tree ID of the embedder, if this is a browser plugin guest.
-  AXTreeIDRegistry::AXTreeID browser_plugin_embedder_ax_tree_id_;
+  ui::AXTreeIDRegistry::AXTreeID browser_plugin_embedder_ax_tree_id_;
 
   // The mapping from callback id to corresponding callback for pending
   // accessibility tree snapshot calls created by RequestAXTreeSnapshot.
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
index fb01dbc..fa072b9 100644
--- a/content/browser/media/media_internals.cc
+++ b/content/browser/media/media_internals.cc
@@ -301,6 +301,8 @@
 
   struct PipelineInfo {
     bool has_pipeline = false;
+    bool has_ever_played = false;
+    bool has_reached_have_enough = false;
     media::PipelineStatus last_pipeline_status = media::PIPELINE_OK;
     bool has_audio = false;
     bool has_video = false;
@@ -397,6 +399,10 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   PlayerInfoMap& player_info = renderer_info_[render_process_id];
   switch (event.type) {
+    case media::MediaLogEvent::PLAY: {
+      player_info[event.id].has_ever_played = true;
+      break;
+    }
     case media::MediaLogEvent::PIPELINE_STATE_CHANGED: {
       player_info[event.id].has_pipeline = true;
       break;
@@ -437,6 +443,12 @@
       if (event.params.HasKey("video_dds")) {
         event.params.GetBoolean("video_dds", &player_info[event.id].video_dds);
       }
+      if (event.params.HasKey("pipeline_buffering_state")) {
+        std::string buffering_state;
+        event.params.GetString("pipeline_buffering_state", &buffering_state);
+        if (buffering_state == "BUFFERING_HAVE_ENOUGH")
+          player_info[event.id].has_reached_have_enough = true;
+      }
       break;
     case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: {
       DVLOG(2) << "Processing watch time update.";
@@ -573,6 +585,11 @@
     UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback",
                           player_info.video_decoder_changed);
   }
+
+  // Report whether this player ever saw a playback event. Used to measure the
+  // effectiveness of efforts to reduce loaded-but-never-used players.
+  if (player_info.has_reached_have_enough)
+    UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played);
 }
 
 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated(
diff --git a/content/browser/renderer_host/context_provider_factory_impl_android.cc b/content/browser/renderer_host/context_provider_factory_impl_android.cc
index 2437ca8..c102a65 100644
--- a/content/browser/renderer_host/context_provider_factory_impl_android.cc
+++ b/content/browser/renderer_host/context_provider_factory_impl_android.cc
@@ -26,6 +26,10 @@
 
 namespace {
 
+// The client_id used here should not conflict with the client_id generated
+// from RenderWidgetHostImpl.
+constexpr uint32_t kDefaultClientId = 0u;
+
 ui::command_buffer_metrics::ContextType ToCommandBufferContextType(
     ui::ContextProviderFactory::ContextType context_type) {
   switch (context_type) {
@@ -66,7 +70,7 @@
     : gpu_channel_factory_(gpu_channel_factory),
       in_handle_pending_requests_(false),
       in_shutdown_(false),
-      next_sink_id_(1u),
+      frame_sink_id_allocator_(kDefaultClientId),
       weak_factory_(this) {
   DCHECK(gpu_channel_factory_);
 }
@@ -136,12 +140,7 @@
 }
 
 cc::FrameSinkId ContextProviderFactoryImpl::AllocateFrameSinkId() {
-  // The FrameSinkId generated here must be unique with
-  // RenderWidgetHostViewAndroid's
-  // FrameSinkId allocation.
-  // TODO(crbug.com/685777): Centralize allocation in one place for easier
-  // maintenance.
-  return cc::FrameSinkId(0 /* client_id */, next_sink_id_++);
+  return frame_sink_id_allocator_.NextFrameSinkId();
 }
 
 gpu::GpuMemoryBufferManager*
diff --git a/content/browser/renderer_host/context_provider_factory_impl_android.h b/content/browser/renderer_host/context_provider_factory_impl_android.h
index 79a529b..751cd420 100644
--- a/content/browser/renderer_host/context_provider_factory_impl_android.h
+++ b/content/browser/renderer_host/context_provider_factory_impl_android.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "cc/surfaces/frame_sink_id_allocator.h"
 #include "content/common/content_export.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
@@ -104,7 +105,7 @@
   base::OneShotTimer establish_gpu_channel_timeout_;
 
   std::unique_ptr<cc::SurfaceManager> surface_manager_;
-  uint32_t next_sink_id_;
+  cc::FrameSinkIdAllocator frame_sink_id_allocator_;
 
   base::WeakPtrFactory<ContextProviderFactoryImpl> weak_factory_;
 
diff --git a/content/browser/renderer_host/input/legacy_touch_event_queue.cc b/content/browser/renderer_host/input/legacy_touch_event_queue.cc
index c723964..9f685b8 100644
--- a/content/browser/renderer_host/input/legacy_touch_event_queue.cc
+++ b/content/browser/renderer_host/input/legacy_touch_event_queue.cc
@@ -11,7 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
-#include "content/browser/renderer_host/input/timeout_monitor.h"
+#include "content/browser/renderer_host/input/touch_timeout_handler.h"
 #include "content/common/input/web_touch_event_traits.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/gfx/geometry/point_f.h"
@@ -28,22 +28,6 @@
 // scrolling is active and possible.
 const double kAsyncTouchMoveIntervalSec = .2;
 
-TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent(
-    const TouchEventWithLatencyInfo& event_to_cancel) {
-  TouchEventWithLatencyInfo event = event_to_cancel;
-  WebTouchEventTraits::ResetTypeAndTouchStates(
-      WebInputEvent::TouchCancel,
-      // TODO(rbyers): Shouldn't we use a fresh timestamp?
-      event.event.timeStampSeconds(), &event.event);
-  return event;
-}
-
-bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
-  return (event.type() == WebInputEvent::TouchStart ||
-          event.type() == WebInputEvent::TouchMove) &&
-         event.dispatchType == WebInputEvent::Blocking;
-}
-
 // Compare all properties of touch points to determine the state.
 bool HasPointChanged(const WebTouchPoint& point_1,
                      const WebTouchPoint& point_2) {
@@ -62,219 +46,6 @@
 
 }  // namespace
 
-// Cancels a touch sequence if a touchstart or touchmove ack response is
-// sufficiently delayed.
-class LegacyTouchEventQueue::TouchTimeoutHandler {
- public:
-  TouchTimeoutHandler(LegacyTouchEventQueue* touch_queue,
-                      base::TimeDelta desktop_timeout_delay,
-                      base::TimeDelta mobile_timeout_delay)
-      : touch_queue_(touch_queue),
-        desktop_timeout_delay_(desktop_timeout_delay),
-        mobile_timeout_delay_(mobile_timeout_delay),
-        use_mobile_timeout_(false),
-        pending_ack_state_(PENDING_ACK_NONE),
-        timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut,
-                                    base::Unretained(this))),
-        enabled_(true),
-        enabled_for_current_sequence_(false),
-        sequence_awaiting_uma_update_(false),
-        sequence_using_mobile_timeout_(false) {
-    SetUseMobileTimeout(false);
-  }
-
-  ~TouchTimeoutHandler() { LogSequenceEndForUMAIfNecessary(false); }
-
-  void StartIfNecessary(const TouchEventWithLatencyInfo& event) {
-    if (pending_ack_state_ != PENDING_ACK_NONE)
-      return;
-
-    if (!enabled_)
-      return;
-
-    const base::TimeDelta timeout_delay = GetTimeoutDelay();
-    if (timeout_delay.is_zero())
-      return;
-
-    if (!ShouldTouchTriggerTimeout(event.event))
-      return;
-
-    if (WebTouchEventTraits::IsTouchSequenceStart(event.event)) {
-      LogSequenceStartForUMA();
-      enabled_for_current_sequence_ = true;
-    }
-
-    if (!enabled_for_current_sequence_)
-      return;
-
-    timeout_event_ = event;
-    timeout_monitor_.Restart(timeout_delay);
-  }
-
-  bool ConfirmTouchEvent(InputEventAckState ack_result) {
-    switch (pending_ack_state_) {
-      case PENDING_ACK_NONE:
-        if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
-          enabled_for_current_sequence_ = false;
-        timeout_monitor_.Stop();
-        return false;
-      case PENDING_ACK_ORIGINAL_EVENT:
-        if (AckedTimeoutEventRequiresCancel(ack_result)) {
-          SetPendingAckState(PENDING_ACK_CANCEL_EVENT);
-          TouchEventWithLatencyInfo cancel_event =
-              ObtainCancelEventForTouchEvent(timeout_event_);
-          touch_queue_->SendTouchEventImmediately(&cancel_event);
-        } else {
-          SetPendingAckState(PENDING_ACK_NONE);
-          touch_queue_->UpdateTouchConsumerStates(timeout_event_.event,
-                                                  ack_result);
-        }
-        return true;
-      case PENDING_ACK_CANCEL_EVENT:
-        SetPendingAckState(PENDING_ACK_NONE);
-        return true;
-    }
-    return false;
-  }
-
-  bool FilterEvent(const WebTouchEvent& event) {
-    if (!HasTimeoutEvent())
-      return false;
-
-    if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
-      // If a new sequence is observed while we're still waiting on the
-      // timed-out sequence response, also count the new sequence as timed-out.
-      LogSequenceStartForUMA();
-      LogSequenceEndForUMAIfNecessary(true);
-    }
-
-    return true;
-  }
-
-  void SetEnabled(bool enabled) {
-    if (enabled_ == enabled)
-      return;
-
-    enabled_ = enabled;
-
-    if (enabled_)
-      return;
-
-    enabled_for_current_sequence_ = false;
-    // Only reset the |timeout_handler_| if the timer is running and has not
-    // yet timed out. This ensures that an already timed out sequence is
-    // properly flushed by the handler.
-    if (IsTimeoutTimerRunning()) {
-      pending_ack_state_ = PENDING_ACK_NONE;
-      timeout_monitor_.Stop();
-    }
-  }
-
-  void SetUseMobileTimeout(bool use_mobile_timeout) {
-    use_mobile_timeout_ = use_mobile_timeout;
-  }
-
-  bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); }
-
-  bool IsEnabled() const { return enabled_ && !GetTimeoutDelay().is_zero(); }
-
- private:
-  enum PendingAckState {
-    PENDING_ACK_NONE,
-    PENDING_ACK_ORIGINAL_EVENT,
-    PENDING_ACK_CANCEL_EVENT,
-  };
-
-  void OnTimeOut() {
-    LogSequenceEndForUMAIfNecessary(true);
-    SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT);
-    touch_queue_->FlushQueue();
-  }
-
-  // Skip a cancel event if the timed-out event had no consumer and was the
-  // initial event in the gesture.
-  bool AckedTimeoutEventRequiresCancel(InputEventAckState ack_result) const {
-    DCHECK(HasTimeoutEvent());
-    if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
-      return true;
-    return !WebTouchEventTraits::IsTouchSequenceStart(timeout_event_.event);
-  }
-
-  void SetPendingAckState(PendingAckState new_pending_ack_state) {
-    DCHECK_NE(pending_ack_state_, new_pending_ack_state);
-    switch (new_pending_ack_state) {
-      case PENDING_ACK_ORIGINAL_EVENT:
-        DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
-        TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventTimeout", this);
-        break;
-      case PENDING_ACK_CANCEL_EVENT:
-        DCHECK_EQ(pending_ack_state_, PENDING_ACK_ORIGINAL_EVENT);
-        DCHECK(!timeout_monitor_.IsRunning());
-        DCHECK(touch_queue_->empty());
-        TRACE_EVENT_ASYNC_STEP_INTO0("input", "TouchEventTimeout", this,
-                                     "CancelEvent");
-        break;
-      case PENDING_ACK_NONE:
-        DCHECK(!timeout_monitor_.IsRunning());
-        DCHECK(touch_queue_->empty());
-        TRACE_EVENT_ASYNC_END0("input", "TouchEventTimeout", this);
-        break;
-    }
-    pending_ack_state_ = new_pending_ack_state;
-  }
-
-  void LogSequenceStartForUMA() {
-    // Always flush any unlogged entries before starting a new one.
-    LogSequenceEndForUMAIfNecessary(false);
-    sequence_awaiting_uma_update_ = true;
-    sequence_using_mobile_timeout_ = use_mobile_timeout_;
-  }
-
-  void LogSequenceEndForUMAIfNecessary(bool timed_out) {
-    if (!sequence_awaiting_uma_update_)
-      return;
-
-    sequence_awaiting_uma_update_ = false;
-
-    if (sequence_using_mobile_timeout_) {
-      UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnMobileSite", timed_out);
-    } else {
-      UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnDesktopSite", timed_out);
-    }
-  }
-
-  base::TimeDelta GetTimeoutDelay() const {
-    return use_mobile_timeout_ ? mobile_timeout_delay_ : desktop_timeout_delay_;
-  }
-
-  bool HasTimeoutEvent() const {
-    return pending_ack_state_ != PENDING_ACK_NONE;
-  }
-
-  LegacyTouchEventQueue* touch_queue_;
-
-  // How long to wait on a touch ack before cancelling the touch sequence.
-  const base::TimeDelta desktop_timeout_delay_;
-  const base::TimeDelta mobile_timeout_delay_;
-  bool use_mobile_timeout_;
-
-  // The touch event source for which we expect the next ack.
-  PendingAckState pending_ack_state_;
-
-  // The event for which the ack timeout is triggered.
-  TouchEventWithLatencyInfo timeout_event_;
-
-  // Provides timeout-based callback behavior.
-  TimeoutMonitor timeout_monitor_;
-
-  bool enabled_;
-  bool enabled_for_current_sequence_;
-
-  // Bookkeeping to classify and log whether a touch sequence times out.
-  bool sequence_awaiting_uma_update_;
-  bool sequence_using_mobile_timeout_;
-};
-
 // This class represents a single coalesced touch event. However, it also keeps
 // track of all the original touch-events that were coalesced into a single
 // event. The coalesced event is forwarded to the renderer, while the original
@@ -472,7 +243,8 @@
   DCHECK(!dispatching_touch_ack_);
   dispatching_touch_ = false;
 
-  if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result))
+  if (timeout_handler_ &&
+      timeout_handler_->ConfirmTouchEvent(unique_touch_event_id, ack_result))
     return;
 
   if (touch_queue_.empty())
@@ -719,6 +491,16 @@
   touch_queue_.pop_front();
 }
 
+void LegacyTouchEventQueue::SendTouchCancelEventForTouchEvent(
+    const TouchEventWithLatencyInfo& event_to_cancel) {
+  TouchEventWithLatencyInfo event = event_to_cancel;
+  WebTouchEventTraits::ResetTypeAndTouchStates(
+      WebInputEvent::TouchCancel,
+      // TODO(rbyers): Shouldn't we use a fresh timestamp?
+      event.event.timeStampSeconds(), &event.event);
+  SendTouchEventImmediately(&event);
+}
+
 void LegacyTouchEventQueue::SendTouchEventImmediately(
     TouchEventWithLatencyInfo* touch) {
   // TODO(crbug.com/600773): Hack to avoid cyclic reentry to this method.
@@ -794,7 +576,6 @@
     pending_async_touchmove_.reset();
     last_sent_touchevent_.reset();
 
-    touch_sequence_start_position_ = gfx::PointF(event.touches[0].position);
     drop_remaining_touches_in_sequence_ = false;
     if (!has_handlers_) {
       drop_remaining_touches_in_sequence_ = true;
diff --git a/content/browser/renderer_host/input/legacy_touch_event_queue.h b/content/browser/renderer_host/input/legacy_touch_event_queue.h
index 60f9c6b7..8468cde 100644
--- a/content/browser/renderer_host/input/legacy_touch_event_queue.h
+++ b/content/browser/renderer_host/input/legacy_touch_event_queue.h
@@ -24,6 +24,7 @@
 namespace content {
 
 class CoalescedWebTouchEvent;
+class TouchTimeoutHandler;
 
 // A queue for throttling and coalescing touch-events.
 class CONTENT_EXPORT LegacyTouchEventQueue : public TouchEventQueue {
@@ -95,8 +96,6 @@
   }
 
  private:
-  class TouchTimeoutHandler;
-  friend class TouchTimeoutHandler;
   friend class TouchEventQueueTest;
 
   bool HasPendingAsyncTouchMoveForTesting() const;
@@ -105,7 +104,7 @@
 
   // Empties the queue of touch events. This may result in any number of gesture
   // events being sent to the renderer.
-  void FlushQueue();
+  void FlushQueue() override;
 
   // Walks the queue, checking each event with |FilterBeforeForwarding()|.
   // If allowed, forwards the touch event and stops processing further events.
@@ -129,6 +128,10 @@
   void AckTouchEventToClient(InputEventAckState ack_result,
                              const ui::LatencyInfo* optional_latency_info);
 
+  // Dispatch a touch cancel event for the |event_to_cancel|.
+  void SendTouchCancelEventForTouchEvent(
+      const TouchEventWithLatencyInfo& event_to_cancel) override;
+
   // Dispatch |touch| to the client. Before dispatching, updates pointer
   // states in touchmove events for pointers that have not changed position.
   void SendTouchEventImmediately(TouchEventWithLatencyInfo* touch);
@@ -143,7 +146,7 @@
   PreFilterResult FilterBeforeForwarding(const blink::WebTouchEvent& event);
   void ForwardToRenderer(const TouchEventWithLatencyInfo& event);
   void UpdateTouchConsumerStates(const blink::WebTouchEvent& event,
-                                 InputEventAckState ack_result);
+                                 InputEventAckState ack_result) override;
   void FlushPendingAsyncTouchmove();
 
   // Handles touch event forwarding and ack'ed event dispatch.
@@ -151,10 +154,6 @@
 
   std::list<std::unique_ptr<CoalescedWebTouchEvent>> touch_queue_;
 
-  // Position of the first touch in the most recent sequence forwarded to the
-  // client.
-  gfx::PointF touch_sequence_start_position_;
-
   // Used to defer touch forwarding when ack dispatch triggers |QueueEvent()|.
   // True within the scope of |AckTouchEventToClient()|.
   bool dispatching_touch_ack_;
diff --git a/content/browser/renderer_host/input/touch_emulator.cc b/content/browser/renderer_host/input/touch_emulator.cc
index b30370b..2991879 100644
--- a/content/browser/renderer_host/input/touch_emulator.cc
+++ b/content/browser/renderer_host/input/touch_emulator.cc
@@ -461,7 +461,7 @@
   point.id = 0;
   point.radiusX = 0.5f * cursor_size_.width();
   point.radiusY = 0.5f * cursor_size_.height();
-  point.force = 1.f;
+  point.force = eventType == WebInputEvent::TouchEnd ? 0.f : 1.f;
   point.rotationAngle = 0.f;
   point.position.x = mouse_event.x;
   point.screenPosition.x = mouse_event.globalX;
diff --git a/content/browser/renderer_host/input/touch_event_queue.h b/content/browser/renderer_host/input/touch_event_queue.h
index 9384ee4..c1c4115 100644
--- a/content/browser/renderer_host/input/touch_event_queue.h
+++ b/content/browser/renderer_host/input/touch_event_queue.h
@@ -112,7 +112,19 @@
 
   virtual bool Empty() const WARN_UNUSED_RESULT = 0;
 
+ protected:
+  virtual void SendTouchCancelEventForTouchEvent(
+      const TouchEventWithLatencyInfo& event_to_cancel) = 0;
+
+  // Empties the queue of touch events. This may result in any number of gesture
+  // events being sent to the renderer.
+  virtual void FlushQueue() = 0;
+  virtual void UpdateTouchConsumerStates(const blink::WebTouchEvent& event,
+                                         InputEventAckState ack_result) = 0;
+
  private:
+  friend class TouchTimeoutHandler;
+
   DISALLOW_COPY_AND_ASSIGN(TouchEventQueue);
 };
 
diff --git a/content/browser/renderer_host/input/touch_timeout_handler.cc b/content/browser/renderer_host/input/touch_timeout_handler.cc
new file mode 100644
index 0000000..a3bf256
--- /dev/null
+++ b/content/browser/renderer_host/input/touch_timeout_handler.cc
@@ -0,0 +1,216 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/input/touch_timeout_handler.h"
+
+#include <utility>
+
+#include "base/auto_reset.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
+#include "content/browser/renderer_host/input/touch_event_queue.h"
+#include "content/common/input/web_touch_event_traits.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/gfx/geometry/point_f.h"
+
+using blink::WebInputEvent;
+using blink::WebTouchEvent;
+using blink::WebTouchPoint;
+using ui::LatencyInfo;
+
+namespace content {
+namespace {
+
+bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
+  return (event.type() == WebInputEvent::TouchStart ||
+          event.type() == WebInputEvent::TouchMove) &&
+         event.dispatchType == WebInputEvent::Blocking;
+}
+
+}  // namespace
+
+TouchTimeoutHandler::TouchTimeoutHandler(TouchEventQueue* touch_queue,
+                                         base::TimeDelta desktop_timeout_delay,
+                                         base::TimeDelta mobile_timeout_delay)
+    : touch_queue_(touch_queue),
+      desktop_timeout_delay_(desktop_timeout_delay),
+      mobile_timeout_delay_(mobile_timeout_delay),
+      use_mobile_timeout_(false),
+      pending_ack_state_(PENDING_ACK_NONE),
+      timeout_monitor_(
+          base::Bind(&TouchTimeoutHandler::OnTimeOut, base::Unretained(this))),
+      enabled_(true),
+      enabled_for_current_sequence_(false),
+      sequence_awaiting_uma_update_(false),
+      sequence_using_mobile_timeout_(false) {
+  SetUseMobileTimeout(false);
+}
+
+TouchTimeoutHandler::~TouchTimeoutHandler() {
+  LogSequenceEndForUMAIfNecessary(false);
+}
+
+void TouchTimeoutHandler::StartIfNecessary(
+    const TouchEventWithLatencyInfo& event) {
+  if (pending_ack_state_ != PENDING_ACK_NONE)
+    return;
+
+  if (!enabled_)
+    return;
+
+  const base::TimeDelta timeout_delay = GetTimeoutDelay();
+  if (timeout_delay.is_zero())
+    return;
+
+  if (!ShouldTouchTriggerTimeout(event.event))
+    return;
+
+  if (WebTouchEventTraits::IsTouchSequenceStart(event.event)) {
+    LogSequenceStartForUMA();
+    enabled_for_current_sequence_ = true;
+  }
+
+  if (!enabled_for_current_sequence_)
+    return;
+
+  timeout_event_ = event;
+  timeout_monitor_.Restart(timeout_delay);
+}
+
+bool TouchTimeoutHandler::ConfirmTouchEvent(uint32_t unique_touch_event_id,
+                                            InputEventAckState ack_result) {
+  if (timeout_event_.event.uniqueTouchEventId != unique_touch_event_id)
+    return false;
+
+  switch (pending_ack_state_) {
+    case PENDING_ACK_NONE:
+      if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+        enabled_for_current_sequence_ = false;
+      timeout_monitor_.Stop();
+      return false;
+    case PENDING_ACK_ORIGINAL_EVENT:
+      if (AckedTimeoutEventRequiresCancel(ack_result)) {
+        SetPendingAckState(PENDING_ACK_CANCEL_EVENT);
+        touch_queue_->SendTouchCancelEventForTouchEvent(timeout_event_);
+      } else {
+        SetPendingAckState(PENDING_ACK_NONE);
+        touch_queue_->UpdateTouchConsumerStates(timeout_event_.event,
+                                                ack_result);
+      }
+      return true;
+    case PENDING_ACK_CANCEL_EVENT:
+      SetPendingAckState(PENDING_ACK_NONE);
+      return true;
+  }
+  return false;
+}
+
+bool TouchTimeoutHandler::FilterEvent(const WebTouchEvent& event) {
+  if (!HasTimeoutEvent())
+    return false;
+
+  if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
+    // If a new sequence is observed while we're still waiting on the
+    // timed-out sequence response, also count the new sequence as timed-out.
+    LogSequenceStartForUMA();
+    LogSequenceEndForUMAIfNecessary(true);
+  }
+
+  return true;
+}
+
+void TouchTimeoutHandler::SetEnabled(bool enabled) {
+  if (enabled_ == enabled)
+    return;
+
+  enabled_ = enabled;
+
+  if (enabled_)
+    return;
+
+  enabled_for_current_sequence_ = false;
+  // Only reset the |timeout_handler_| if the timer is running and has not
+  // yet timed out. This ensures that an already timed out sequence is
+  // properly flushed by the handler.
+  if (IsTimeoutTimerRunning()) {
+    pending_ack_state_ = PENDING_ACK_NONE;
+    timeout_monitor_.Stop();
+  }
+}
+
+void TouchTimeoutHandler::SetUseMobileTimeout(bool use_mobile_timeout) {
+  use_mobile_timeout_ = use_mobile_timeout;
+}
+
+void TouchTimeoutHandler::OnTimeOut() {
+  LogSequenceEndForUMAIfNecessary(true);
+  SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT);
+  touch_queue_->FlushQueue();
+}
+
+// Skip a cancel event if the timed-out event had no consumer and was the
+// initial event in the gesture.
+bool TouchTimeoutHandler::AckedTimeoutEventRequiresCancel(
+    InputEventAckState ack_result) const {
+  DCHECK(HasTimeoutEvent());
+  if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
+    return true;
+  return !WebTouchEventTraits::IsTouchSequenceStart(timeout_event_.event);
+}
+
+void TouchTimeoutHandler::SetPendingAckState(
+    PendingAckState new_pending_ack_state) {
+  DCHECK_NE(pending_ack_state_, new_pending_ack_state);
+  switch (new_pending_ack_state) {
+    case PENDING_ACK_ORIGINAL_EVENT:
+      DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
+      TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventTimeout", this);
+      break;
+    case PENDING_ACK_CANCEL_EVENT:
+      DCHECK_EQ(pending_ack_state_, PENDING_ACK_ORIGINAL_EVENT);
+      DCHECK(!timeout_monitor_.IsRunning());
+      DCHECK(touch_queue_->Empty());
+      TRACE_EVENT_ASYNC_STEP_INTO0("input", "TouchEventTimeout", this,
+                                   "CancelEvent");
+      break;
+    case PENDING_ACK_NONE:
+      DCHECK(!timeout_monitor_.IsRunning());
+      DCHECK(touch_queue_->Empty());
+      TRACE_EVENT_ASYNC_END0("input", "TouchEventTimeout", this);
+      break;
+  }
+  pending_ack_state_ = new_pending_ack_state;
+}
+
+void TouchTimeoutHandler::LogSequenceStartForUMA() {
+  // Always flush any unlogged entries before starting a new one.
+  LogSequenceEndForUMAIfNecessary(false);
+  sequence_awaiting_uma_update_ = true;
+  sequence_using_mobile_timeout_ = use_mobile_timeout_;
+}
+
+void TouchTimeoutHandler::LogSequenceEndForUMAIfNecessary(bool timed_out) {
+  if (!sequence_awaiting_uma_update_)
+    return;
+
+  sequence_awaiting_uma_update_ = false;
+
+  if (sequence_using_mobile_timeout_) {
+    UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnMobileSite", timed_out);
+  } else {
+    UMA_HISTOGRAM_BOOLEAN("Event.Touch.TimedOutOnDesktopSite", timed_out);
+  }
+}
+
+base::TimeDelta TouchTimeoutHandler::GetTimeoutDelay() const {
+  return use_mobile_timeout_ ? mobile_timeout_delay_ : desktop_timeout_delay_;
+}
+
+bool TouchTimeoutHandler::HasTimeoutEvent() const {
+  return pending_ack_state_ != PENDING_ACK_NONE;
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/input/touch_timeout_handler.h b/content/browser/renderer_host/input/touch_timeout_handler.h
new file mode 100644
index 0000000..1556ff36
--- /dev/null
+++ b/content/browser/renderer_host/input/touch_timeout_handler.h
@@ -0,0 +1,81 @@
+// 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 CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_TIMEOUT_HANDLER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_TIMEOUT_HANDLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "content/browser/renderer_host/event_with_latency_info.h"
+#include "content/browser/renderer_host/input/timeout_monitor.h"
+#include "content/common/input/input_event_ack_state.h"
+
+namespace content {
+
+class TouchEventQueue;
+
+class TouchTimeoutHandler {
+ public:
+  TouchTimeoutHandler(TouchEventQueue* touch_queue,
+                      base::TimeDelta desktop_timeout_delay,
+                      base::TimeDelta mobile_timeout_delay);
+
+  ~TouchTimeoutHandler();
+
+  void StartIfNecessary(const TouchEventWithLatencyInfo& event);
+  bool ConfirmTouchEvent(uint32_t unique_touch_event_id,
+                         InputEventAckState ack_result);
+  bool FilterEvent(const blink::WebTouchEvent& event);
+  void SetEnabled(bool enabled);
+  void SetUseMobileTimeout(bool use_mobile_timeout);
+  bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); }
+  bool IsEnabled() const { return enabled_ && !GetTimeoutDelay().is_zero(); }
+
+ private:
+  enum PendingAckState {
+    PENDING_ACK_NONE,
+    PENDING_ACK_ORIGINAL_EVENT,
+    PENDING_ACK_CANCEL_EVENT,
+  };
+
+  void OnTimeOut();
+  // Skip a cancel event if the timed-out event had no consumer and was the
+  // initial event in the gesture.
+  bool AckedTimeoutEventRequiresCancel(InputEventAckState ack_result) const;
+  void SetPendingAckState(PendingAckState new_pending_ack_state);
+  void LogSequenceStartForUMA();
+  void LogSequenceEndForUMAIfNecessary(bool timed_out);
+  base::TimeDelta GetTimeoutDelay() const;
+  bool HasTimeoutEvent() const;
+
+  TouchEventQueue* touch_queue_;
+
+  // How long to wait on a touch ack before cancelling the touch sequence.
+  const base::TimeDelta desktop_timeout_delay_;
+  const base::TimeDelta mobile_timeout_delay_;
+  bool use_mobile_timeout_;
+
+  // The touch event source for which we expect the next ack.
+  PendingAckState pending_ack_state_;
+
+  // The event for which the ack timeout is triggered.
+  TouchEventWithLatencyInfo timeout_event_;
+
+  // Provides timeout-based callback behavior.
+  TimeoutMonitor timeout_monitor_;
+
+  bool enabled_;
+  bool enabled_for_current_sequence_;
+
+  // Bookkeeping to classify and log whether a touch sequence times out.
+  bool sequence_awaiting_uma_update_;
+  bool sequence_using_mobile_timeout_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_TIMEOUT_HANDLER_H_
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 9b64f82..0f488d8 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -95,6 +95,10 @@
 
 #if defined(OS_ANDROID)
 #include "ui/android/view_android.h"
+#else
+#include "content/browser/compositor/image_transport_factory.h"
+// nogncheck as dependency of "ui/compositor" is on non-Android platforms only.
+#include "ui/compositor/compositor.h"  // nogncheck
 #endif
 
 #if defined(OS_MACOSX)
@@ -425,6 +429,23 @@
   return view_.get();
 }
 
+cc::FrameSinkId RenderWidgetHostImpl::AllocateFrameSinkId(
+    bool is_guest_view_hack) {
+// GuestViews have two RenderWidgetHostViews and so we need to make sure
+// we don't have FrameSinkId collisions.
+// The FrameSinkId generated here must not conflict with FrameSinkId allocated
+// in cc::FrameSinkIdAllocator.
+#if !defined(OS_ANDROID)
+  if (is_guest_view_hack) {
+    ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+    return factory->GetContextFactoryPrivate()->AllocateFrameSinkId();
+  }
+#endif
+  return cc::FrameSinkId(
+      base::checked_cast<uint32_t>(this->GetProcess()->GetID()),
+      base::checked_cast<uint32_t>(this->GetRoutingID()));
+}
+
 void RenderWidgetHostImpl::ResetSizeAndRepaintPendingFlags() {
   resize_ack_pending_ = false;
   if (repaint_ack_pending_) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 1db87d0..8d83000 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -25,6 +25,7 @@
 #include "base/timer/elapsed_timer.h"
 #include "build/build_config.h"
 #include "cc/resources/shared_bitmap.h"
+#include "cc/surfaces/frame_sink_id.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
 #include "content/browser/renderer_host/input/input_ack_handler.h"
 #include "content/browser/renderer_host/input/input_router_client.h"
@@ -135,6 +136,8 @@
 
   RenderWidgetHostOwnerDelegate* owner_delegate() { return owner_delegate_; }
 
+  cc::FrameSinkId AllocateFrameSinkId(bool is_guest_view_hack);
+
   // RenderWidgetHost implementation.
   void UpdateTextDirection(blink::WebTextDirection direction) override;
   void NotifyTextDirection() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 02d54e8..3d1d70d 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -440,13 +440,8 @@
   // layer is managed by the DelegatedFrameHost.
   view_.SetLayer(cc::Layer::Create());
   if (using_browser_compositor_) {
-    // This FrameSinkId must be unique with ContextProviderFactory's FrameSinkId
-    // allocation.
-    // TODO(crbug.com/685777): Centralize allocation in one place for easier
-    // maintenance.
-    cc::FrameSinkId frame_sink_id = cc::FrameSinkId(
-        base::checked_cast<uint32_t>(host_->GetProcess()->GetID()),
-        base::checked_cast<uint32_t>(host_->GetRoutingID()));
+    cc::FrameSinkId frame_sink_id =
+        host_->AllocateFrameSinkId(false /* is_guest_view_hack */);
     delegated_frame_host_.reset(new ui::DelegatedFrameHostAndroid(
         &view_, cached_background_color_, this, frame_sink_id));
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 74e7ed4..010e059 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1922,19 +1922,9 @@
   if (IsMus())
     return;
 
-  // GuestViews have two RenderWidgetHostViews and so we need to make sure
-  // we don't have FrameSinkId collisions.
-  // The FrameSinkId generated here must be unique with FrameSinkId allocated
-  // in ContextFactoryPrivate.
-  // TODO(crbug.com/685777): Centralize allocation in one place for easier
-  // maintenance.
-  ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
   cc::FrameSinkId frame_sink_id =
-      is_guest_view_hack_
-          ? factory->GetContextFactoryPrivate()->AllocateFrameSinkId()
-          : cc::FrameSinkId(
-                base::checked_cast<uint32_t>(host_->GetProcess()->GetID()),
-                base::checked_cast<uint32_t>(host_->GetRoutingID()));
+      host_->AllocateFrameSinkId(is_guest_view_hack_);
+
   // Tests may set |delegated_frame_host_client_|.
   if (!delegated_frame_host_client_) {
     delegated_frame_host_client_ =
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index f2c270f..3609b89 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -470,20 +470,8 @@
   [cocoa_view_ setLayer:background_layer_];
   [cocoa_view_ setWantsLayer:YES];
 
-  // GuestViews have two RenderWidgetHostViews and so we need to make sure
-  // we don't have FrameSinkId collisions.
-  // The FrameSinkId generated here must be unique with FrameSinkId allocated
-  // in ContextFactoryPrivate.
-  // TODO(crbug.com/685777): Centralize allocation in one place for easier
-  // maintenance.
-  ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
   cc::FrameSinkId frame_sink_id =
-      is_guest_view_hack_
-          ? factory->GetContextFactoryPrivate()->AllocateFrameSinkId()
-          : cc::FrameSinkId(base::checked_cast<uint32_t>(
-                                render_widget_host_->GetProcess()->GetID()),
-                            base::checked_cast<uint32_t>(
-                                render_widget_host_->GetRoutingID()));
+      render_widget_host_->AllocateFrameSinkId(is_guest_view_hack_);
   browser_compositor_.reset(
       new BrowserCompositorMac(this, this, render_widget_host_->is_hidden(),
                                [cocoa_view_ window], frame_sink_id));
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 042d920..00bbf733 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -70,7 +70,9 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
@@ -9190,6 +9192,74 @@
       FrameHostMsg_ContextMenu(rfh->GetRoutingID(), ContextMenuParams()));
 }
 
+// Test iframe "allow" attribute is propagated correctly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessFeaturePolicyBrowserTest, AllowedIFrames) {
+  GURL url(embedded_test_server()->GetURL("/allowed_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+  // Iframes without "allow" attribute, or an empty "allow" attribute will not
+  // have any allowed features propagated.
+  EXPECT_TRUE(
+      root->child_at(0)->frame_owner_properties().allowed_features.empty());
+  EXPECT_TRUE(
+      root->child_at(1)->frame_owner_properties().allowed_features.empty());
+
+  // Make sure the third frame starts out at the correct cross-site page.
+  EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
+            root->child_at(2)->current_url());
+  // Check allowed features are propagated correctly for cross-site iframes.
+  EXPECT_EQ(root->child_at(2)->frame_owner_properties().allowed_features.size(),
+            2u);
+  EXPECT_EQ(root->child_at(2)->frame_owner_properties().allowed_features[0],
+            blink::WebFeaturePolicyFeature::Fullscreen);
+  EXPECT_EQ(root->child_at(2)->frame_owner_properties().allowed_features[1],
+            blink::WebFeaturePolicyFeature::Vibrate);
+
+  // Check allowed features are propagated correctly for same-site iframes.
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features.size(),
+            2u);
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features[0],
+            blink::WebFeaturePolicyFeature::Fullscreen);
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features[1],
+            blink::WebFeaturePolicyFeature::Vibrate);
+}
+
+// Test dynamic updates to iframe "allow" attribute are propagated correctly.
+IN_PROC_BROWSER_TEST_F(SitePerProcessFeaturePolicyBrowserTest,
+                       AllowedIFramesDynamic) {
+  GURL main_url(embedded_test_server()->GetURL("/allowed_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+  // Test for dynamically removing "allow" attribute.
+  EXPECT_TRUE(ExecuteScript(
+      root, "document.getElementById('child-2').removeAttribute('allow')"));
+  EXPECT_TRUE(
+      root->child_at(2)->frame_owner_properties().allowed_features.empty());
+
+  // Test for dynamically setting "allow" attribute by element.setAttribute.
+  EXPECT_TRUE(ExecuteScript(
+      root,
+      "document.getElementById('child-3').setAttribute('allow', 'payment')"));
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features.size(),
+            1u);
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features[0],
+            blink::WebFeaturePolicyFeature::Payment);
+
+  // Test for dynamically setting "allow" attribute by frame.allow="...".
+  EXPECT_TRUE(ExecuteScript(
+      root, "document.getElementById('child-3').allow='fullscreen vibrate'"));
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features.size(),
+            2u);
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features[0],
+            blink::WebFeaturePolicyFeature::Fullscreen);
+  EXPECT_EQ(root->child_at(3)->frame_owner_properties().allowed_features[1],
+            blink::WebFeaturePolicyFeature::Vibrate);
+}
+
 // Test harness that allows for "barrier" style delaying of requests matching
 // certain paths. Call SetDelayedRequestsForPath to delay requests, then
 // SetUpEmbeddedTestServer to register handlers and start the server.
diff --git a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
index 5c66497..085df8f 100644
--- a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
+++ b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
@@ -63,6 +63,9 @@
     // Allow <video>/<audio>.play() when not initiated by user gesture.
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kDisableGestureRequirementForMediaPlayback);
+    // Allow experimental canvas features.
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kEnableExperimentalCanvasFeatures);
   }
 
  private:
@@ -85,6 +88,12 @@
   MakeTypicalCall("testCanvasCapture(drawWebGL);", kCanvasCaptureTestHtmlFile);
 }
 
+IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
+                       VerifyCanvasCaptureOffscreenCanvasCommitFrames) {
+  MakeTypicalCall("testCanvasCapture(drawOffscreenCanvasCommit);",
+                  kCanvasCaptureTestHtmlFile);
+}
+
 IN_PROC_BROWSER_TEST_P(WebRtcCaptureFromElementBrowserTest,
                        MAYBE_CaptureFromMediaElement) {
 #if defined(OS_ANDROID)
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index aca87946..6993ee1 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -49,6 +49,7 @@
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_platform_file.h"
 #include "ppapi/features/features.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
 #include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
@@ -113,6 +114,8 @@
                           content::FileChooserParams::Save)
 IPC_ENUM_TRAITS_MAX_VALUE(content::CSPDirective::Name,
                           content::CSPDirective::NameLast)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFeaturePolicyFeature,
+                          blink::WebFeaturePolicyFeature::LAST_FEATURE)
 
 IPC_STRUCT_TRAITS_BEGIN(blink::WebFindOptions)
   IPC_STRUCT_TRAITS_MEMBER(forward)
@@ -180,6 +183,7 @@
   IPC_STRUCT_TRAITS_MEMBER(allow_fullscreen)
   IPC_STRUCT_TRAITS_MEMBER(allow_payment_request)
   IPC_STRUCT_TRAITS_MEMBER(required_csp)
+  IPC_STRUCT_TRAITS_MEMBER(allowed_features)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(content::PageImportanceSignals)
diff --git a/content/common/frame_owner_properties.cc b/content/common/frame_owner_properties.cc
index ef7dac13..8e0f7ead 100644
--- a/content/common/frame_owner_properties.cc
+++ b/content/common/frame_owner_properties.cc
@@ -19,15 +19,16 @@
 FrameOwnerProperties::~FrameOwnerProperties() {}
 
 bool FrameOwnerProperties::operator==(const FrameOwnerProperties& other) const {
-  return name == other.name &&
-         scrolling_mode == other.scrolling_mode &&
+  return name == other.name && scrolling_mode == other.scrolling_mode &&
          margin_width == other.margin_width &&
          margin_height == other.margin_height &&
          allow_fullscreen == other.allow_fullscreen &&
          allow_payment_request == other.allow_payment_request &&
          required_csp == other.required_csp &&
          std::equal(delegated_permissions.begin(), delegated_permissions.end(),
-                    other.delegated_permissions.begin());
+                    other.delegated_permissions.begin()) &&
+         std::equal(allowed_features.begin(), allowed_features.end(),
+                    other.allowed_features.begin());
 }
 
 }  // namespace content
diff --git a/content/common/frame_owner_properties.h b/content/common/frame_owner_properties.h
index 7773d406..20d3510 100644
--- a/content/common/frame_owner_properties.h
+++ b/content/common/frame_owner_properties.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "content/common/content_export.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission.mojom.h"
 #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h"
 
@@ -41,6 +42,7 @@
   std::string required_csp;
 
   std::vector<blink::mojom::PermissionName> delegated_permissions;
+  std::vector<blink::WebFeaturePolicyFeature> allowed_features;
 };
 
 }  // namespace content
diff --git a/content/common/input/synthetic_web_input_event_builders.cc b/content/common/input/synthetic_web_input_event_builders.cc
index b949108..6533863 100644
--- a/content/common/input/synthetic_web_input_event_builders.cc
+++ b/content/common/input/synthetic_web_input_event_builders.cc
@@ -230,6 +230,7 @@
   CHECK_GE(index, 0);
   CHECK_LT(index, kTouchesLengthCap);
   touches[index].state = WebTouchPoint::StateReleased;
+  touches[index].force = 0.f;
   WebTouchEventTraits::ResetType(WebInputEvent::TouchEnd, timeStampSeconds(),
                                  this);
 }
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 0f3892c..f06bbc7b 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -11,6 +11,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/reload_type.h"
+#include "content/public/browser/restore_type.h"
 #include "content/public/common/referrer.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
@@ -105,6 +106,10 @@
   // ReloadType::NONE.
   virtual ReloadType GetReloadType() = 0;
 
+  // Returns the restore type for this navigation. RestoreType::NONE is returned
+  // if the navigation is not a restore.
+  virtual RestoreType GetRestoreType() = 0;
+
   // Parameters available at network request start time ------------------------
   //
   // The following parameters are only available when the network request is
diff --git a/content/public/renderer/resource_fetcher.h b/content/public/renderer/resource_fetcher.h
index 9b89765..ba75a4e 100644
--- a/content/public/renderer/resource_fetcher.h
+++ b/content/public/renderer/resource_fetcher.h
@@ -53,7 +53,6 @@
   // done.
   virtual void Start(blink::WebFrame* frame,
                      blink::WebURLRequest::RequestContext request_context,
-                     blink::WebURLRequest::FrameType frame_type,
                      const Callback& callback) = 0;
 
   // Sets how long to wait for the server to reply.  By default, there is no
diff --git a/content/public/test/render_view_test.h b/content/public/test/render_view_test.h
index 38d6f48..a14e4ec 100644
--- a/content/public/test/render_view_test.h
+++ b/content/public/test/render_view_test.h
@@ -13,7 +13,6 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string16.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/test/test_io_thread.h"
 #include "build/build_config.h"
 #include "content/public/browser/native_web_keyboard_event.h"
@@ -191,14 +190,7 @@
   // blink::WebLeakDetectorClient implementation.
   void onLeakDetectionComplete(const Result& result) override;
 
- private:
   base::MessageLoop msg_loop_;
-
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
-
- protected:
   std::unique_ptr<FakeCompositorDependencies> compositor_deps_;
   std::unique_ptr<MockRenderProcess> mock_process_;
   // We use a naked pointer because we don't want to expose RenderViewImpl in
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index dbe6bc5..b7ee72c 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -172,7 +172,6 @@
 void ResourceFetcherImpl::Start(
     blink::WebFrame* frame,
     blink::WebURLRequest::RequestContext request_context,
-    blink::WebURLRequest::FrameType frame_type,
     const Callback& callback) {
   DCHECK(!loader_);
   DCHECK(!client_);
@@ -181,7 +180,6 @@
     DCHECK_NE("GET", request_.httpMethod().utf8()) << "GETs can't have bodies.";
 
   request_.setRequestContext(request_context);
-  request_.setFrameType(frame_type);
   request_.setFirstPartyForCookies(frame->document().firstPartyForCookies());
   request_.addHTTPOriginIfNeeded(blink::WebSecurityOrigin::createUnique());
 
diff --git a/content/renderer/fetchers/resource_fetcher_impl.h b/content/renderer/fetchers/resource_fetcher_impl.h
index 70c0d2a..fb13047 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.h
+++ b/content/renderer/fetchers/resource_fetcher_impl.h
@@ -32,7 +32,6 @@
   void SetHeader(const std::string& header, const std::string& value) override;
   void Start(blink::WebFrame* frame,
              blink::WebURLRequest::RequestContext request_context,
-             blink::WebURLRequest::FrameType frame_type,
              const Callback& callback) override;
   void SetTimeout(const base::TimeDelta& timeout) override;
 
diff --git a/content/renderer/frame_owner_properties.cc b/content/renderer/frame_owner_properties.cc
index d885fa1..bd0b4ce 100644
--- a/content/renderer/frame_owner_properties.cc
+++ b/content/renderer/frame_owner_properties.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <iterator>
 
+#include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission.mojom.h"
 
 namespace content {
@@ -25,6 +26,9 @@
   std::copy(web_frame_owner_properties.delegatedPermissions.begin(),
             web_frame_owner_properties.delegatedPermissions.end(),
             std::back_inserter(result.delegated_permissions));
+  std::copy(web_frame_owner_properties.allowedFeatures.begin(),
+            web_frame_owner_properties.allowedFeatures.end(),
+            std::back_inserter(result.allowed_features));
 
   return result;
 }
@@ -44,6 +48,8 @@
       blink::WebString::fromUTF8(frame_owner_properties.required_csp);
   result.delegatedPermissions = blink::WebVector<blink::mojom::PermissionName>(
       frame_owner_properties.delegated_permissions);
+  result.allowedFeatures = blink::WebVector<blink::WebFeaturePolicyFeature>(
+      frame_owner_properties.allowed_features);
 
   return result;
 }
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index 1ff102e6..691e768 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -389,19 +389,26 @@
     const RequestSettings& request_settings,
     const VideoCaptureSourceSelectionResult& selection_result) {
   DCHECK(CalledOnValidThread());
-  // Select video device.
-  if (!selection_result.has_value()) {
+  if (selection_result.has_value()) {
+    controls->video.device_id = selection_result.settings.device_id();
+  } else {
+    // TODO(guidou): Abort the request in all cases where |selection_result|
+    // has no value, as the spec mandates.
+    // Currently, some applications rely on the nonstandard behavior of asking
+    // for permission even if constraints cannot be satisfied or there are no
+    // devices. Fix once the standard behavior ceases to be disruptive.
+    // See http://crbug.com/690491.
     blink::WebString failed_constraint_name =
         blink::WebString::fromASCII(selection_result.failed_constraint_name);
-    MediaStreamRequestResult result =
-        failed_constraint_name.isEmpty()
-            ? MEDIA_DEVICE_NO_HARDWARE
-            : MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED;
-    GetUserMediaRequestFailed(user_media_request, result,
-                              failed_constraint_name);
-    return;
+    blink::WebString device_id_constraint_name = blink::WebString::fromASCII(
+        user_media_request.videoConstraints().basic().deviceId.name());
+    if (failed_constraint_name.equals(device_id_constraint_name)) {
+      GetUserMediaRequestFailed(user_media_request,
+                                MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED,
+                                failed_constraint_name);
+      return;
+    }
   }
-  controls->video.device_id = selection_result.settings.device_id();
   FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls),
                            request_settings);
 }
diff --git a/content/renderer/mojo_context_state.cc b/content/renderer/mojo_context_state.cc
index 16c802b..c3ff133 100644
--- a/content/renderer/mojo_context_state.cc
+++ b/content/renderer/mojo_context_state.cc
@@ -185,7 +185,6 @@
   module_fetchers_.push_back(fetcher);
   fetcher->Start(frame_,
                  blink::WebURLRequest::RequestContextScript,
-                 blink::WebURLRequest::FrameTypeNone,
                  base::Bind(&MojoContextState::OnFetchModuleComplete,
                             base::Unretained(this), fetcher, id));
 }
diff --git a/content/renderer/pepper/host_var_tracker_unittest.cc b/content/renderer/pepper/host_var_tracker_unittest.cc
index 72e546c..75d0f26 100644
--- a/content/renderer/pepper/host_var_tracker_unittest.cc
+++ b/content/renderer/pepper/host_var_tracker_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/mock_resource.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
@@ -80,11 +79,6 @@
   }
 
   HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); }
-
- private:
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
 };
 
 TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) {
diff --git a/content/renderer/presentation/presentation_dispatcher_unittest.cc b/content/renderer/presentation/presentation_dispatcher_unittest.cc
index ab2bf4d..5cf22a0 100644
--- a/content/renderer/presentation/presentation_dispatcher_unittest.cc
+++ b/content/renderer/presentation/presentation_dispatcher_unittest.cc
@@ -424,8 +424,8 @@
 
   base::RunLoop run_loop;
   EXPECT_CALL(connection_proxy, SendConnectionMessageInternal(_, _))
-      .WillOnce(Invoke([this, &message](ConnectionMessage* session_message,
-                                        const OnMessageCallback& callback) {
+      .WillOnce(Invoke([&message](ConnectionMessage* session_message,
+                                  const OnMessageCallback& callback) {
         EXPECT_EQ(blink::mojom::PresentationMessageType::TEXT,
                   session_message->type);
         EXPECT_EQ(message.utf8(), session_message->message.value());
diff --git a/content/renderer/resource_fetcher_browsertest.cc b/content/renderer/resource_fetcher_browsertest.cc
index e2e423cc..ebb3ad8 100644
--- a/content/renderer/resource_fetcher_browsertest.cc
+++ b/content/renderer/resource_fetcher_browsertest.cc
@@ -155,7 +155,6 @@
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
 
     delegate->WaitForResponse();
@@ -173,7 +172,6 @@
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
 
     delegate->WaitForResponse();
@@ -191,7 +189,6 @@
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
 
     delegate->WaitForResponse();
@@ -211,7 +208,6 @@
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
     fetcher->SetTimeout(base::TimeDelta());
 
@@ -232,7 +228,6 @@
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
     fetcher->SetTimeout(base::TimeDelta());
     delegate->SetFetcher(fetcher.release());
@@ -252,7 +247,6 @@
     fetcher->SetBody(kBody);
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
 
     delegate->WaitForResponse();
@@ -271,7 +265,6 @@
     fetcher->SetHeader("header", kHeader);
     fetcher->Start(frame,
                    WebURLRequest::RequestContextInternal,
-                   WebURLRequest::FrameTypeNone,
                    delegate->NewCallback());
 
     delegate->WaitForResponse();
diff --git a/content/test/blink_test_environment.cc b/content/test/blink_test_environment.cc
index 67c7a1b..51066254 100644
--- a/content/test/blink_test_environment.cc
+++ b/content/test/blink_test_environment.cc
@@ -10,7 +10,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_tokenizer.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/test/test_discardable_memory_allocator.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "build/build_config.h"
@@ -37,9 +36,17 @@
 
 class TestEnvironment {
  public:
+#if defined(OS_ANDROID)
+  // Android UI message loop goes through Java, so don't use it in tests.
+  typedef base::MessageLoop MessageLoopType;
+#else
+  typedef base::MessageLoopForUI MessageLoopType;
+#endif
+
   TestEnvironment() {
-    // TestBlinkWebUnitTestSupport must be instantiated after the main
-    // MessageLoop.
+    main_message_loop_.reset(new MessageLoopType);
+
+    // TestBlinkWebUnitTestSupport must be instantiated after MessageLoopType.
     blink_test_support_.reset(new TestBlinkWebUnitTestSupport);
     content_initializer_.reset(new content::TestContentClientInitializer());
 
@@ -55,17 +62,7 @@
   }
 
  private:
-#if defined(OS_ANDROID)
-  // Android UI message loop goes through Java, so don't use it in tests.
-  base::MessageLoop main_message_loop_;
-#else
-  base::MessageLoopForUI main_message_loop_;
-#endif
-
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
-
+  std::unique_ptr<MessageLoopType> main_message_loop_;
   std::unique_ptr<TestBlinkWebUnitTestSupport> blink_test_support_;
   std::unique_ptr<TestContentClientInitializer> content_initializer_;
   base::TestDiscardableMemoryAllocator discardable_memory_allocator_;
diff --git a/content/test/data/allowed_frames.html b/content/test/data/allowed_frames.html
new file mode 100644
index 0000000..a9ccb90
--- /dev/null
+++ b/content/test/data/allowed_frames.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>
+  <iframe name="frame0" id="child-0"></iframe>
+  <iframe name="frame1" id="child-1" allow></iframe>
+  <iframe name="frame2" id="child-2" allow="fullscreen vibrate" src="/cross-site/bar.com/title1.html"></iframe>
+  <iframe name="frame3" id="child-3" allow="fullscreen vibrate" src="title1.html"></iframe>
+</body>
+</html>
+
diff --git a/content/test/data/media/canvas_capture.html b/content/test/data/media/canvas_capture.html
index 15a904264..d93dd9c 100644
--- a/content/test/data/media/canvas_capture.html
+++ b/content/test/data/media/canvas_capture.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <head>
-<title>Media Capture from DOM Elements (video/audio) Browser Test</title>
+<title>Media Capture from Canvas ElementsBrowser Test</title>
 </head>
 <body>
-  <div> Capture and playback from video/audio elements.</div>
+  <div> Capture and playback from canvas elements.</div>
 </body>
 <script type="text/javascript" src="webrtc_test_utilities.js"></script>
 <script>
@@ -33,8 +33,17 @@
   checkForRedraw(canvas, drawCounter, drawWebGL);
 };
 
+function drawOffscreenCanvasCommit(canvas, drawCounter) {
+  var ctx = canvas.getContext('2d');
+  ctx.fillStyle = 'green';
+  ctx.fillRect(0, 0, canvas.width, canvas.height);
+  ctx.commit();
+  checkForRedraw(canvas, drawCounter, drawOffscreenCanvasCommit);
+};
+
 function testCanvasCapture(drawFunction) {
   var canvas = document.createElement('canvas');
+  canvas.width = canvas.height = 64;
   document.body.appendChild(canvas);
 
   var stream = canvas.captureStream();
@@ -54,7 +63,12 @@
   };
 
   recorder.start(0);
-  drawFunction(canvas, 0);
+  if (drawFunction.toString() == drawOffscreenCanvasCommit.toString()) {
+    var offscreen = canvas.transferControlToOffscreen();
+    drawFunction(offscreen, 0);
+  } else {
+    drawFunction(canvas, 0);
+  }
 }
 
 </script>
diff --git a/device/base/device_info_query_win.cc b/device/base/device_info_query_win.cc
index 3ff6f5ea..e53968b 100644
--- a/device/base/device_info_query_win.cc
+++ b/device/base/device_info_query_win.cc
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
 
 namespace device {
 
@@ -25,8 +26,8 @@
   }
 }
 
-bool DeviceInfoQueryWin::AddDevice(const char* device_path) {
-  return SetupDiOpenDeviceInterfaceA(device_info_list_, device_path, 0,
+bool DeviceInfoQueryWin::AddDevice(const std::string& device_path) {
+  return SetupDiOpenDeviceInterfaceA(device_info_list_, device_path.c_str(), 0,
                                      nullptr) != FALSE;
 }
 
@@ -41,26 +42,26 @@
   return true;
 }
 
-bool DeviceInfoQueryWin::GetDeviceStringProperty(DWORD property,
+bool DeviceInfoQueryWin::GetDeviceStringProperty(const DEVPROPKEY& property,
                                                  std::string* property_buffer) {
-  DWORD property_reg_data_type;
-  const size_t property_buffer_length = 512;
-  if (!SetupDiGetDeviceRegistryPropertyA(
-          device_info_list_, &device_info_data_, property,
-          &property_reg_data_type,
-          reinterpret_cast<PBYTE>(
-              base::WriteInto(property_buffer, property_buffer_length)),
-          static_cast<DWORD>(property_buffer_length), nullptr))
+  DEVPROPTYPE property_type;
+  DWORD required_size;
+  if (SetupDiGetDeviceProperty(device_info_list_, &device_info_data_, &property,
+                               &property_type, nullptr, 0, &required_size, 0) ||
+      GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
+      property_type != DEVPROP_TYPE_STRING) {
     return false;
+  }
 
-  if (property_reg_data_type != REG_SZ)
+  std::wstring wide_buffer;
+  if (!SetupDiGetDeviceProperty(
+          device_info_list_, &device_info_data_, &property, &property_type,
+          reinterpret_cast<PBYTE>(base::WriteInto(&wide_buffer, required_size)),
+          required_size, nullptr, 0)) {
     return false;
+  }
 
-  // Shrink |property_buffer| down to its correct size.
-  size_t eos = property_buffer->find('\0');
-  if (eos != std::string::npos)
-    property_buffer->resize(eos);
-
+  *property_buffer = base::SysWideToUTF8(wide_buffer);
   return true;
 }
 
diff --git a/device/base/device_info_query_win.h b/device/base/device_info_query_win.h
index 17ee13b..f9f464a 100644
--- a/device/base/device_info_query_win.h
+++ b/device/base/device_info_query_win.h
@@ -25,12 +25,13 @@
 
   // Add a device to |device_info_list_| using its |device_path| so that
   // its device info can be retrieved.
-  bool AddDevice(const char* device_path);
+  bool AddDevice(const std::string& device_path);
   // Get the device info and store it into |device_info_data_|, this function
   // should be called at most once.
   bool GetDeviceInfo();
   // Get device string property and store it into |property_buffer|.
-  bool GetDeviceStringProperty(DWORD property, std::string* property_buffer);
+  bool GetDeviceStringProperty(const DEVPROPKEY& property,
+                               std::string* property_buffer);
 
   bool device_info_list_valid() {
     return device_info_list_ != INVALID_HANDLE_VALUE;
diff --git a/device/bluetooth/README.md b/device/bluetooth/README.md
index 597de23..7ccda1f 100644
--- a/device/bluetooth/README.md
+++ b/device/bluetooth/README.md
@@ -10,15 +10,15 @@
 implementations may support only one or the other, even though several classes
 have interfaces for both, e.g. `BluetoothAdapter` & `BluetoothDevice`.
 
-|          | Classic |  Low Energy |
-|----------|:-------:|:-----------:|
-| Android  |   no    |     yes     |
-| ChromeOS |   yes   |     yes     |
-| Linux    |   yes   |     yes     |
-| Mac      |   yes   |     yes     |
-| Windows  |   some  |    nearly   |
+|           | Classic |  Low Energy |
+|-----------|:-------:|:-----------:|
+| Android   |   no    |     yes     |
+| Chrome OS |   yes   |     yes     |
+| Linux     |   yes   |     yes     |
+| Mac       |   yes   |     yes     |
+| Windows   |   some  |    nearly   |
 
-ChromeOS and Linux are supported via BlueZ, see `*_bluez` files.
+Chrome OS and Linux are supported via BlueZ, see `*_bluez` files.
 
 
 Maintainer History
@@ -26,7 +26,7 @@
 
 Initial implementation OWNERS were youngki@chromium.org, keybuk@chromium.org,
 armansito@chromium.org, and rpaquay@chromium.org. They no longer contribute to
-chromium fulltime. They were responsible for support for ChromeOS Bluetooth
+chromium fulltime. They were responsible for support for Chrome OS Bluetooth
 features and the Chrome Apps APIs:
 
 * [chrome.bluetooth](https://developer.chrome.com/apps/bluetooth)
@@ -36,7 +36,7 @@
 Active development in 2015 & 2016 is focused on enabling GATT features for:
 
 * [Web Bluetooth](https://crbug.com/419413)
-* Peripheral mode for ChromeOS.
+* Peripheral mode for Chrome OS.
 
 Known future work is tracked in the
 [Refactoring meta issue](https://crbug.com/580406).
@@ -84,10 +84,10 @@
 client code.
 
 
-### ChromeOS Blueooth Controller Tests
+### Chrome OS Blueooth Controller Tests
 
 Bluetooth controller system tests generating radio signals are run and managed
-by the ChromeOS team. See:
+by the Chrome OS team. See:
 https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/server/site_tests/
 https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/server/cros/bluetooth/
 https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/client/cros/bluetooth/
diff --git a/device/serial/serial_io_handler_win.cc b/device/serial/serial_io_handler_win.cc
index f09e4a2f..6be1127 100644
--- a/device/serial/serial_io_handler_win.cc
+++ b/device/serial/serial_io_handler_win.cc
@@ -4,8 +4,10 @@
 
 #include "device/serial/serial_io_handler_win.h"
 
-#include <windows.h>
+#define INITGUID
+#include <devpkey.h>
 #include <setupapi.h>
+#include <windows.h>
 
 #include "base/bind.h"
 #include "base/macros.h"
@@ -203,7 +205,7 @@
   }
 
   // This will add the device so we can query driver info.
-  if (!device_info_query.AddDevice(device_path.c_str())) {
+  if (!device_info_query.AddDevice(device_path)) {
     DVPLOG(1) << "Failed to get device interface data for " << device_path;
     return;
   }
@@ -214,7 +216,7 @@
   }
 
   std::string friendly_name;
-  if (!device_info_query.GetDeviceStringProperty(SPDRP_FRIENDLYNAME,
+  if (!device_info_query.GetDeviceStringProperty(DEVPKEY_Device_FriendlyName,
                                                  &friendly_name)) {
     DVPLOG(1) << "Failed to get device service property";
     return;
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index 6c1922d3..2408eb4 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -28,6 +28,8 @@
 #include "third_party/libusb/src/libusb/libusb.h"
 
 #if defined(OS_WIN)
+#define INITGUID
+#include <devpkey.h>
 #include <setupapi.h>
 #include <usbiodef.h>
 
@@ -54,7 +56,7 @@
   }
 
   // This will add the device so we can query driver info.
-  if (!device_info_query.AddDevice(device_path.c_str())) {
+  if (!device_info_query.AddDevice(device_path)) {
     USB_PLOG(ERROR) << "Failed to get device interface data for "
                     << device_path;
     return false;
@@ -66,7 +68,8 @@
   }
 
   std::string buffer;
-  if (!device_info_query.GetDeviceStringProperty(SPDRP_SERVICE, &buffer)) {
+  if (!device_info_query.GetDeviceStringProperty(DEVPKEY_Device_Service,
+                                                 &buffer)) {
     USB_PLOG(ERROR) << "Failed to get device service property";
     return false;
   }
diff --git a/docs/adding_to_third_party.md b/docs/adding_to_third_party.md
index 02bc235..745e7598 100644
--- a/docs/adding_to_third_party.md
+++ b/docs/adding_to_third_party.md
@@ -82,7 +82,7 @@
 ### Modify DEPS
 
 If the code is applicable and will be compiled on all supported Chromium
-platforms (Windows, Mac, Linux, ChromeOS, iOS, Android), check it in to
+platforms (Windows, Mac, Linux, Chrome OS, iOS, Android), check it in to
 [src/third_party](http://src.chromium.org/viewvc/chrome/trunk/src/third_party/). 
 
 If the code is only applicable to certain platforms, check it in to
diff --git a/docs/chrome_settings.md b/docs/chrome_settings.md
index 69893c5..97e0b27d 100644
--- a/docs/chrome_settings.md
+++ b/docs/chrome_settings.md
@@ -2,7 +2,7 @@
 
 Chrome (version 10 and above) uses WebUI settings by default for all platforms.
 Access it via the wrench menu ("Preferences" on Mac and Linux; "Options" on
-Windows and ChromeOS), or by typing chrome://settings into the address bar.
+Windows and Chrome OS), or by typing chrome://settings into the address bar.
 
 One advantage of chrome://settings over platform-native dialogs is that it is
 shared by all platforms; therefore, it is easier to add new options UI and to
diff --git a/docs/get_the_code.md b/docs/get_the_code.md
index 0308a2d..cc834b56 100644
--- a/docs/get_the_code.md
+++ b/docs/get_the_code.md
@@ -11,7 +11,7 @@
 
 * [Android](android_build_instructions.md)
 * [Cast](old_cast_build_instructions.md)
-* [ChromeOS](old_chromeos_build_instructions.md)
+* [Chrome OS](old_chromeos_build_instructions.md)
 * [iOS](ios_build_instructions.md)
 * [Linux](linux_build_instructions.md)
 * [Mac](mac_build_instructions.md)
diff --git a/docs/linux_minidump_to_core.md b/docs/linux_minidump_to_core.md
index 930d9057..7f25c88 100644
--- a/docs/linux_minidump_to_core.md
+++ b/docs/linux_minidump_to_core.md
@@ -104,5 +104,5 @@
 
 For more discussion on this process see
 [Debugging a Minidump](https://www.chromium.org/chromium-os/how-tos-and-troubleshooting/crash-reporting/debugging-a-minidump).
-This page discusses the same process in the context of ChromeOS and many of the
+This page discusses the same process in the context of Chrome OS and many of the
 concepts and techniques overlap.
diff --git a/docs/linux_sublime_dev.md b/docs/linux_sublime_dev.md
index e80aa25..1bbe4ffb 100644
--- a/docs/linux_sublime_dev.md
+++ b/docs/linux_sublime_dev.md
@@ -249,6 +249,19 @@
 2. Select some text and press `Ctrl + Shift + C` to format, or select no text to
    format the entire file
 
+## CodeSearch Integration with Chromium X-Refs
+
+With [Chromium X-Refs](https://github.com/karlinjf/ChromiumXRefs/) you can
+perform [https://cs.chromium.org](https://cs.chromium.org) cross-reference
+searches in your editor. This gives you the call graph, overrides, references,
+declaration, and definition of most of the code. The results are as fresh as
+the search engine's index so uncomitted changes won't be reflected.
+
+More information on Chromium X-Ref's functionality (including keyboard and
+mouse shortcuts) can be found on the [Chromium X-Refs
+page](https://github.com/karlinjf/ChromiumXRefs/).
+
+
 ## Code Completion with SublimeClang (Linux Only)
 
 SublimeClang is a powerful autocompletion plugin for Sublime that uses the Clang
diff --git a/docs/old_chromeos_build_instructions.md b/docs/old_chromeos_build_instructions.md
index 45f936c4..5baa515 100644
--- a/docs/old_chromeos_build_instructions.md
+++ b/docs/old_chromeos_build_instructions.md
@@ -1,4 +1,4 @@
-# ChromeOS Build Instructions (Chromium OS on Linux)
+# Chrome OS Build Instructions (Chromium OS on Linux)
 
 Chromium on Chromium OS is built from a mix of code sourced from Chromium
 on Linux and Chromium on Windows. Much of the user interface code is
diff --git a/docs/ozone_overview.md b/docs/ozone_overview.md
index 3d070392..2ba7f29 100644
--- a/docs/ozone_overview.md
+++ b/docs/ozone_overview.md
@@ -118,7 +118,7 @@
 
 ## Building with Ozone
 
-### ChromeOS - ([waterfall](https://build.chromium.org/p/chromium.chromiumos/waterfall?builder=Linux+ChromiumOS+Ozone+Builder&builder=Linux+ChromiumOS+Ozone+Tests+%281%29&builder=Linux+ChromiumOS+Ozone+Tests+%282%29&reload=none))
+### Chrome OS - ([waterfall](https://build.chromium.org/p/chromium.chromiumos/waterfall?builder=Linux+ChromiumOS+Ozone+Builder&builder=Linux+ChromiumOS+Ozone+Tests+%281%29&builder=Linux+ChromiumOS+Ozone+Tests+%282%29&reload=none))
 
 To build `chrome`, do this from the `src` directory:
 
@@ -224,9 +224,9 @@
 
 This is Linux direct rending with acceleration via mesa GBM & linux DRM/KMS
 (EGL/GLES2 accelerated rendering & modesetting in GPU process) and is in
-production use on [ChromeOS](https://www.chromium.org/chromium-os).
+production use on [Chrome OS](https://www.chromium.org/chromium-os).
 
-Note that all ChromeOS builds of Chrome will compile and attempt to use this.
+Note that all Chrome OS builds of Chrome will compile and attempt to use this.
 See [Building Chromium for Chromium OS](https://www.chromium.org/chromium-os/how-tos-and-troubleshooting/building-chromium-browser) for build instructions.
 
 ### Cast
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index a3ade02..77124a8 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -10,8 +10,6 @@
 #include <iterator>
 #include <utility>
 
-#include "base/debug/crash_logging.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -317,10 +315,6 @@
     // might be useful. Remove the dumps after we analyze them.
     if (key_value->GetType() != type_enum_value) {
       NOTREACHED();
-      base::debug::SetCrashKeyValue(
-          "existing_extension_pref_value_type",
-          base::IntToString(static_cast<int>(key_value->GetType())));
-      base::debug::DumpWithoutCrashing();
       value_as_t = new T();
       extension->SetWithoutPathExpansion(key_, base::WrapUnique(value_as_t));
     } else {
diff --git a/extensions/renderer/api_binding_test.h b/extensions/renderer/api_binding_test.h
index 4a67989..d72de47 100644
--- a/extensions/renderer/api_binding_test.h
+++ b/extensions/renderer/api_binding_test.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "v8/include/v8.h"
 
@@ -44,11 +43,6 @@
 
  private:
   base::MessageLoop message_loop_;
-
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
-
   std::unique_ptr<gin::IsolateHolder> isolate_holder_;
   std::unique_ptr<gin::ContextHolder> context_holder_;
 
diff --git a/extensions/renderer/gc_callback_unittest.cc b/extensions/renderer/gc_callback_unittest.cc
index e79a9274..e6dfab6 100644
--- a/extensions/renderer/gc_callback_unittest.cc
+++ b/extensions/renderer/gc_callback_unittest.cc
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/gc_callback.h"
 #include "base/bind.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/test/scoped_async_task_scheduler.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/features/feature.h"
+#include "extensions/renderer/gc_callback.h"
 #include "extensions/renderer/scoped_web_frame.h"
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/script_context_set.h"
@@ -35,6 +34,8 @@
   GCCallbackTest() : script_context_set_(&active_extensions_) {}
 
  protected:
+  base::MessageLoop& message_loop() { return message_loop_; }
+
   ScriptContextSet& script_context_set() { return script_context_set_; }
 
   v8::Local<v8::Context> v8_context() {
@@ -71,11 +72,6 @@
   }
 
   base::MessageLoop message_loop_;
-
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
-
   ScopedWebFrame web_frame_;  // (this will construct the v8::Isolate)
   // ExtensionsRendererClient is a dependency of ScriptContextSet.
   TestExtensionsRendererClient extensions_renderer_client_;
diff --git a/extensions/renderer/module_system_test.h b/extensions/renderer/module_system_test.h
index 3508574..1cfbb7c4 100644
--- a/extensions/renderer/module_system_test.h
+++ b/extensions/renderer/module_system_test.h
@@ -6,7 +6,6 @@
 #define EXTENSIONS_RENDERER_MODULE_SYSTEM_TEST_H_
 
 #include "base/macros.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/script_context.h"
 #include "gin/public/context_holder.h"
@@ -99,10 +98,6 @@
   void RunResolvedPromises();
 
  private:
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
-
   v8::Isolate* isolate_;
   std::unique_ptr<ModuleSystemTestEnvironment> env_;
   bool should_assertions_be_made_;
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index b8b1a5d..6ad0eac4 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -151,7 +151,6 @@
     "//testing/gtest",
   ]
   deps = [
-    "//base/test:test_support",
     "//v8",
   ]
 
diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc
index 08703a4..c7cf5987 100644
--- a/gin/shell/gin_main.cc
+++ b/gin/shell/gin_main.cc
@@ -14,8 +14,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/sys_info.h"
-#include "base/task_scheduler/task_scheduler.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "gin/array_buffer.h"
 #include "gin/modules/console.h"
@@ -75,44 +73,34 @@
 #endif
 
   base::MessageLoop message_loop;
-  base::TaskScheduler::CreateAndSetSimpleTaskScheduler(
-      base::SysInfo::NumberOfProcessors());
 
   // Initialize the base::FeatureList since IsolateHolder can depend on it.
   base::FeatureList::SetInstance(base::WrapUnique(new base::FeatureList));
 
+  gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
+                                 gin::IsolateHolder::kStableV8Extras,
+                                 gin::ArrayBufferAllocator::SharedInstance());
+  gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
+
+  gin::GinShellRunnerDelegate delegate;
+  gin::ShellRunner runner(&delegate, instance.isolate());
+
   {
-    gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
-                                   gin::IsolateHolder::kStableV8Extras,
-                                   gin::ArrayBufferAllocator::SharedInstance());
-    gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
-
-    gin::GinShellRunnerDelegate delegate;
-    gin::ShellRunner runner(&delegate, instance.isolate());
-
-    {
-      gin::Runner::Scope scope(&runner);
-      runner.GetContextHolder()
-          ->isolate()
-          ->SetCaptureStackTraceForUncaughtExceptions(true);
-    }
-
-    base::CommandLine::StringVector args =
-        base::CommandLine::ForCurrentProcess()->GetArgs();
-    for (base::CommandLine::StringVector::const_iterator it = args.begin();
-         it != args.end(); ++it) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::Bind(gin::Run, runner.GetWeakPtr(), base::FilePath(*it)));
-    }
-
-    base::RunLoop().RunUntilIdle();
+    gin::Runner::Scope scope(&runner);
+    runner.GetContextHolder()
+        ->isolate()
+        ->SetCaptureStackTraceForUncaughtExceptions(true);
   }
 
-  // gin::IsolateHolder waits for tasks running in TaskScheduler in its
-  // destructor and thus must be destroyed before TaskScheduler starts skipping
-  // CONTINUE_ON_SHUTDOWN tasks.
-  base::TaskScheduler::GetInstance()->Shutdown();
+  base::CommandLine::StringVector args =
+      base::CommandLine::ForCurrentProcess()->GetArgs();
+  for (base::CommandLine::StringVector::const_iterator it = args.begin();
+       it != args.end(); ++it) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(gin::Run, runner.GetWeakPtr(), base::FilePath(*it)));
+  }
 
+  base::RunLoop().RunUntilIdle();
   return 0;
 }
diff --git a/gin/shell_runner_unittest.cc b/gin/shell_runner_unittest.cc
index 0053ad1..0743ede 100644
--- a/gin/shell_runner_unittest.cc
+++ b/gin/shell_runner_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/message_loop/message_loop.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "gin/array_buffer.h"
 #include "gin/converter.h"
@@ -27,7 +26,6 @@
 
 TEST(RunnerTest, Run) {
   base::MessageLoop message_loop;
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
   std::string source = "this.result = 'PASS';\n";
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
diff --git a/gin/test/file_runner.cc b/gin/test/file_runner.cc
index 600696e..c8e9f53 100644
--- a/gin/test/file_runner.cc
+++ b/gin/test/file_runner.cc
@@ -8,7 +8,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "gin/array_buffer.h"
 #include "gin/converter.h"
@@ -61,7 +60,6 @@
   ASSERT_TRUE(ReadFileToString(path, &source));
 
   base::MessageLoop message_loop;
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
diff --git a/gin/test/v8_test.h b/gin/test/v8_test.h
index da5fb6a..635281b1 100644
--- a/gin/test/v8_test.h
+++ b/gin/test/v8_test.h
@@ -10,7 +10,6 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "v8/include/v8.h"
 
@@ -30,11 +29,6 @@
 
  protected:
   base::MessageLoop message_loop_;
-
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler_;
-
   std::unique_ptr<IsolateHolder> instance_;
   v8::Persistent<v8::Context> context_;
 
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index 9c69aa97..4fe7c7c 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -7,8 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/sys_info.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_scheduler.h"
+#include "base/threading/worker_pool.h"
 #include "base/trace_event/trace_event.h"
 #include "gin/per_isolate_data.h"
 
@@ -43,11 +42,6 @@
   DISALLOW_COPY_AND_ASSIGN(IdleTaskWithLocker);
 };
 
-base::TaskTraits GetBackgroundThreadTaskTraits() {
-  return base::TaskTraits().WithShutdownBehavior(
-      base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN);
-}
-
 }  // namespace
 
 // static
@@ -58,16 +52,25 @@
 V8Platform::~V8Platform() {}
 
 size_t V8Platform::NumberOfAvailableBackgroundThreads() {
-  return base::TaskScheduler::GetInstance()
-      ->GetMaxConcurrentTasksWithTraitsDeprecated(
-          GetBackgroundThreadTaskTraits());
+  // WorkerPool will currently always create additional threads for posted
+  // background tasks, unless there are threads sitting idle (on posix).
+  // Indicate that V8 should create no more than the number of cores available,
+  // reserving one core for the main thread.
+  const size_t available_cores =
+    static_cast<size_t>(base::SysInfo::NumberOfProcessors());
+  if (available_cores > 1) {
+    return available_cores - 1;
+  }
+  return 1;
 }
 
 void V8Platform::CallOnBackgroundThread(
     v8::Task* task,
     v8::Platform::ExpectedRuntime expected_runtime) {
-  base::PostTaskWithTraits(FROM_HERE, GetBackgroundThreadTaskTraits(),
-                           base::Bind(&v8::Task::Run, base::Owned(task)));
+  base::WorkerPool::PostTask(
+      FROM_HERE,
+      base::Bind(&v8::Task::Run, base::Owned(task)),
+      expected_runtime == v8::Platform::kLongRunningTask);
 }
 
 void V8Platform::CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) {
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn
index c3ad17d1..f92cbac 100644
--- a/google_apis/BUILD.gn
+++ b/google_apis/BUILD.gn
@@ -162,6 +162,8 @@
         "drive/drive_api_url_generator.cc",
         "drive/drive_api_url_generator.h",
         "drive/drive_common_callbacks.h",
+        "drive/drive_switches.cc",
+        "drive/drive_switches.h",
         "drive/files_list_request_runner.cc",
         "drive/files_list_request_runner.h",
         "drive/request_sender.cc",
diff --git a/google_apis/drive/drive_api_requests_unittest.cc b/google_apis/drive/drive_api_requests_unittest.cc
index c4263d9..27cd0eb 100644
--- a/google_apis/drive/drive_api_requests_unittest.cc
+++ b/google_apis/drive/drive_api_requests_unittest.cc
@@ -170,7 +170,8 @@
 
     GURL test_base_url = test_util::GetBaseUrlForTesting(test_server_.port());
     url_generator_.reset(
-        new DriveApiUrlGenerator(test_base_url, test_base_url));
+        new DriveApiUrlGenerator(test_base_url, test_base_url,
+                                 TEAM_DRIVES_INTEGRATION_DISABLED));
 
     // Reset the server's expected behavior just in case.
     ResetExpectedResponse();
diff --git a/google_apis/drive/drive_api_url_generator.cc b/google_apis/drive/drive_api_url_generator.cc
index a2113d41..fc52097 100644
--- a/google_apis/drive/drive_api_url_generator.cc
+++ b/google_apis/drive/drive_api_url_generator.cc
@@ -4,9 +4,11 @@
 
 #include "google_apis/drive/drive_api_url_generator.h"
 
+#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "google_apis/drive/drive_switches.h"
 #include "google_apis/google_api_keys.h"
 #include "net/base/escape.h"
 #include "net/base/url_util.h"
@@ -16,11 +18,16 @@
 namespace {
 
 // Hard coded URLs for communication with a google drive server.
+// TODO(yamaguchi): Make a utility function to compose some of these URLs by a
+// version and a resource name.
 const char kDriveV2AboutUrl[] = "drive/v2/about";
 const char kDriveV2AppsUrl[] = "drive/v2/apps";
 const char kDriveV2ChangelistUrl[] = "drive/v2/changes";
+const char kDriveV2BetaChangelistUrl[] = "drive/v2beta/changes";
 const char kDriveV2FilesUrl[] = "drive/v2/files";
+const char kDriveV2BetaFilesUrl[] = "drive/v2beta/files";
 const char kDriveV2FileUrlPrefix[] = "drive/v2/files/";
+const char kDriveV2BetaFileUrlPrefix[] = "drive/v2beta/files/";
 const char kDriveV2ChildrenUrlFormat[] = "drive/v2/files/%s/children";
 const char kDriveV2ChildrenUrlForRemovalFormat[] =
     "drive/v2/files/%s/children/%s";
@@ -35,6 +42,9 @@
 const char kDriveV2ThumbnailUrlFormat[] = "d/%s=w%d-h%d";
 const char kDriveV2ThumbnailUrlWithCropFormat[] = "d/%s=w%d-h%d-c";
 
+const char kIncludeTeamDriveItems[] = "includeTeamDriveItems";
+const char kSupportsTeamDrives[] = "supportsTeamDrives";
+
 // apps.delete and file.authorize API is exposed through a special endpoint
 // v2internal that is accessible only by the official API key for Chrome.
 const char kDriveV2InternalAppsUrl[] = "drive/v2internal/apps";
@@ -53,13 +63,19 @@
 
 }  // namespace
 
-DriveApiUrlGenerator::DriveApiUrlGenerator(const GURL& base_url,
-                                           const GURL& base_thumbnail_url)
+DriveApiUrlGenerator::DriveApiUrlGenerator(
+    const GURL& base_url, const GURL& base_thumbnail_url,
+    TeamDrivesIntegrationStatus team_drives_integration)
     : base_url_(base_url),
-      base_thumbnail_url_(base_thumbnail_url) {
+      base_thumbnail_url_(base_thumbnail_url),
+      enable_team_drives_(
+          team_drives_integration == TEAM_DRIVES_INTEGRATION_ENABLED) {
   // Do nothing.
 }
 
+DriveApiUrlGenerator::DriveApiUrlGenerator(const DriveApiUrlGenerator& src) =
+    default;
+
 DriveApiUrlGenerator::~DriveApiUrlGenerator() {
   // Do nothing.
 }
@@ -87,9 +103,19 @@
 GURL DriveApiUrlGenerator::GetFilesGetUrl(const std::string& file_id,
                                           bool use_internal_endpoint,
                                           const GURL& embed_origin) const {
-  GURL url = base_url_.Resolve(use_internal_endpoint ?
-      kDriveV2InternalFileUrlPrefix + net::EscapePath(file_id) :
-      kDriveV2FileUrlPrefix + net::EscapePath(file_id));
+  const char* url_prefix = nullptr;
+  if (use_internal_endpoint)
+    url_prefix = kDriveV2InternalFileUrlPrefix;
+  else if (enable_team_drives_)
+    url_prefix = kDriveV2BetaFileUrlPrefix;
+  else
+    url_prefix = kDriveV2FileUrlPrefix;
+
+  GURL url = base_url_.Resolve(url_prefix + net::EscapePath(file_id));
+
+  if (enable_team_drives_)
+    url = net::AppendOrReplaceQueryParameter(url, kSupportsTeamDrives, "true");
+
   if (!embed_origin.is_empty()) {
     // Construct a valid serialized embed origin from an url, according to
     // WD-html5-20110525. Such string has to be built manually, since
@@ -155,8 +181,15 @@
 GURL DriveApiUrlGenerator::GetFilesListUrl(int max_results,
                                            const std::string& page_token,
                                            const std::string& q) const {
-  GURL url = base_url_.Resolve(kDriveV2FilesUrl);
-
+  GURL url;
+  if (enable_team_drives_) {
+    url = base_url_.Resolve(kDriveV2BetaFilesUrl);
+    url = net::AppendOrReplaceQueryParameter(url, kSupportsTeamDrives, "true");
+    url = net::AppendOrReplaceQueryParameter(url, kIncludeTeamDriveItems,
+                                             "true");
+  } else {
+    url = base_url_.Resolve(kDriveV2FilesUrl);
+  }
   // maxResults is 100 by default.
   if (max_results != 100) {
     url = net::AppendOrReplaceQueryParameter(
@@ -188,8 +221,15 @@
                                              int64_t start_change_id) const {
   DCHECK_GE(start_change_id, 0);
 
-  GURL url = base_url_.Resolve(kDriveV2ChangelistUrl);
-
+  GURL url;
+  if (enable_team_drives_) {
+    url = base_url_.Resolve(kDriveV2BetaChangelistUrl);
+    url = net::AppendOrReplaceQueryParameter(url, kSupportsTeamDrives, "true");
+    url = net::AppendOrReplaceQueryParameter(url, kIncludeTeamDriveItems,
+                                             "true");
+  } else {
+    url = base_url_.Resolve(kDriveV2ChangelistUrl);
+  }
   // includeDeleted is "true" by default.
   if (!include_deleted)
     url = net::AppendOrReplaceQueryParameter(url, "includeDeleted", "false");
diff --git a/google_apis/drive/drive_api_url_generator.h b/google_apis/drive/drive_api_url_generator.h
index af07333..dd050fe 100644
--- a/google_apis/drive/drive_api_url_generator.h
+++ b/google_apis/drive/drive_api_url_generator.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "google_apis/drive/drive_switches.h"
 #include "url/gurl.h"
 
 namespace google_apis {
@@ -21,7 +22,9 @@
   // |base_url| is the path to the target drive api server.
   // Note that this is an injecting point for a testing server.
   DriveApiUrlGenerator(const GURL& base_url,
-                       const GURL& base_thumbnail_url);
+                       const GURL& base_thumbnail_url,
+                       TeamDrivesIntegrationStatus team_drives_integration);
+  DriveApiUrlGenerator(const DriveApiUrlGenerator& src);
   ~DriveApiUrlGenerator();
 
   // The base URL for communicating with the production drive api server.
@@ -126,6 +129,7 @@
   const GURL base_url_;
   const GURL base_download_url_;
   const GURL base_thumbnail_url_;
+  const bool enable_team_drives_;
 
   // This class is copyable hence no DISALLOW_COPY_AND_ASSIGN here.
 };
diff --git a/google_apis/drive/drive_api_url_generator_unittest.cc b/google_apis/drive/drive_api_url_generator_unittest.cc
index 29d85f1..e20ba209 100644
--- a/google_apis/drive/drive_api_url_generator_unittest.cc
+++ b/google_apis/drive/drive_api_url_generator_unittest.cc
@@ -25,10 +25,15 @@
  public:
   DriveApiUrlGeneratorTest()
       : url_generator_(GURL(kBaseUrlForTesting),
-                       GURL(kBaseThumbnailUrlForTesting)) {}
+                       GURL(kBaseThumbnailUrlForTesting),
+                       TEAM_DRIVES_INTEGRATION_DISABLED),
+        team_drives_url_generator_(GURL(kBaseUrlForTesting),
+                                   GURL(kBaseThumbnailUrlForTesting),
+                                   TEAM_DRIVES_INTEGRATION_ENABLED) {}
 
  protected:
   DriveApiUrlGenerator url_generator_;
+  DriveApiUrlGenerator team_drives_url_generator_;
 };
 
 // Make sure the hard-coded urls are returned.
@@ -59,6 +64,10 @@
   EXPECT_EQ(
       "https://www.example.com/drive/v2/files/file%3Afile_id",
       url_generator_.GetFilesGetUrl("file:file_id", false, GURL()).spec());
+  EXPECT_EQ("https://www.example.com/drive/v2beta/files/0Bz0bd074"
+                "?supportsTeamDrives=true",
+            team_drives_url_generator_.GetFilesGetUrl(
+                "0Bz0bd074", false, GURL()).spec());
 
   // If |use_internal_endpoint| is true, the generated url should point to the
   // v2internal.
@@ -156,25 +165,38 @@
   };
   const TestPattern kTestPatterns[] = {
     { 100, "", "", "" },
-    { 150, "", "", "?maxResults=150" },
-    { 10, "", "", "?maxResults=10" },
-    { 100, "token", "", "?pageToken=token" },
-    { 150, "token", "", "?maxResults=150&pageToken=token" },
-    { 10, "token", "", "?maxResults=10&pageToken=token" },
-    { 100, "", "query", "?q=query" },
-    { 150, "", "query", "?maxResults=150&q=query" },
-    { 10, "", "query", "?maxResults=10&q=query" },
-    { 100, "token", "query", "?pageToken=token&q=query" },
-    { 150, "token", "query", "?maxResults=150&pageToken=token&q=query" },
-    { 10, "token", "query", "?maxResults=10&pageToken=token&q=query" },
+    { 150, "", "", "maxResults=150" },
+    { 10, "", "", "maxResults=10" },
+    { 100, "token", "", "pageToken=token" },
+    { 150, "token", "", "maxResults=150&pageToken=token" },
+    { 10, "token", "", "maxResults=10&pageToken=token" },
+    { 100, "", "query", "q=query" },
+    { 150, "", "query", "maxResults=150&q=query" },
+    { 10, "", "query", "maxResults=10&q=query" },
+    { 100, "token", "query", "pageToken=token&q=query" },
+    { 150, "token", "query", "maxResults=150&pageToken=token&q=query" },
+    { 10, "token", "query", "maxResults=10&pageToken=token&q=query" },
   };
+  const std::string kV2FilesUrlPrefix =
+      "https://www.example.com/drive/v2/files";
+  const std::string kV2BetaFilesUrlPrefix =
+      "https://www.example.com/drive/v2beta/files?"
+      "supportsTeamDrives=true&includeTeamDriveItems=true";
 
   for (size_t i = 0; i < arraysize(kTestPatterns); ++i) {
-    EXPECT_EQ("https://www.example.com/drive/v2/files" +
+    EXPECT_EQ(kV2FilesUrlPrefix +
+                  (kTestPatterns[i].expected_query.empty() ? "" : "?") +
                   kTestPatterns[i].expected_query,
               url_generator_.GetFilesListUrl(kTestPatterns[i].max_results,
                                              kTestPatterns[i].page_token,
                                              kTestPatterns[i].q).spec());
+    EXPECT_EQ(kV2BetaFilesUrlPrefix +
+                  (kTestPatterns[i].expected_query.empty() ? "" : "&") +
+                  kTestPatterns[i].expected_query,
+              team_drives_url_generator_.GetFilesListUrl(
+                  kTestPatterns[i].max_results,
+                  kTestPatterns[i].page_token,
+                  kTestPatterns[i].q).spec());
   }
 }
 
@@ -208,53 +230,68 @@
   };
   const TestPattern kTestPatterns[] = {
     { true, 100, "", 0, "" },
-    { false, 100, "", 0, "?includeDeleted=false" },
-    { true, 150, "", 0, "?maxResults=150" },
-    { false, 150, "", 0, "?includeDeleted=false&maxResults=150" },
-    { true, 10, "", 0, "?maxResults=10" },
-    { false, 10, "", 0, "?includeDeleted=false&maxResults=10" },
+    { false, 100, "", 0, "includeDeleted=false" },
+    { true, 150, "", 0, "maxResults=150" },
+    { false, 150, "", 0, "includeDeleted=false&maxResults=150" },
+    { true, 10, "", 0, "maxResults=10" },
+    { false, 10, "", 0, "includeDeleted=false&maxResults=10" },
 
-    { true, 100, "token", 0, "?pageToken=token" },
-    { false, 100, "token", 0, "?includeDeleted=false&pageToken=token" },
-    { true, 150, "token", 0, "?maxResults=150&pageToken=token" },
+    { true, 100, "token", 0, "pageToken=token" },
+    { false, 100, "token", 0, "includeDeleted=false&pageToken=token" },
+    { true, 150, "token", 0, "maxResults=150&pageToken=token" },
     { false, 150, "token", 0,
-      "?includeDeleted=false&maxResults=150&pageToken=token" },
-    { true, 10, "token", 0, "?maxResults=10&pageToken=token" },
+      "includeDeleted=false&maxResults=150&pageToken=token" },
+    { true, 10, "token", 0, "maxResults=10&pageToken=token" },
     { false, 10, "token", 0,
-      "?includeDeleted=false&maxResults=10&pageToken=token" },
+      "includeDeleted=false&maxResults=10&pageToken=token" },
 
-    { true, 100, "", 12345, "?startChangeId=12345" },
-    { false, 100, "", 12345, "?includeDeleted=false&startChangeId=12345" },
-    { true, 150, "", 12345, "?maxResults=150&startChangeId=12345" },
+    { true, 100, "", 12345, "startChangeId=12345" },
+    { false, 100, "", 12345, "includeDeleted=false&startChangeId=12345" },
+    { true, 150, "", 12345, "maxResults=150&startChangeId=12345" },
     { false, 150, "", 12345,
-      "?includeDeleted=false&maxResults=150&startChangeId=12345" },
-    { true, 10, "", 12345, "?maxResults=10&startChangeId=12345" },
+      "includeDeleted=false&maxResults=150&startChangeId=12345" },
+    { true, 10, "", 12345, "maxResults=10&startChangeId=12345" },
     { false, 10, "", 12345,
-      "?includeDeleted=false&maxResults=10&startChangeId=12345" },
+      "includeDeleted=false&maxResults=10&startChangeId=12345" },
 
-    { true, 100, "token", 12345, "?pageToken=token&startChangeId=12345" },
+    { true, 100, "token", 12345, "pageToken=token&startChangeId=12345" },
     { false, 100, "token", 12345,
-      "?includeDeleted=false&pageToken=token&startChangeId=12345" },
+      "includeDeleted=false&pageToken=token&startChangeId=12345" },
     { true, 150, "token", 12345,
-      "?maxResults=150&pageToken=token&startChangeId=12345" },
+      "maxResults=150&pageToken=token&startChangeId=12345" },
     { false, 150, "token", 12345,
-      "?includeDeleted=false&maxResults=150&pageToken=token"
+      "includeDeleted=false&maxResults=150&pageToken=token"
       "&startChangeId=12345" },
     { true, 10, "token", 12345,
-      "?maxResults=10&pageToken=token&startChangeId=12345" },
+      "maxResults=10&pageToken=token&startChangeId=12345" },
     { false, 10, "token", 12345,
-      "?includeDeleted=false&maxResults=10&pageToken=token"
+      "includeDeleted=false&maxResults=10&pageToken=token"
       "&startChangeId=12345" },
   };
 
+  const std::string kV2ChangesUrlPrefix =
+      "https://www.example.com/drive/v2/changes";
+  const std::string kV2BetaChangesUrlPrefix =
+      "https://www.example.com/drive/v2beta/changes?"
+      "supportsTeamDrives=true&includeTeamDriveItems=true";
   for (size_t i = 0; i < arraysize(kTestPatterns); ++i) {
-    EXPECT_EQ("https://www.example.com/drive/v2/changes" +
+    EXPECT_EQ(kV2ChangesUrlPrefix +
+                  (kTestPatterns[i].expected_query.empty() ? "" : "?") +
                   kTestPatterns[i].expected_query,
               url_generator_.GetChangesListUrl(kTestPatterns[i].include_deleted,
                                                kTestPatterns[i].max_results,
                                                kTestPatterns[i].page_token,
                                                kTestPatterns[i].start_change_id)
                   .spec());
+    EXPECT_EQ(kV2BetaChangesUrlPrefix +
+                  (kTestPatterns[i].expected_query.empty() ? "" : "&") +
+                  kTestPatterns[i].expected_query,
+              team_drives_url_generator_.GetChangesListUrl(
+                  kTestPatterns[i].include_deleted,
+                  kTestPatterns[i].max_results,
+                  kTestPatterns[i].page_token,
+                  kTestPatterns[i].start_change_id)
+                  .spec());
   }
 }
 
diff --git a/google_apis/drive/drive_switches.cc b/google_apis/drive/drive_switches.cc
new file mode 100644
index 0000000..581e0680
--- /dev/null
+++ b/google_apis/drive/drive_switches.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "google_apis/drive/drive_switches.h"
+
+namespace google_apis {
+namespace {
+// Enables or disables Team Drives integration.
+constexpr char kEnableTeamDrives[] = "team-drives";
+
+}
+
+TeamDrivesIntegrationStatus GetTeamDrivesIntegrationSwitch() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(kEnableTeamDrives) ?
+      TEAM_DRIVES_INTEGRATION_ENABLED : TEAM_DRIVES_INTEGRATION_DISABLED;
+}
+
+}  // namespace google_apis
diff --git a/google_apis/drive/drive_switches.h b/google_apis/drive/drive_switches.h
new file mode 100644
index 0000000..1c7460f
--- /dev/null
+++ b/google_apis/drive/drive_switches.h
@@ -0,0 +1,20 @@
+// 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 GOOGLE_APIS_DRIVE_DRIVE_SWITHES_H_
+#define GOOGLE_APIS_DRIVE_DRIVE_SWITHES_H_
+
+namespace google_apis {
+
+enum TeamDrivesIntegrationStatus {
+  TEAM_DRIVES_INTEGRATION_DISABLED,
+  TEAM_DRIVES_INTEGRATION_ENABLED
+};
+
+// Whether Team Drives integration is enabled or not.
+TeamDrivesIntegrationStatus GetTeamDrivesIntegrationSwitch();
+
+}  // namespace switches
+
+#endif  // GOOGLE_APIS_DRIVE_DRIVE_SWITHES_H_
diff --git a/google_apis/drive/files_list_request_runner_unittest.cc b/google_apis/drive/files_list_request_runner_unittest.cc
index ea8408785..a6719f45 100644
--- a/google_apis/drive/files_list_request_runner_unittest.cc
+++ b/google_apis/drive/files_list_request_runner_unittest.cc
@@ -80,7 +80,8 @@
     runner_.reset(new FilesListRequestRunner(
         request_sender_.get(),
         google_apis::DriveApiUrlGenerator(test_server_.base_url(),
-                                          test_server_.GetURL("/thumbnail/"))));
+                                          test_server_.GetURL("/thumbnail/"),
+                                          TEAM_DRIVES_INTEGRATION_DISABLED)));
   }
 
   void TearDown() override {
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 6eb9b8e..129934b 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -1878,6 +1878,36 @@
   return false;
 }
 
+bool IsWebGL1OrES2ContextType(ContextType context_type) {
+  // Switch statement to cause a compile-time error if we miss a case.
+  switch (context_type) {
+    case CONTEXT_TYPE_WEBGL1:
+    case CONTEXT_TYPE_OPENGLES2:
+      return true;
+    case CONTEXT_TYPE_WEBGL2:
+    case CONTEXT_TYPE_OPENGLES3:
+      return false;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+bool IsWebGL2OrES3ContextType(ContextType context_type) {
+  // Switch statement to cause a compile-time error if we miss a case.
+  switch (context_type) {
+    case CONTEXT_TYPE_OPENGLES3:
+    case CONTEXT_TYPE_WEBGL2:
+      return true;
+    case CONTEXT_TYPE_WEBGL1:
+    case CONTEXT_TYPE_OPENGLES2:
+      return false;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
 ContextCreationAttribHelper::ContextCreationAttribHelper()
     : gpu_preference(gl::PreferIntegratedGpu),
       alpha_size(-1),
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 969a724..2d378a9 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -308,6 +308,8 @@
   CONTEXT_TYPE_LAST = CONTEXT_TYPE_OPENGLES3
 };
 GLES2_UTILS_EXPORT bool IsWebGLContextType(ContextType context_type);
+GLES2_UTILS_EXPORT bool IsWebGL1OrES2ContextType(ContextType context_type);
+GLES2_UTILS_EXPORT bool IsWebGL2OrES3ContextType(ContextType context_type);
 
 struct GLES2_UTILS_EXPORT ContextCreationAttribHelper {
   ContextCreationAttribHelper();
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index a8b497fd..1ca1169 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -1509,33 +1509,11 @@
 }
 
 bool FeatureInfo::IsWebGL1OrES2Context() const {
-  // Switch statement to cause a compile-time error if we miss a case.
-  switch (context_type_) {
-    case CONTEXT_TYPE_WEBGL1:
-    case CONTEXT_TYPE_OPENGLES2:
-      return true;
-    case CONTEXT_TYPE_WEBGL2:
-    case CONTEXT_TYPE_OPENGLES3:
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
+  return IsWebGL1OrES2ContextType(context_type_);
 }
 
 bool FeatureInfo::IsWebGL2OrES3Context() const {
-  // Switch statement to cause a compile-time error if we miss a case.
-  switch (context_type_) {
-    case CONTEXT_TYPE_WEBGL2:
-    case CONTEXT_TYPE_OPENGLES3:
-      return true;
-    case CONTEXT_TYPE_WEBGL1:
-    case CONTEXT_TYPE_OPENGLES2:
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
+  return IsWebGL2OrES3ContextType(context_type_);
 }
 
 void FeatureInfo::AddExtensionString(const char* s) {
diff --git a/gpu/command_buffer/service/service_utils.cc b/gpu/command_buffer/service/service_utils.cc
index e8642d76..a3b53116 100644
--- a/gpu/command_buffer/service/service_utils.cc
+++ b/gpu/command_buffer/service/service_utils.cc
@@ -4,8 +4,10 @@
 
 #include "gpu/command_buffer/service/service_utils.h"
 
+#include "base/command_line.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
+#include "ui/gl/gl_switches.h"
 
 namespace gpu {
 namespace gles2 {
@@ -19,7 +21,32 @@
     attribs.bind_generates_resource = attribs_helper.bind_generates_resource;
     attribs.webgl_compatibility_context =
         IsWebGLContextType(attribs_helper.context_type);
+
+    // Always use the global texture share group for the passthrough command
+    // decoder
+    attribs.global_texture_share_group = true;
+
+    // Request a specific context version instead of always 3.0
+    if (IsWebGL2OrES3ContextType(attribs_helper.context_type)) {
+      attribs.client_major_es_version = 3;
+      attribs.client_minor_es_version = 0;
+    } else {
+      DCHECK(IsWebGL1OrES2ContextType(attribs_helper.context_type));
+      attribs.client_major_es_version = 2;
+      attribs.client_minor_es_version = 0;
+    }
+  } else {
+    attribs.client_major_es_version = 3;
+    attribs.client_minor_es_version = 0;
   }
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableES3GLContext)) {
+    // Forcefully disable ES3 contexts
+    attribs.client_major_es_version = 2;
+    attribs.client_minor_es_version = 0;
+  }
+
   return attribs;
 }
 
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index 6977c82..1375acb 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -538,6 +538,8 @@
   for (auto& observer : destruction_observers_)
     observer.OnWillDestroyStub();
 
+  share_group_ = nullptr;
+
   // Remove this after crbug.com/248395 is sorted out.
   // Destroy the surface before the context, some surface destructors make GL
   // calls.
@@ -670,23 +672,36 @@
     }
   }
 
+  if (context_group_->gpu_preferences().use_passthrough_cmd_decoder) {
+    // When using the passthrough command decoder, only share with other
+    // contexts in the explicitly requested share group
+    if (share_command_buffer_stub) {
+      share_group_ = share_command_buffer_stub->share_group_;
+    } else {
+      share_group_ = new gl::GLShareGroup();
+    }
+  } else {
+    // When using the validating command decoder, always use the global share
+    // group
+    share_group_ = channel_->share_group();
+  }
+
   scoped_refptr<gl::GLContext> context;
-  gl::GLShareGroup* gl_share_group = channel_->share_group();
-  if (use_virtualized_gl_context_ && gl_share_group) {
-    context = gl_share_group->GetSharedContext(surface_.get());
+  if (use_virtualized_gl_context_ && share_group_) {
+    context = share_group_->GetSharedContext(surface_.get());
     if (!context.get()) {
       context = gl::init::CreateGLContext(
-          gl_share_group, surface_.get(),
+          share_group_.get(), surface_.get(),
           GenerateGLContextAttribs(init_params.attribs,
                                    context_group_->gpu_preferences()));
       if (!context.get()) {
         DLOG(ERROR) << "Failed to create shared context for virtualization.";
         return false;
       }
-      // Ensure that context creation did not lose track of the intended
-      // gl_share_group.
-      DCHECK(context->share_group() == gl_share_group);
-      gl_share_group->SetSharedContext(surface_.get(), context.get());
+      // Ensure that context creation did not lose track of the intended share
+      // group.
+      DCHECK(context->share_group() == share_group_.get());
+      share_group_->SetSharedContext(surface_.get(), context.get());
     }
     // This should be either:
     // (1) a non-virtual GL context, or
@@ -694,8 +709,8 @@
     DCHECK(context->GetHandle() ||
            gl::GetGLImplementation() == gl::kGLImplementationMockGL ||
            gl::GetGLImplementation() == gl::kGLImplementationStubGL);
-    context = new GLContextVirtual(
-        gl_share_group, context.get(), decoder_->AsWeakPtr());
+    context = new GLContextVirtual(share_group_.get(), context.get(),
+                                   decoder_->AsWeakPtr());
     if (!context->Initialize(
             surface_.get(),
             GenerateGLContextAttribs(init_params.attribs,
@@ -709,7 +724,7 @@
   }
   if (!context.get()) {
     context = gl::init::CreateGLContext(
-        gl_share_group, surface_.get(),
+        share_group_.get(), surface_.get(),
         GenerateGLContextAttribs(init_params.attribs,
                                  context_group_->gpu_preferences()));
   }
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.h b/gpu/ipc/service/gpu_command_buffer_stub.h
index ff834de4..75dba0a 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.h
+++ b/gpu/ipc/service/gpu_command_buffer_stub.h
@@ -37,6 +37,10 @@
 #include "ui/gl/gpu_preference.h"
 #include "url/gurl.h"
 
+namespace gl {
+class GLShareGroup;
+}
+
 namespace gpu {
 struct Mailbox;
 struct SyncToken;
@@ -232,6 +236,7 @@
   std::unique_ptr<CommandExecutor> executor_;
   std::unique_ptr<SyncPointClient> sync_point_client_;
   scoped_refptr<gl::GLSurface> surface_;
+  scoped_refptr<gl::GLShareGroup> share_group_;
 
   base::ObserverList<DestructionObserver> destruction_observers_;
 
diff --git a/ios/build/chrome_build.gni b/ios/build/chrome_build.gni
index af4b46c..30ff8fb 100644
--- a/ios/build/chrome_build.gni
+++ b/ios/build/chrome_build.gni
@@ -24,6 +24,10 @@
 
   # List of plist templates to merge when generating chrome entitlements.
   ios_chrome_entitlements_additions = []
+
+  # List of plist templates to merge when generating EarlGrey tests
+  # entitlements.
+  ios_egtests_entitlements_additions = []
 }
 assert(!(ios_enable_today_extension && ios_enable_widget_extension),
        "Both today extensions cannot be enabled simultaneously.")
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 56695088..8271931 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -106,9 +106,6 @@
   if (ios_chrome_entitlements_additions != []) {
     plist_templates += ios_chrome_entitlements_additions
   }
-  if (!ios_automatically_manage_certs) {
-    plist_templates += [ "resources/AssociatedDomains.entitlements" ]
-  }
   substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
   output_name = "$target_gen_dir/$chromium_short_name.entitlements"
 }
diff --git a/ios/chrome/app/resources/AssociatedDomains.entitlements b/ios/chrome/app/resources/AssociatedDomains.entitlements
deleted file mode 100644
index d8cf1bd..0000000
--- a/ios/chrome/app/resources/AssociatedDomains.entitlements
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>com.apple.developer.associated-domains</key>
-	<array>
-		<string>applinks:goo.gl</string>
-	</array>
-</dict>
-</plist>
diff --git a/ios/chrome/browser/metrics/new_tab_page_uma.h b/ios/chrome/browser/metrics/new_tab_page_uma.h
index be25dd3..b6110c4 100644
--- a/ios/chrome/browser/metrics/new_tab_page_uma.h
+++ b/ios/chrome/browser/metrics/new_tab_page_uma.h
@@ -24,6 +24,7 @@
   ACTION_OPENED_RECENTLY_CLOSED_ENTRY,
   ACTION_OPENED_BOOKMARK,
   ACTION_OPENED_FOREIGN_SESSION,
+  ACTION_OPENED_DOODLE,
   NUM_ACTION_TYPES,
 };
 
diff --git a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view.mm b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view.mm
index d16a92a5..7c85551 100644
--- a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view.mm
+++ b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view.mm
@@ -39,7 +39,9 @@
 // Shadow radius of the viewport border.
 const CGFloat kViewportBorderShadowRadius = 10.0;
 // Padding of the viewport caption, below the viewport.
-const CGFloat kViewportCaptionPadding = 24.0;
+const CGFloat kViewportCaptionVerticalPadding = 14.0;
+// Padding of the viewport caption from the edges of the superview.
+const CGFloat kViewportCaptionHorizontalPadding = 20.0;
 // Shadow opacity of the viewport caption.
 const CGFloat kViewportCaptionShadowOpacity = 1.0;
 // Shadow radius of the viewport caption.
@@ -468,6 +470,8 @@
   UILabel* viewportCaption = [[[UILabel alloc] init] autorelease];
   NSString* label = l10n_util::GetNSString(IDS_IOS_QR_SCANNER_VIEWPORT_CAPTION);
   [viewportCaption setText:label];
+  [viewportCaption setNumberOfLines:0];
+  [viewportCaption setTextAlignment:NSTextAlignmentCenter];
   [viewportCaption setAccessibilityLabel:label];
   [viewportCaption setAccessibilityIdentifier:@"qr_scanner_viewport_caption"];
   [viewportCaption setTextColor:[UIColor whiteColor]];
@@ -482,11 +486,16 @@
   // Constraints for viewportCaption.
   [viewportCaption setTranslatesAutoresizingMaskIntoConstraints:NO];
   [NSLayoutConstraint activateConstraints:@[
-    [[viewportCaption centerXAnchor]
-        constraintEqualToAnchor:[self centerXAnchor]],
-    [[viewportCaption centerYAnchor]
+    [[viewportCaption topAnchor]
         constraintEqualToAnchor:[self centerYAnchor]
-                       constant:GetViewportSize() / 2 + kViewportCaptionPadding]
+                       constant:GetViewportSize() / 2 +
+                                kViewportCaptionVerticalPadding],
+    [viewportCaption.leadingAnchor
+        constraintEqualToAnchor:self.leadingAnchor
+                       constant:kViewportCaptionHorizontalPadding],
+    [viewportCaption.trailingAnchor
+        constraintEqualToAnchor:self.trailingAnchor
+                       constant:-kViewportCaptionHorizontalPadding],
   ]];
 }
 
diff --git a/ios/chrome/browser/ui/uikit_ui_util.mm b/ios/chrome/browser/ui/uikit_ui_util.mm
index b82122d..381ffc1 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/uikit_ui_util.mm
@@ -12,7 +12,6 @@
 #import <UIKit/UIKit.h>
 #include <cmath>
 
-#include "base/ios/ios_util.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "ios/chrome/browser/experimental_flags.h"
@@ -175,7 +174,7 @@
                                CaptureViewOption option) {
   UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES /* opaque */,
                                          scale);
-  if (base::ios::IsRunningOnIOS9OrLater() && option != kClientSideRendering) {
+  if (option != kClientSideRendering) {
     [view drawViewHierarchyInRect:view.bounds
                afterScreenUpdates:option == kAfterScreenUpdate];
   } else {
diff --git a/ios/chrome/share_extension/BUILD.gn b/ios/chrome/share_extension/BUILD.gn
index 17e50e1..c1ff17d 100644
--- a/ios/chrome/share_extension/BUILD.gn
+++ b/ios/chrome/share_extension/BUILD.gn
@@ -32,8 +32,7 @@
   substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
   output_name = "$target_gen_dir/share_extension.appex.entitlements"
   plist_templates =
-      [ "entitlements/external/share_extension.appex.entitlements" ] +
-      ios_chrome_entitlements_additions
+      [ "entitlements/external/share_extension.appex.entitlements" ]
 }
 
 ios_appex_bundle("share_extension") {
diff --git a/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni b/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni
index 9e55660f..b18a357 100644
--- a/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni
+++ b/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni
@@ -53,8 +53,8 @@
       output_name = "$target_gen_dir/$_target_name.entitlements"
       plist_templates =
           [ "//ios/chrome/test/earl_grey/resources/Chrome.entitlements" ]
-      if (ios_chrome_entitlements_additions != []) {
-        plist_templates += ios_chrome_entitlements_additions
+      if (ios_egtests_entitlements_additions != []) {
+        plist_templates += ios_egtests_entitlements_additions
       }
     }
   }
diff --git a/ios/chrome/today_extension/BUILD.gn b/ios/chrome/today_extension/BUILD.gn
index f201cbf..8a9ebffd 100644
--- a/ios/chrome/today_extension/BUILD.gn
+++ b/ios/chrome/today_extension/BUILD.gn
@@ -26,8 +26,7 @@
   substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
   output_name = "$target_gen_dir/today_extension.appex.entitlements"
   plist_templates =
-      [ "entitlements/external/today_extension.appex.entitlements" ] +
-      ios_chrome_entitlements_additions
+      [ "entitlements/external/today_extension.appex.entitlements" ]
 }
 
 ios_appex_bundle("today_extension") {
diff --git a/ios/chrome/widget_extension/BUILD.gn b/ios/chrome/widget_extension/BUILD.gn
index 6b020507..7fbc32a 100644
--- a/ios/chrome/widget_extension/BUILD.gn
+++ b/ios/chrome/widget_extension/BUILD.gn
@@ -16,8 +16,7 @@
   substitutions = [ "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix" ]
   output_name = "$target_gen_dir/today_extension.appex.entitlements"
   plist_templates =
-      [ "entitlements/external/widget_extension.appex.entitlements" ] +
-      ios_chrome_entitlements_additions
+      [ "entitlements/external/widget_extension.appex.entitlements" ]
 }
 
 ios_appex_bundle("widget_extension") {
diff --git a/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm b/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
index 71fb6058b..06c398cd 100644
--- a/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
@@ -96,7 +96,7 @@
   if (self.contentViewController == contentViewController)
     return;
   if ([self isViewLoaded]) {
-    [self removeChildViewController:self.contentViewController];
+    [self detachChildViewController:self.contentViewController];
     [self addChildViewController:contentViewController
                        toSubview:self.contentView];
   }
@@ -107,7 +107,7 @@
   if (self.toolbarViewController == toolbarViewController)
     return;
   if ([self isViewLoaded]) {
-    [self removeChildViewController:self.toolbarViewController];
+    [self detachChildViewController:self.toolbarViewController];
     [self addChildViewController:toolbarViewController
                        toSubview:self.toolbarView];
   }
@@ -118,7 +118,7 @@
   if (self.tabStripViewController == tabStripViewController)
     return;
   if ([self isViewLoaded]) {
-    [self removeChildViewController:self.tabStripViewController];
+    [self detachChildViewController:self.tabStripViewController];
     [self addChildViewController:tabStripViewController
                        toSubview:self.tabStripView];
   }
@@ -141,7 +141,7 @@
   [viewController didMoveToParentViewController:self];
 }
 
-- (void)removeChildViewController:(UIViewController*)viewController {
+- (void)detachChildViewController:(UIViewController*)viewController {
   if (viewController.parentViewController != self)
     return;
   [viewController willMoveToParentViewController:nil];
diff --git a/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm b/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
index dd2f71f..4afcb23 100644
--- a/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
@@ -19,7 +19,6 @@
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h"
 #import "ios/clean/chrome/browser/ui/web_contents/web_coordinator.h"
 #import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
-#import "ios/web/public/web_state/web_state_observer_bridge.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -35,10 +34,7 @@
 @property(nonatomic, strong) TabContainerViewController* viewController;
 @end
 
-@implementation TabCoordinator {
-  std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
-}
-
+@implementation TabCoordinator
 @synthesize presentationKey = _presentationKey;
 @synthesize viewController = _viewController;
 @synthesize webState = _webState;
@@ -57,11 +53,9 @@
   [webCoordinator start];
 
   ToolbarCoordinator* toolbarCoordinator = [[ToolbarCoordinator alloc] init];
+  toolbarCoordinator.webState = self.webState;
   [self addChildCoordinator:toolbarCoordinator];
-  // PLACEHOLDER : Pass the WebState into the toolbar coordinator and let it
-  // create a mediator (or whatever) that observes the webState.
-  _webStateObserver = base::MakeUnique<web::WebStateObserverBridge>(
-      self.webState, toolbarCoordinator);
+
   // Unset the base view controller, so |toolbarCoordinator| doesn't present
   // its view controller.
   toolbarCoordinator.context.baseViewController = nil;
@@ -93,7 +87,6 @@
   [self.viewController.presentingViewController
       dismissViewControllerAnimated:self.context.animated
                          completion:nil];
-  _webStateObserver.reset();
 }
 
 - (BOOL)canAddOverlayCoordinator:(BrowserCoordinator*)overlayCoordinator {
diff --git a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm
index 0fcdfe74..5a8c92fd 100644
--- a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_container_view_controller.mm
@@ -36,8 +36,9 @@
 
 @property(nonatomic, strong) NSLayoutConstraint* stripHeightConstraint;
 
-// Contained view controller utility methods.
-- (void)removeChildViewController:(UIViewController*)viewController;
+// Contained view controller utility methods. This method cannot be named
+//-removeChildViewController:, as that is a private superclass method.
+- (void)detachChildViewController:(UIViewController*)viewController;
 
 // Called after a new content view controller is set, but before
 // |-didMoveToParentViewController:| is called on that view controller.
@@ -76,7 +77,7 @@
   [NSLayoutConstraint
       deactivateConstraints:self.contentConstraintsWithoutStrip];
   [NSLayoutConstraint deactivateConstraints:self.contentConstraintsWithStrip];
-  [self removeChildViewController:self.contentViewController];
+  [self detachChildViewController:self.contentViewController];
 
   // Add the new content view controller.
   [self addChildViewController:contentViewController];
@@ -95,7 +96,7 @@
   // Remove the current strip view controller, if any.
   [NSLayoutConstraint deactivateConstraints:self.stripConstraints];
   [NSLayoutConstraint deactivateConstraints:self.contentConstraintsWithStrip];
-  [self removeChildViewController:self.tabStripViewController];
+  [self detachChildViewController:self.tabStripViewController];
 
   // Add the new strip view controller.
   [self addChildViewController:tabStripViewController];
@@ -212,7 +213,7 @@
 
 #pragma mark - Private methods
 
-- (void)removeChildViewController:(UIViewController*)viewController {
+- (void)detachChildViewController:(UIViewController*)viewController {
   if (viewController.parentViewController != self)
     return;
   [viewController willMoveToParentViewController:nil];
diff --git a/ios/clean/chrome/browser/ui/toolbar/BUILD.gn b/ios/clean/chrome/browser/ui/toolbar/BUILD.gn
index c0df5d9..4fe1a58 100644
--- a/ios/clean/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/toolbar/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "toolbar_coordinator.h",
     "toolbar_coordinator.mm",
+    "toolbar_mediator.h",
+    "toolbar_mediator.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
@@ -23,6 +25,7 @@
 
 source_set("toolbar_ui") {
   sources = [
+    "toolbar_consumer.h",
     "toolbar_view_controller.h",
     "toolbar_view_controller.mm",
   ]
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_consumer.h b/ios/clean/chrome/browser/ui/toolbar/toolbar_consumer.h
new file mode 100644
index 0000000..89b51f9
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_consumer.h
@@ -0,0 +1,17 @@
+// 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 IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_CONSUMER_H_
+#define IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_CONSUMER_H_
+
+#import <UIKit/UIKit.h>
+
+// ToolbarConsumer sets the current appearance of the Toolbar based on
+// WebState or other data sources provided by this protocol.
+@protocol ToolbarConsumer
+// Sets the text for a label appearing in the center of the toolbar.
+- (void)setCurrentPageText:(NSString*)text;
+@end
+
+#endif  // IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_CONSUMER_H_
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h b/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h
index 8d74ee3d..3bd00dfd 100644
--- a/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h
@@ -10,10 +10,15 @@
 #define IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_COORDINATOR_H_
 
 #import "ios/clean/chrome/browser/browser_coordinator.h"
-#import "ios/web/public/web_state/web_state_observer_bridge.h"
+
+namespace web {
+class WebState;
+}
 
 // Coordinator to run a toolbar -- a UI element housing controls.
-@interface ToolbarCoordinator : BrowserCoordinator<CRWWebStateObserver>
+@interface ToolbarCoordinator : BrowserCoordinator
+// The web state this ToolbarCoordinator is handling.
+@property(nonatomic, assign) web::WebState* webState;
 @end
 
 #endif  // IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_COORDINATOR_H_
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm b/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm
index fa452cb1..8bda941 100644
--- a/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm
@@ -8,13 +8,12 @@
 
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h"
 
-#include "base/strings/sys_string_conversions.h"
 #import "ios/clean/chrome/browser/browser_coordinator+internal.h"
 #import "ios/clean/chrome/browser/ui/commands/toolbar_commands.h"
+#import "ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.h"
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h"
 #import "ios/clean/chrome/browser/ui/tools/tools_coordinator.h"
 #import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
-#include "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -23,29 +22,37 @@
 @interface ToolbarCoordinator ()<ToolbarCommands>
 @property(nonatomic, weak) ToolsCoordinator* toolsMenuCoordinator;
 @property(nonatomic, strong) ToolbarViewController* viewController;
+@property(nonatomic, strong) ToolbarMediator* mediator;
 @end
 
 @implementation ToolbarCoordinator
 @synthesize toolsMenuCoordinator = _toolsMenuCoordinator;
 @synthesize viewController = _viewController;
+@synthesize webState = _webState;
+@synthesize mediator = _mediator;
+
+- (instancetype)init {
+  if ((self = [super init])) {
+    _mediator = [[ToolbarMediator alloc] init];
+  }
+  return self;
+}
+
+- (void)setWebState:(web::WebState*)webState {
+  _webState = webState;
+  self.mediator.webState = self.webState;
+}
 
 - (void)start {
   self.viewController = [[ToolbarViewController alloc] init];
   self.viewController.toolbarCommandHandler = self;
+  self.mediator.consumer = self.viewController;
 
   [self.context.baseViewController presentViewController:self.viewController
                                                 animated:self.context.animated
                                               completion:nil];
 }
 
-#pragma mark - CRWWebStateObserver
-
-- (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success {
-  const GURL& pageURL = webState->GetVisibleURL();
-  [self.viewController
-      setCurrentPageText:base::SysUTF8ToNSString(pageURL.spec())];
-}
-
 #pragma mark - ToolbarCommands
 
 - (void)showToolsMenu {
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.h b/ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.h
new file mode 100644
index 0000000..2afe96d
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.h
@@ -0,0 +1,30 @@
+// 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 IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MEDIATOR_H_
+#define IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MEDIATOR_H_
+
+#import <Foundation/Foundation.h>
+
+@protocol ToolbarConsumer;
+
+namespace web {
+class WebState;
+}
+
+// A mediator object that provides the relevant properties of a web state
+// to a consumer.
+@interface ToolbarMediator : NSObject
+
+// The WebState whose properties this object mediates. This can change during
+// the lifetime of this object and may be null.
+@property(nonatomic, assign) web::WebState* webState;
+
+// The consumer for this object. This can change during the lifetime of this
+// object and may be nil.
+@property(nonatomic, strong) id<ToolbarConsumer> consumer;
+
+@end
+
+#endif  // IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MEDIATOR_H_
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.mm b/ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.mm
new file mode 100644
index 0000000..256084c
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.mm
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/sys_string_conversions.h"
+#import "ios/clean/chrome/browser/ui/toolbar/toolbar_consumer.h"
+#include "ios/web/public/web_state/web_state.h"
+#import "ios/web/public/web_state/web_state_observer_bridge.h"
+
+@interface ToolbarMediator ()<CRWWebStateObserver>
+@end
+
+@implementation ToolbarMediator {
+  std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
+}
+
+@synthesize consumer = _consumer;
+@synthesize webState = _webState;
+
+- (void)dealloc {
+  _webStateObserver.reset();
+  _webState = nullptr;
+}
+
+- (void)setWebState:(web::WebState*)webState {
+  _webState = webState;
+  _webStateObserver =
+      base::MakeUnique<web::WebStateObserverBridge>(self.webState, self);
+}
+
+#pragma mark - CRWWebStateObserver
+
+- (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success {
+  const GURL& pageURL = webState->GetVisibleURL();
+  [self.consumer setCurrentPageText:base::SysUTF8ToNSString(pageURL.spec())];
+}
+
+@end
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h b/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h
index 9bdcaa3..e5f5f04 100644
--- a/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h
@@ -12,6 +12,7 @@
 #import <UIKit/UIKit.h>
 
 #import "ios/clean/chrome/browser/ui/animators/zoom_transition_delegate.h"
+#import "ios/clean/chrome/browser/ui/toolbar/toolbar_consumer.h"
 
 @protocol ToolbarCommands;
 
@@ -20,14 +21,11 @@
 // This view controller will fill its container; it is up to the containing
 // view controller or presentation controller to configure an appropriate
 // height for it.
-@interface ToolbarViewController : UIViewController<ZoomTransitionDelegate>
+@interface ToolbarViewController
+    : UIViewController<ZoomTransitionDelegate, ToolbarConsumer>
 
 // The action delegate for this view controller.
 @property(nonatomic, weak) id<ToolbarCommands> toolbarCommandHandler;
-
-// Sets the text for a label appearing in the center of the toolbar.
-- (void)setCurrentPageText:(NSString*)text;
-
 @end
 
 #endif  // IOS_CLEAN_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_VIEW_CONTROLLER_H_
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm b/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm
index 260735b..57335f8 100644
--- a/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.mm
@@ -171,7 +171,7 @@
   }
 }
 
-#pragma mark - Public API
+#pragma mark - ToolbarWebStateConsumer
 
 - (void)setCurrentPageText:(NSString*)text {
   self.omnibox.text = text;
diff --git a/ios/third_party/material_font_disk_loader_ios/README.chromium b/ios/third_party/material_font_disk_loader_ios/README.chromium
index 0e21813e..4e20df8 100644
--- a/ios/third_party/material_font_disk_loader_ios/README.chromium
+++ b/ios/third_party/material_font_disk_loader_ios/README.chromium
@@ -1,7 +1,7 @@
 Name: Material Font Disk Loader iOS
 URL: https://github.com/material-foundation/material-font-disk-loader-ios
 Version: 0
-Revision: 93acc021e3034898716028822cb802a3a816be7e
+Revision: 8e30188777b016182658fbaa0a4a020a48183224
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/ios/web/navigation/navigation_item_impl.h b/ios/web/navigation/navigation_item_impl.h
index f42cacc..2280735 100644
--- a/ios/web/navigation/navigation_item_impl.h
+++ b/ios/web/navigation/navigation_item_impl.h
@@ -95,8 +95,7 @@
   void SetIsCreatedFromHashChange(bool hash_change);
   bool IsCreatedFromHashChange() const;
 
-  // The initiation type of this pending navigation. Resets to user-initiated
-  // after commit.
+  // Initiation type of this pending navigation. Resets to NONE after commit.
   void SetNavigationInitiationType(
       web::NavigationInitiationType navigation_initiation_type);
   web::NavigationInitiationType NavigationInitiationType() const;
diff --git a/ios/web/navigation/navigation_item_impl.mm b/ios/web/navigation/navigation_item_impl.mm
index 1757cd9..31f35756 100644
--- a/ios/web/navigation/navigation_item_impl.mm
+++ b/ios/web/navigation/navigation_item_impl.mm
@@ -45,8 +45,7 @@
       has_state_been_replaced_(false),
       is_created_from_hash_change_(false),
       should_skip_repost_form_confirmation_(false),
-      navigation_initiation_type_(
-          web::NavigationInitiationType::USER_INITIATED),
+      navigation_initiation_type_(web::NavigationInitiationType::NONE),
       is_unsafe_(false),
       facade_delegate_(nullptr) {}
 
@@ -306,9 +305,9 @@
 }
 
 void NavigationItemImpl::ResetForCommit() {
-  // Any state that only matters when a navigation item is pending should be
-  // cleared here.
-  SetNavigationInitiationType(web::NavigationInitiationType::USER_INITIATED);
+  // Navigation initiation type is only valid for pending navigations, thus
+  // always reset to NONE after the item is committed.
+  SetNavigationInitiationType(web::NavigationInitiationType::NONE);
 }
 
 }  // namespace web
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index 11663bd..7293cb5 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -28,8 +28,12 @@
 
 // Defines the ways how a pending navigation can be initiated.
 enum class NavigationInitiationType {
+  // Navigation initiation type is only valid for pending navigations, use NONE
+  // if a navigation is already committed.
+  NONE = 0,
+
   // Navigation was initiated by actual user action.
-  USER_INITIATED = 1,
+  USER_INITIATED,
 
   // Navigation was initiated by renderer. Examples of renderer-initiated
   // navigations include:
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 9be54a3..bfcc3f98 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1066,14 +1066,22 @@
 }
 
 - (NSDictionary*)WKWebViewObservers {
-  return @{
-    @"certificateChain" : @"webViewSecurityFeaturesDidChange",
+  NSMutableDictionary* result = [NSMutableDictionary dictionary];
+  if (base::ios::IsRunningOnIOS10OrLater()) {
+    result[@"serverTrust"] = @"webViewSecurityFeaturesDidChange";
+  } else {
+    result[@"certificateChain"] = @"webViewSecurityFeaturesDidChange";
+  }
+
+  [result addEntriesFromDictionary:@{
     @"estimatedProgress" : @"webViewEstimatedProgressDidChange",
     @"hasOnlySecureContent" : @"webViewSecurityFeaturesDidChange",
     @"loading" : @"webViewLoadingStateDidChange",
     @"title" : @"webViewTitleDidChange",
     @"URL" : @"webViewURLDidChange",
-  };
+  }];
+
+  return result;
 }
 
 // NativeControllerDelegate method, called to inform that title has changed.
diff --git a/mash/BUILD.gn b/mash/BUILD.gn
index 64259637..73689fb4 100644
--- a/mash/BUILD.gn
+++ b/mash/BUILD.gn
@@ -114,8 +114,7 @@
       "test/mash_unittests.cc",
     ]
     deps = [
-      "//ash/common:unittests",
-      "//ash/common/test:test_support",
+      "//ash:common_unittests",
       "//ash/mus:resources",
       "//ash/mus:unittests",
       "//base",
diff --git a/mash/test/mash_test_suite.cc b/mash/test/mash_test_suite.cc
index 2f7a94d..51210a0c 100644
--- a/mash/test/mash_test_suite.cc
+++ b/mash/test/mash_test_suite.cc
@@ -17,6 +17,7 @@
 #include "ui/compositor/compositor.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_switches.h"
+#include "ui/gl/test/gl_surface_test_support.h"
 
 namespace mash {
 namespace test {
@@ -61,6 +62,7 @@
 
 void MashTestSuite::Initialize() {
   base::TestSuite::Initialize();
+  gl::GLSurfaceTestSupport::InitializeOneOff();
 
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kOverrideUseSoftwareGLForTests);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index bea9a92..f8c8d24 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -234,7 +234,6 @@
       suspend_enabled_(params.allow_suspend()),
       use_fallback_path_(false),
       is_encrypted_(false),
-      underflow_count_(0),
       preroll_attempt_pending_(false),
       observer_(params.media_observer()),
       max_keyframe_distance_to_disable_background_video_(
@@ -1111,9 +1110,9 @@
   if (time_updated)
     should_notify_time_changed_ = true;
 
-  // Reset underflow count upon seek; this prevents looping videos and user
-  // actions from artificially inflating the underflow count.
-  underflow_count_ = 0;
+  // Reset underflow duration upon seek; this prevents looping videos and user
+  // actions from artificially inflating the duration.
+  underflow_timer_.reset();
 
   // Background video optimizations are delayed when shown/hidden if pipeline
   // is seeking.
@@ -1284,13 +1283,10 @@
       "pipeline_buffering_state", state));
 
   if (state == BUFFERING_HAVE_ENOUGH) {
-    if (data_source_ &&
-        highest_ready_state_ < WebMediaPlayer::ReadyStateHaveEnoughData) {
-      DCHECK_EQ(underflow_count_, 0);
-      // Record a zero value for underflow histograms so that the histogram
+    if (highest_ready_state_ < WebMediaPlayer::ReadyStateHaveEnoughData) {
+      // Record a zero value for underflow histogram so that the histogram
       // includes playbacks which never encounter an underflow event.
-      UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", 0);
-      UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", base::TimeDelta());
+      RecordUnderflowDuration(base::TimeDelta());
     }
 
     // TODO(chcunningham): Monitor playback position vs buffered. Potentially
@@ -1312,11 +1308,9 @@
     // report once playback starts.
     ReportMemoryUsage();
 
-    // Report the amount of time it took to leave the underflow state. Don't
-    // bother to report this for MSE playbacks since it's out of our control.
-    if (underflow_timer_ && data_source_) {
-      UMA_HISTOGRAM_TIMES("Media.UnderflowDuration",
-                          underflow_timer_->Elapsed());
+    // Report the amount of time it took to leave the underflow state.
+    if (underflow_timer_) {
+      RecordUnderflowDuration(underflow_timer_->Elapsed());
       underflow_timer_.reset();
     }
   } else {
@@ -1328,7 +1322,6 @@
     // report the value when transitioning from HAVE_ENOUGH to HAVE_NOTHING.
     if (data_source_ &&
         ready_state_ == WebMediaPlayer::ReadyStateHaveEnoughData) {
-      UMA_HISTOGRAM_COUNTS_100("Media.UnderflowCount", ++underflow_count_);
       underflow_timer_.reset(new base::ElapsedTimer());
     }
 
@@ -2300,4 +2293,12 @@
   ScheduleRestart();
 }
 
+void WebMediaPlayerImpl::RecordUnderflowDuration(base::TimeDelta duration) {
+  DCHECK(data_source_ || chunk_demuxer_);
+  if (data_source_)
+    UMA_HISTOGRAM_TIMES("Media.UnderflowDuration", duration);
+  else
+    UMA_HISTOGRAM_TIMES("Media.UnderflowDuration.MSE", duration);
+}
+
 }  // namespace media
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 7dbf69c..974141c 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -446,6 +446,10 @@
   void ReportTimeFromForegroundToFirstFrame(base::TimeTicks foreground_time,
                                             base::TimeTicks new_frame_time);
 
+  // Records |duration| to the appropriate metric based on whether we're
+  // handling a src= or MSE based playback.
+  void RecordUnderflowDuration(base::TimeDelta duration);
+
   blink::WebLocalFrame* frame_;
 
   // The playback state last reported to |delegate_|, to avoid setting duplicate
@@ -659,8 +663,7 @@
   std::unique_ptr<WatchTimeReporter> watch_time_reporter_;
   bool is_encrypted_;
 
-  // Number of times we've reached BUFFERING_HAVE_NOTHING during playback.
-  int underflow_count_;
+  // Elapsed time since we've last reached BUFFERING_HAVE_NOTHING.
   std::unique_ptr<base::ElapsedTimer> underflow_timer_;
 
   // Used to track loading progress, used by IsPrerollAttemptNeeded().
diff --git a/media/formats/mpeg/mpeg1_audio_stream_parser.cc b/media/formats/mpeg/mpeg1_audio_stream_parser.cc
index bf5d1cbd..a86c1e1b 100644
--- a/media/formats/mpeg/mpeg1_audio_stream_parser.cc
+++ b/media/formats/mpeg/mpeg1_audio_stream_parser.cc
@@ -138,7 +138,7 @@
     return false;
   }
 
-  if (layer == kLayer2 && kIsAllowed[bitrate_index][channel_mode]) {
+  if (layer == kLayer2 && !kIsAllowed[bitrate_index][channel_mode]) {
     MEDIA_LOG(ERROR, media_log) << "Invalid (bitrate_index, channel_mode)"
                                 << " combination :" << std::hex
                                 << " bitrate_index " << bitrate_index
diff --git a/media/formats/mpeg/mpeg1_audio_stream_parser_unittest.cc b/media/formats/mpeg/mpeg1_audio_stream_parser_unittest.cc
index bfa8021..f403ca1b 100644
--- a/media/formats/mpeg/mpeg1_audio_stream_parser_unittest.cc
+++ b/media/formats/mpeg/mpeg1_audio_stream_parser_unittest.cc
@@ -48,6 +48,26 @@
   EXPECT_GT(last_audio_config().codec_delay(), 0);
 }
 
+TEST_F(MPEG1AudioStreamParserTest, UnalignedAppendMP2) {
+  const std::string expected =
+      "NewSegment"
+      "{ 0K }"
+      "{ 0K }"
+      "{ 0K }"
+      "{ 0K }"
+      "EndOfSegment"
+      "NewSegment"
+      "{ 0K }"
+      "{ 0K }"
+      "{ 0K }"
+      "{ 0K }"
+      "{ 0K }"
+      "{ 0K }"
+      "EndOfSegment";
+  EXPECT_EQ(expected, ParseFile("sfx.mp2", 17));
+  EXPECT_GT(last_audio_config().codec_delay(), 0);
+}
+
 // Test parsing with a larger piece size to verify that multiple buffers
 // are passed to |new_buffer_cb_|.
 TEST_F(MPEG1AudioStreamParserTest, UnalignedAppend512) {
diff --git a/media/test/data/sfx.mp2 b/media/test/data/sfx.mp2
new file mode 100644
index 0000000..46d0e314c
--- /dev/null
+++ b/media/test/data/sfx.mp2
Binary files differ
diff --git a/media/tools/layout_tests/layouttest_analyzer.py b/media/tools/layout_tests/layouttest_analyzer.py
index f0ba917f..b137fd6 100755
--- a/media/tools/layout_tests/layouttest_analyzer.py
+++ b/media/tools/layout_tests/layouttest_analyzer.py
@@ -379,7 +379,7 @@
           '<tr><td><a href="%s">%s</a></td><td><a href="%s">dashboard</a>'
           '</td><td>%s</td></tr>') % (
               layouttest_root_path + testname, testname,
-              ('http://test-results.appspot.com/dashboards/'
+              ('https://test-results.appspot.com/dashboards/'
                'flakiness_dashboard.html#tests=%s') % testname,
               data_map[tg][0][testname]))
     file_object.write('</table>')
diff --git a/media/tools/layout_tests/layouttest_analyzer_helpers.py b/media/tools/layout_tests/layouttest_analyzer_helpers.py
index b3f3cbd..63bb823 100644
--- a/media/tools/layout_tests/layouttest_analyzer_helpers.py
+++ b/media/tools/layout_tests/layouttest_analyzer_helpers.py
@@ -231,7 +231,7 @@
           gpu_link = ''
           if 'GPU' in te_info:
             gpu_link = 'group=%40ToT%20GPU%20Mesa%20-%20chromium.org&'
-          dashboard_link = ('http://test-results.appspot.com/dashboards/'
+          dashboard_link = ('https://test-results.appspot.com/dashboards/'
                             'flakiness_dashboard.html#%stests=%s') % (
                                 gpu_link, test_name)
           return_str += '<li><a href="%s">%s</a> (%s) </li>' % (
@@ -430,7 +430,7 @@
           gpu_link = ''
           if 'GPU' in line:
             gpu_link = 'group=%40ToT%20GPU%20Mesa%20-%20chromium.org&'
-          dashboard_link = ('http://test-results.appspot.com/dashboards/'
+          dashboard_link = ('https://test-results.appspot.com/dashboards/'
                             'flakiness_dashboard.html#%stests=%s') % (
                                 gpu_link, test_name)
           line = line.replace(test_name, '<a href="%s">%s</a>' % (
diff --git a/media/tools/layout_tests/layouttest_analyzer_helpers_unittest.py b/media/tools/layout_tests/layouttest_analyzer_helpers_unittest.py
index ab14d87a..9a94f3b 100755
--- a/media/tools/layout_tests/layouttest_analyzer_helpers_unittest.py
+++ b/media/tools/layout_tests/layouttest_analyzer_helpers_unittest.py
@@ -143,7 +143,7 @@
                         '<li>jamesr@google.com</li>\n'
                         '<li>2011-09-01 18:00:23</li>\n'
                         '<ul><li>-<a href="http://webkit.org/b/63878">'
-                        'BUGWK63878</a> : <a href="http://test-results.'
+                        'BUGWK63878</a> : <a href="https://test-results.'
                         'appspot.com/dashboards/flakiness_dashboard.html#'
                         'tests=fast/dom/dom-constructors.html">fast/dom/'
                         'dom-constructors.html</a> = TEXT</li>\n</ul></ul>')
diff --git a/mojo/edk/js/tests/BUILD.gn b/mojo/edk/js/tests/BUILD.gn
index 45ec071..41850d7 100644
--- a/mojo/edk/js/tests/BUILD.gn
+++ b/mojo/edk/js/tests/BUILD.gn
@@ -23,7 +23,6 @@
 test("mojo_js_integration_tests") {
   deps = [
     ":js_to_cpp_bindings",
-    "//base/test:test_support",
     "//gin:gin_test",
     "//mojo/common",
     "//mojo/edk/js",
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.cc b/mojo/edk/js/tests/js_to_cpp_tests.cc
index 8896953..e5e6bd1 100644
--- a/mojo/edk/js/tests/js_to_cpp_tests.cc
+++ b/mojo/edk/js/tests/js_to_cpp_tests.cc
@@ -15,7 +15,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "gin/array_buffer.h"
 #include "gin/public/isolate_holder.h"
@@ -419,10 +418,6 @@
   base::MessageLoop loop;
   base::RunLoop run_loop_;
 
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
-
   DISALLOW_COPY_AND_ASSIGN(JsToCppTest);
 };
 
diff --git a/net/docs/bug-triage-labels.md b/net/docs/bug-triage-labels.md
index 4b4d8b5..d1faafa 100644
--- a/net/docs/bug-triage-labels.md
+++ b/net/docs/bug-triage-labels.md
@@ -149,8 +149,8 @@
 
 * **OS>Systems>Network** / **OS>Systems>Mobile** / **OS>Systems>Bluetooth**
 
-    These should be used for issues with ChromeOS's platform network code, and
-    not net/ issues on ChromeOS.
+    These should be used for issues with Chrome OS's platform network code, and
+    not net/ issues on Chrome OS.
 
 * **Blink>SecurityFeature**
 
diff --git a/net/docs/bug-triage-suggested-workflow.md b/net/docs/bug-triage-suggested-workflow.md
index b41944a..147dd8b 100644
--- a/net/docs/bug-triage-suggested-workflow.md
+++ b/net/docs/bug-triage-suggested-workflow.md
@@ -90,7 +90,7 @@
   job is done, though you should still ask for a net-internals dump if it seems
   likely to be useful.
 
-* Note that ChromeOS-specific network-related code (Captive portal detection,
+* Note that Chrome-OS-specific network-related code (Captive portal detection,
   connectivity detection, login, etc) may not all have appropriate more
   specific subcomponents, but are not in areas handled by the network stack
   team. Just make sure those have the OS-Chrome label, and any more specific
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 4b5a3b0..a5395d7 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -212,7 +212,7 @@
     DCHECK(stream_request_ != NULL);
     auth_controllers_[target] = NULL;
     ResetStateForRestart();
-    rv = stream_request_->RestartTunnelWithProxyAuth(credentials);
+    rv = stream_request_->RestartTunnelWithProxyAuth();
   } else {
     // In this case, we've gathered credentials for the server or the proxy
     // but it is not during the tunneling phase.
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index ccd15360..edc71ff 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -14904,7 +14904,7 @@
     return weak_stream;
   }
 
-  int RestartTunnelWithProxyAuth(const AuthCredentials& credentials) override {
+  int RestartTunnelWithProxyAuth() override {
     ADD_FAILURE();
     return ERR_UNEXPECTED;
   }
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 1a19744..ecbe8820 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -30,7 +30,6 @@
 
 namespace net {
 
-class AuthCredentials;
 class BidirectionalStreamImpl;
 class HostMappingRules;
 class HttpAuthController;
@@ -169,8 +168,7 @@
   // will have been called.  It now becomes the delegate's responsibility
   // to collect the necessary credentials, and then call this method to
   // resume the HttpStream creation process.
-  virtual int RestartTunnelWithProxyAuth(
-      const AuthCredentials& credentials) = 0;
+  virtual int RestartTunnelWithProxyAuth() = 0;
 
   // Called when the priority of the parent transaction changes.
   virtual void SetPriority(RequestPriority priority) = 0;
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 0d59cc5..c837f75 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -301,8 +301,7 @@
   return StartInternal();
 }
 
-int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth(
-    const AuthCredentials& credentials) {
+int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth() {
   DCHECK(establishing_tunnel_);
   next_state_ = STATE_RESTART_TUNNEL_AUTH;
   stream_.reset();
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index a04e8e3..9201edc 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -202,7 +202,7 @@
   // appropriate ClientSocketPool.
   int Preconnect(int num_streams);
 
-  int RestartTunnelWithProxyAuth(const AuthCredentials& credentials);
+  int RestartTunnelWithProxyAuth();
   LoadState GetLoadState() const;
 
   // Tells |this| that |delegate_| has determined it still needs to continue
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
index 72669128..aa2a95c 100644
--- a/net/http/http_stream_factory_impl_job_controller.cc
+++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -184,10 +184,9 @@
   MaybeNotifyFactoryOfCompletion();
 }
 
-int HttpStreamFactoryImpl::JobController::RestartTunnelWithProxyAuth(
-    const AuthCredentials& credentials) {
+int HttpStreamFactoryImpl::JobController::RestartTunnelWithProxyAuth() {
   DCHECK(bound_job_);
-  return bound_job_->RestartTunnelWithProxyAuth(credentials);
+  return bound_job_->RestartTunnelWithProxyAuth();
 }
 
 void HttpStreamFactoryImpl::JobController::SetPriority(
diff --git a/net/http/http_stream_factory_impl_job_controller.h b/net/http/http_stream_factory_impl_job_controller.h
index df246a58..c57ecd4 100644
--- a/net/http/http_stream_factory_impl_job_controller.h
+++ b/net/http/http_stream_factory_impl_job_controller.h
@@ -65,7 +65,7 @@
 
   // Called to resume the HttpStream creation process when necessary
   // Proxy authentication credentials are collected.
-  int RestartTunnelWithProxyAuth(const AuthCredentials& credentials) override;
+  int RestartTunnelWithProxyAuth() override;
 
   // Called when the priority of transaction changes.
   void SetPriority(RequestPriority priority) override;
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index e6bcbe4..76abed6 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -122,9 +122,8 @@
       response_info, used_ssl_config, used_proxy_info, stream);
 }
 
-int HttpStreamFactoryImpl::Request::RestartTunnelWithProxyAuth(
-    const AuthCredentials& credentials) {
-  return helper_->RestartTunnelWithProxyAuth(credentials);
+int HttpStreamFactoryImpl::Request::RestartTunnelWithProxyAuth() {
+  return helper_->RestartTunnelWithProxyAuth();
 }
 
 void HttpStreamFactoryImpl::Request::SetPriority(RequestPriority priority) {
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index 91cb0d7..703dedd 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -36,8 +36,7 @@
 
     // Called to resume the HttpStream creation process when necessary
     // Proxy authentication credentials are collected.
-    virtual int RestartTunnelWithProxyAuth(
-        const AuthCredentials& credentials) = 0;
+    virtual int RestartTunnelWithProxyAuth() = 0;
 
     // Called when the priority of transaction changes.
     virtual void SetPriority(RequestPriority priority) = 0;
@@ -114,7 +113,7 @@
 
   // HttpStreamRequest methods.
 
-  int RestartTunnelWithProxyAuth(const AuthCredentials& credentials) override;
+  int RestartTunnelWithProxyAuth() override;
   void SetPriority(RequestPriority priority) override;
   LoadState GetLoadState() const override;
   bool was_alpn_negotiated() const override;
diff --git a/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
index df3e82d..3456f55 100644
--- a/net/proxy/proxy_resolver_v8_tracing_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_checker.h"
 #include "base/values.h"
@@ -950,10 +949,6 @@
 // this test was written) each ProxyResolverV8Tracing creates its own thread to
 // run V8 on, however each thread is operating on the same v8::Isolate.
 TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) {
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
-
   // ------------------------
   // Setup resolver0
   // ------------------------
diff --git a/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc
index 9b00fe83..53cb1cb 100644
--- a/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "base/threading/platform_thread.h"
 #include "base/values.h"
 #include "net/base/net_errors.h"
@@ -1070,10 +1069,6 @@
 // own thread to run V8 on, however each thread is operating on the same
 // v8::Isolate.
 TEST_F(ProxyResolverV8TracingWrapperTest, MultipleResolvers) {
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
-
   // ------------------------
   // Setup resolver0
   // ------------------------
diff --git a/net/proxy/proxy_resolver_v8_unittest.cc b/net/proxy/proxy_resolver_v8_unittest.cc
index 0142c14..d6f5215 100644
--- a/net/proxy/proxy_resolver_v8_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_unittest.cc
@@ -2,18 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "net/proxy/proxy_resolver_v8.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_async_task_scheduler.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_resolver_script_data.h"
+#include "net/proxy/proxy_resolver_v8.h"
 #include "net/test/gtest_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -137,10 +136,6 @@
   MockJSBindings* bindings() { return &js_bindings_; }
 
  private:
-  // Required by gin::V8Platform::CallOnBackgroundThread(). Can't be a
-  // ScopedTaskScheduler because v8 synchronously waits for tasks to run.
-  base::test::ScopedAsyncTaskScheduler scoped_async_task_scheduler;
-
   MockJSBindings js_bindings_;
   std::unique_ptr<ProxyResolverV8> resolver_;
 };
diff --git a/remoting/client/ios/domain/BUILD.gn b/remoting/client/ios/domain/BUILD.gn
new file mode 100644
index 0000000..7d3dd2f
--- /dev/null
+++ b/remoting/client/ios/domain/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chrome_build.gni")
+import("//build/config/ios/rules.gni")
+import("//remoting/build/config/remoting_build.gni")
+
+source_set("domain") {
+  sources = [
+    "host_info.h",
+    "host_info.mm",
+    "user_info.h",
+    "user_info.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/remoting/client/ios/domain/host_info.h b/remoting/client/ios/domain/host_info.h
new file mode 100644
index 0000000..a897f8b
--- /dev/null
+++ b/remoting/client/ios/domain/host_info.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_CLIENT_IOS_DOMAIN_HOST_INFO_H_
+#define REMOTING_CLIENT_IOS_DOMAIN_HOST_INFO_H_
+
+#import <Foundation/Foundation.h>
+
+// A detail record for a Remoting Host.
+@interface HostInfo : NSObject
+
+// Various properties of the Remoting Host.
+@property(nonatomic, copy) NSString* createdTime;
+@property(nonatomic, copy) NSString* hostId;
+@property(nonatomic, copy) NSString* hostName;
+@property(nonatomic, copy) NSString* hostVersion;
+@property(nonatomic, copy) NSString* jabberId;
+@property(nonatomic, copy) NSString* kind;
+@property(nonatomic, copy) NSString* publicKey;
+@property(nonatomic, copy) NSString* status;
+@property(nonatomic, copy) NSDate* updatedTime;
+// True when |status| is @"ONLINE", anything else is False.
+@property(nonatomic, readonly) bool isOnline;
+
++ (NSMutableArray<HostInfo*>*)parseListFromJSON:(NSMutableData*)data;
+
+// First consider if |isOnline| is greater than anything else, then consider by
+// case insensitive locale of |hostName|.
+- (NSComparisonResult)compare:(HostInfo*)host;
+
+@end
+
+#endif  //  REMOTING_CLIENT_IOS_DOMAIN_HOST_INFO_H_
diff --git a/remoting/client/ios/domain/host_info.mm b/remoting/client/ios/domain/host_info.mm
new file mode 100644
index 0000000..d89478e9
--- /dev/null
+++ b/remoting/client/ios/domain/host_info.mm
@@ -0,0 +1,76 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/client/ios/domain/host_info.h"
+
+@implementation HostInfo
+
+@synthesize createdTime = _createdTime;
+@synthesize hostId = _hostId;
+@synthesize hostName = _hostName;
+@synthesize hostVersion = _hostVersion;
+@synthesize jabberId = _jabberId;
+@synthesize kind = _kind;
+@synthesize publicKey = _publicKey;
+@synthesize status = _status;
+@synthesize updatedTime = _updatedTime;
+@synthesize isOnline = _isOnline;
+
+- (bool)isOnline {
+  _isOnline = (self.status && [self.status isEqualToString:@"ONLINE"]);
+  return _isOnline;
+}
+
+// Parse jsonData into Host list.
++ (NSMutableArray<HostInfo*>*)parseListFromJSON:(NSMutableData*)data {
+  NSError* error;
+
+  NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data
+                                                       options:kNilOptions
+                                                         error:&error];
+  NSDictionary* dataDict = [json objectForKey:@"data"];
+  NSArray* availableHosts = [dataDict objectForKey:@"items"];
+  NSMutableArray* hostList = [[NSMutableArray alloc] init];
+  NSUInteger idx = 0;
+  NSDictionary* svr;
+  NSUInteger count = [availableHosts count];
+
+  while (idx < count) {
+    svr = [availableHosts objectAtIndex:idx++];
+    HostInfo* host = [[HostInfo alloc] init];
+    host.createdTime = [svr objectForKey:@"createdTime"];
+    host.hostId = [svr objectForKey:@"hostId"];
+    host.hostName = [svr objectForKey:@"hostName"];
+    host.hostVersion = [svr objectForKey:@"hostVersion"];
+    host.jabberId = [svr objectForKey:@"jabberId"];
+    host.kind = [svr objectForKey:@"kind"];
+    host.publicKey = [svr objectForKey:@"publicKey"];
+    host.status = [svr objectForKey:@"status"];
+
+    NSString* ISO8601DateString = [svr objectForKey:@"updatedTime"];
+    if (ISO8601DateString != nil) {
+      NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
+      [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSz"];
+      host.updatedTime = [dateFormatter dateFromString:ISO8601DateString];
+    }
+
+    [hostList addObject:host];
+  }
+
+  return hostList;
+}
+
+- (NSComparisonResult)compare:(HostInfo*)host {
+  if (self.isOnline != host.isOnline) {
+    return self.isOnline ? NSOrderedAscending : NSOrderedDescending;
+  } else {
+    return [self.hostName localizedCaseInsensitiveCompare:host.hostName];
+  }
+}
+
+@end
diff --git a/remoting/client/ios/domain/user_info.h b/remoting/client/ios/domain/user_info.h
new file mode 100644
index 0000000..726a3b2
--- /dev/null
+++ b/remoting/client/ios/domain/user_info.h
@@ -0,0 +1,24 @@
+// 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 REMOTING_CLIENT_IOS_DOMAIN_USER_INFO_H_
+#define REMOTING_CLIENT_IOS_DOMAIN_USER_INFO_H_
+
+#import <Foundation/Foundation.h>
+
+// A detail record for a Remoting User.
+// TODO(nicholss): This is not the final object yet.
+@interface UserInfo : NSObject
+
+@property(nonatomic, copy) NSString* userId;
+@property(nonatomic, copy) NSString* userFullName;
+@property(nonatomic, copy) NSString* userEmail;
+
++ (User*)parseListFromJSON:(NSMutableData*)data;
+
+- (NSComparisonResult)compare:(UserInfo*)user;
+
+@end
+
+#endif  //  REMOTING_CLIENT_IOS_DOMAIN_USER_INFO_H_
diff --git a/remoting/client/ios/domain/user_info.mm b/remoting/client/ios/domain/user_info.mm
new file mode 100644
index 0000000..ece9064
--- /dev/null
+++ b/remoting/client/ios/domain/user_info.mm
@@ -0,0 +1,37 @@
+// 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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/client/ios/domain/user_info.h"
+
+@implementation UserInfo
+
+@synthesize userId = _userId;
+@synthesize userFullName = _userFullName;
+@synthesize userEmail = _userEmail;
+
+// Parse jsonData into Host list.
++ (UserInfo*)parseListFromJSON:(NSMutableData*)data {
+  NSError* error;
+
+  NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data
+                                                       options:kNilOptions
+                                                         error:&error];
+
+  UserInfo* user = [[UserInfo alloc] init];
+  user.userId = [json objectForKey:@"userId"];
+  user.userFullName = [json objectForKey:@"userFullName"];
+  user.userEmail = [json objectForKey:@"userEmail"];
+
+  return user;
+}
+
+- (NSComparisonResult)compare:(UserInfo*)user {
+  return [self.userId compare:user.userId];
+}
+
+@end
diff --git a/remoting/client/ios/facade/BUILD.gn b/remoting/client/ios/facade/BUILD.gn
new file mode 100644
index 0000000..c455e09b
--- /dev/null
+++ b/remoting/client/ios/facade/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chrome_build.gni")
+import("//build/config/ios/rules.gni")
+import("//remoting/build/config/remoting_build.gni")
+
+source_set("facade") {
+  sources = [
+    "remoting_service.h",
+    "remoting_service.mm",
+  ]
+
+  deps = [
+    "//base",
+    "//remoting/client/ios/domain",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/remoting/client/ios/facade/remoting_service.h b/remoting/client/ios/facade/remoting_service.h
new file mode 100644
index 0000000..18ca8811
--- /dev/null
+++ b/remoting/client/ios/facade/remoting_service.h
@@ -0,0 +1,22 @@
+// 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 REMOTING_CLIENT_IOS_FACADE_REMOTING_SERCICE_H_
+#define REMOTING_CLIENT_IOS_FACADE_REMOTING_SERCICE_H_
+
+#import "remoting/client/ios/domain/host_info.h"
+#import "remoting/client/ios/domain/user_info.h"
+
+@interface RemotingService : NSObject
+
++ (RemotingService*)sharedInstance;
+
+- (BOOL)isAuthenticated;
+- (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode;
+- (UserInfo*)getUser;
+- (NSArray<HostInfo*>*)getHosts;
+
+@end
+
+#endif  // REMOTING_CLIENT_IOS_FACADE_REMOTING_SERCICE_H_
diff --git a/remoting/client/ios/facade/remoting_service.mm b/remoting/client/ios/facade/remoting_service.mm
new file mode 100644
index 0000000..31ac799
--- /dev/null
+++ b/remoting/client/ios/facade/remoting_service.mm
@@ -0,0 +1,107 @@
+// 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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import <Foundation/Foundation.h>
+
+#import "remoting/client/ios/facade/remoting_service.h"
+
+#include "base/logging.h"
+
+@interface RemotingService ()
+
+@property(nonatomic, copy) NSString* authorizationCode;
+
+@end
+
+//
+// RemodingService will act as the facade to the C++ layer that has not been
+// implemented/integrated yet.
+// TODO(nicholss): Implement/Integrate this class. At the moment it is being
+// used to generate fake data to implement the UI of the app.
+//
+@implementation RemotingService
+
+@synthesize authorizationCode = _authorizationCode;
+
+- (BOOL)isAuthenticated {
+  return self.authorizationCode != nil;
+}
+
+- (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode {
+  self.authorizationCode = authorizationCode;
+}
+
+- (UserInfo*)getUser {
+  if (![self isAuthenticated]) {
+    return nil;
+  }
+
+  NSMutableString* json = [[NSMutableString alloc] init];
+  [json appendString:@"{"];
+  [json appendString:@"\"userId\":\"AABBCC123\","];
+  [json appendString:@"\"userFullName\":\"John Smith\","];
+  [json appendString:@"\"userEmail\":\"john@example.com\","];
+  [json appendString:@"}"];
+
+  NSMutableData* data = [NSMutableData
+      dataWithData:[[json copy] dataUsingEncoding:NSUTF8StringEncoding]];
+
+  UserInfo* user = [UserInfo parseListFromJSON:data];
+  return user;
+}
+
+- (NSArray<HostInfo*>*)getHosts {
+  if (![self isAuthenticated]) {
+    return nil;
+  }
+
+  NSMutableString* json = [[NSMutableString alloc] init];
+  [json
+      appendString:@"{\"data\":{\"kind\":\"chromoting#hostList\",\"items\":["];
+  [json appendString:@"{"];
+  [json appendString:@"\"createdTime\":\"2000-01-01T00:00:01.000Z\","];
+  [json appendString:@"\"hostId\":\"Host1\","];
+  [json appendString:@"\"hostName\":\"HostName1\","];
+  [json appendString:@"\"hostVersion\":\"2.22.5.4\","];
+  [json appendString:@"\"kind\":\"Chromoting#host\","];
+  [json appendString:@"\"jabberId\":\"JabberingOn\","];
+  [json appendString:@"\"publicKey\":\"AAAAABBBBBZZZZZ\","];
+  [json appendString:@"\"status\":\"TESTING\","];
+  [json appendString:@"\"updatedTime\":\"2000-01-01T00:00:01.000Z\""];
+  [json appendString:@"},"];
+  [json appendString:@"{"];
+  [json appendString:@"\"createdTime\":\"2000-01-01T00:00:01.000Z\","];
+  [json appendString:@"\"hostId\":\"Host2\","];
+  [json appendString:@"\"hostName\":\"HostName2\","];
+  [json appendString:@"\"hostVersion\":\"2.22.5.4\","];
+  [json appendString:@"\"kind\":\"Chromoting#host\","];
+  [json appendString:@"\"jabberId\":\"JabberingOn\","];
+  [json appendString:@"\"publicKey\":\"AAAAABBBBBZZZZZ\","];
+  [json appendString:@"\"status\":\"ONLINE\","];
+  [json appendString:@"\"updatedTime\":\"2000-01-01T00:00:01.000Z\""];
+  [json appendString:@"}"];
+  [json appendString:@"]}}"];
+
+  NSMutableData* data = [NSMutableData
+      dataWithData:[[json copy] dataUsingEncoding:NSUTF8StringEncoding]];
+
+  NSMutableArray<HostInfo*>* hosts = [HostInfo parseListFromJSON:data];
+  return hosts;
+}
+
+// RemotingService is a singleton.
++ (RemotingService*)sharedInstance {
+  static RemotingService* sharedInstance = nil;
+  static dispatch_once_t guard;
+  dispatch_once(&guard, ^{
+    sharedInstance = [[RemotingService alloc] init];
+  });
+  return sharedInstance;
+}
+
+@end
diff --git a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
index f79fa92..83840779 100644
--- a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
+++ b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
@@ -46,17 +46,19 @@
   BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
 }
 
-#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD) && defined(NDEBUG)
-#define DEATH_BY_SIGILL(msg) DEATH_BY_SIGNAL(SIGILL)
+// In official builds, CHECK(x) causes a SIGTRAP on the architectures where the
+// sanbox is enabled (that are x86, x86_64, arm64 and 32-bit arm processes
+// running on a arm64 kernel).
+#if defined(OFFICIAL_BUILD)
+#define DEATH_BY_CHECK(msg) DEATH_BY_SIGNAL(SIGTRAP)
 #else
-#define DEATH_BY_SIGILL(msg) DEATH_MESSAGE(msg)
+#define DEATH_BY_CHECK(msg) DEATH_MESSAGE(msg)
 #endif
 
 SANDBOX_DEATH_TEST(
     BrokerFilePermission,
     CreateBad,
-    DEATH_BY_SIGILL(BrokerFilePermissionTester::GetErrorMessage())
-) {
+    DEATH_BY_CHECK(BrokerFilePermissionTester::GetErrorMessage())) {
   const char kPath[] = "/tmp/bad/";
   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
 }
@@ -64,8 +66,7 @@
 SANDBOX_DEATH_TEST(
     BrokerFilePermission,
     CreateBadRecursive,
-    DEATH_BY_SIGILL(BrokerFilePermissionTester::GetErrorMessage())
-) {
+    DEATH_BY_CHECK(BrokerFilePermissionTester::GetErrorMessage())) {
   const char kPath[] = "/tmp/bad";
   BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
 }
@@ -73,8 +74,7 @@
 SANDBOX_DEATH_TEST(
     BrokerFilePermission,
     CreateBadNotAbs,
-    DEATH_BY_SIGILL(BrokerFilePermissionTester::GetErrorMessage())
-) {
+    DEATH_BY_CHECK(BrokerFilePermissionTester::GetErrorMessage())) {
   const char kPath[] = "tmp/bad";
   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
 }
@@ -82,8 +82,7 @@
 SANDBOX_DEATH_TEST(
     BrokerFilePermission,
     CreateBadEmpty,
-    DEATH_BY_SIGILL(BrokerFilePermissionTester::GetErrorMessage())
-) {
+    DEATH_BY_CHECK(BrokerFilePermissionTester::GetErrorMessage())) {
   const char kPath[] = "";
   BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
 }
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc
index 660053b5..efe2896 100644
--- a/sandbox/linux/tests/unit_tests.cc
+++ b/sandbox/linux/tests/unit_tests.cc
@@ -288,14 +288,14 @@
   bool subprocess_exited_without_matching_message =
       msg.find(expected_msg) == std::string::npos;
 
-// In official builds CHECK messages are dropped, so look for SIGABRT or SIGILL.
+// In official builds CHECK messages are dropped, look for SIGABRT or SIGTRAP.
 // See https://crbug.com/437312 and https://crbug.com/612507.
 #if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
   if (subprocess_exited_without_matching_message) {
-    static const char kSigIllegalMessage[] = "Received signal 4";
+    static const char kSigTrapMessage[] = "Received signal 5";
     static const char kSigAbortMessage[] = "Received signal 6";
     subprocess_exited_without_matching_message =
-        msg.find(kSigIllegalMessage) == std::string::npos &&
+        msg.find(kSigTrapMessage) == std::string::npos &&
         msg.find(kSigAbortMessage) == std::string::npos;
   }
 #endif
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index d170784..21deea9 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -50,6 +50,7 @@
       mouse_cursor_in_non_client_area_(false) {}
 
 EventDispatcher::~EventDispatcher() {
+  SetMouseCursorSourceWindow(nullptr);
   if (capture_window_) {
     UnobserveWindow(capture_window_);
     capture_window_ = nullptr;
@@ -231,13 +232,12 @@
   if (!mouse_button_down_) {
     DeepestWindow deepest_window =
         FindDeepestVisibleWindowForEvents(mouse_pointer_last_location_);
-    mouse_cursor_source_window_ = deepest_window.window;
+    SetMouseCursorSourceWindow(deepest_window.window);
     if (mouse_cursor_source_window_) {
       mouse_cursor_in_non_client_area_ = deepest_window.in_non_client_area;
     } else {
       gfx::Point location = mouse_pointer_last_location_;
-      mouse_cursor_source_window_ =
-          delegate_->GetRootWindowContaining(&location);
+      SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(&location));
       mouse_cursor_in_non_client_area_ = true;
     }
   }
@@ -308,6 +308,17 @@
   return;
 }
 
+void EventDispatcher::SetMouseCursorSourceWindow(ServerWindow* window) {
+  if (mouse_cursor_source_window_ == window)
+    return;
+
+  if (mouse_cursor_source_window_)
+    UnobserveWindow(mouse_cursor_source_window_);
+  mouse_cursor_source_window_ = window;
+  if (mouse_cursor_source_window_)
+    ObserveWindow(mouse_cursor_source_window_);
+}
+
 void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event,
                                       AcceleratorMatchPhase match_phase) {
   Accelerator* post_target =
@@ -365,7 +376,7 @@
   }
 
   if (capture_window_) {
-    mouse_cursor_source_window_ = capture_window_;
+    SetMouseCursorSourceWindow(capture_window_);
     DispatchToClient(capture_window_, capture_window_client_id_, event);
     return;
   }
@@ -376,12 +387,12 @@
     const bool any_pointers_down = AreAnyPointersDown();
     UpdateTargetForPointer(pointer_id, event);
     if (is_mouse_event)
-      mouse_cursor_source_window_ = pointer_targets_[pointer_id].window;
+      SetMouseCursorSourceWindow(pointer_targets_[pointer_id].window);
 
     PointerTarget& pointer_target = pointer_targets_[pointer_id];
     if (pointer_target.is_pointer_down) {
       if (is_mouse_event)
-        mouse_cursor_source_window_ = pointer_target.window;
+        SetMouseCursorSourceWindow(pointer_target.window);
       if (!any_pointers_down) {
         if (pointer_target.window)
           delegate_->SetFocusedWindowFromEventDispatcher(pointer_target.window);
@@ -640,7 +651,7 @@
   CancelPointerEventsToTarget(window);
 
   if (mouse_cursor_source_window_ == window)
-    mouse_cursor_source_window_ = nullptr;
+    SetMouseCursorSourceWindow(nullptr);
 }
 
 void EventDispatcher::OnDragCursorUpdated() {
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
index 7e1341e2..02e6fcb 100644
--- a/services/ui/ws/event_dispatcher.h
+++ b/services/ui/ws/event_dispatcher.h
@@ -168,6 +168,8 @@
     bool is_pointer_down;
   };
 
+  void SetMouseCursorSourceWindow(ServerWindow* window);
+
   void ProcessKeyEvent(const ui::KeyEvent& event,
                        AcceleratorMatchPhase match_phase);
 
diff --git a/services/ui/ws/event_dispatcher_unittest.cc b/services/ui/ws/event_dispatcher_unittest.cc
index 6c712cc..d78af7d 100644
--- a/services/ui/ws/event_dispatcher_unittest.cc
+++ b/services/ui/ws/event_dispatcher_unittest.cc
@@ -1801,6 +1801,20 @@
   EXPECT_FALSE(test_event_dispatcher_delegate()->has_queued_events());
 }
 
+TEST_F(EventDispatcherTest, MousePointerClearedOnDestroy) {
+  root_window()->set_event_targeting_policy(
+      mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
+  std::unique_ptr<ServerWindow> c1 = CreateChildWindow(WindowId(1, 3));
+
+  root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
+  c1->SetBounds(gfx::Rect(10, 10, 20, 20));
+
+  event_dispatcher()->SetMousePointerScreenLocation(gfx::Point(15, 15));
+  EXPECT_EQ(c1.get(), event_dispatcher()->mouse_cursor_source_window());
+  c1.reset();
+  EXPECT_EQ(nullptr, event_dispatcher()->mouse_cursor_source_window());
+}
+
 }  // namespace test
 }  // namespace ws
 }  // namespace ui
diff --git a/storage/browser/blob/README.md b/storage/browser/blob/README.md
index 0cbd9b49..73ef187d 100644
--- a/storage/browser/blob/README.md
+++ b/storage/browser/blob/README.md
@@ -81,16 +81,16 @@
 
 **In-Memory Storage Limit**
 
-* If the architecture is x64 and NOT ChromeOS or Android: `2GB`
+* If the architecture is x64 and NOT Chrome OS or Android: `2GB`
 * Otherwise: `total_physical_memory / 5`
 
 **Disk Storage Limit**
 
-* If ChromeOS: `disk_size / 2`
+* If Chrome OS: `disk_size / 2`
 * If Android: `disk_size / 20`
 * Else: `disk_size / 10`
 
-Note: ChromeOS's disk is part of the user partition, which is separate from the
+Note: Chrome OS's disk is part of the user partition, which is separate from the
 system partition.
 
 **Minimum Disk Availability**
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 9e0bc4f..65861a4 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -23,12 +23,6 @@
 crbug.com/555418 virtual/mojo-loading/http/tests/security/contentSecurityPolicy/redirect-does-not-match-paths.html [ Timeout ]
 crbug.com/555418 virtual/mojo-loading/http/tests/security/isolatedWorld/bypass-main-world-csp-iframes.html [ Failure ]
 
-# https://crbug.com/638900: Failing due to flipped order of callbacks to
-# WebFrameClient::didStartProvisionalLoad() and
-# WebFrameClient::didFinishDocumentLoad().
-crbug.com/638900 http/tests/loading/doc-write-sync-third-party-script-reload.html [ Failure ]
-crbug.com/638900 virtual/mojo-loading/http/tests/loading/doc-write-sync-third-party-script-reload.html [ Failure ]
-
 # Issue with ServiceWorker timing.
 Bug(none) external/wpt/service-workers/service-worker/navigate-window.https.html [ Failure ]
 
@@ -38,9 +32,10 @@
 # Missing error messages.
 Bug(none) external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure ]
 
-# Missing console error line number.
-Bug(none) http/tests/security/location-href-clears-username-password.html [ Failure ]
-Bug(none) virtual/mojo-loading/http/tests/security/location-href-clears-username-password.html [ Failure ]
+# https://crbug.com/695072: Preserve SourceLocation information.
+# This results in a missing line number in console error messages.
+Bug(695072) http/tests/security/location-href-clears-username-password.html [ Failure ]
+Bug(695072) virtual/mojo-loading/http/tests/security/location-href-clears-username-password.html [ Failure ]
 
 # Timeout
 Bug(none) fast/loader/crash-replacing-location-before-load.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 011ef7b4..822cf3a 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2546,6 +2546,3 @@
 crbug.com/73609 http/tests/media/video-play-stall.html [ Pass Timeout ]
 crbug.com/73609 virtual/mojo-loading/http/tests/media/video-play-stall.html [ Pass Timeout ]
 crbug.com/694467 fast/text/line-break-8bit-after-16bit.html [ Pass Failure ]
-
-Bug(jochen) http/tests/webfont/popup-menu-load-webfont-after-open.html [ NeedsRebaseline ]
-Bug(jochen) virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open.html [ NeedsRebaseline ]
diff --git a/third_party/WebKit/LayoutTests/editing/undo/paste_with_mutation_event_undo_order.html b/third_party/WebKit/LayoutTests/editing/undo/paste_with_mutation_event_undo_order.html
new file mode 100644
index 0000000..79a61e65
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/undo/paste_with_mutation_event_undo_order.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
+<script>
+// Regression test for crbug.com/685975
+
+test(() => {
+  assert_not_equals(window.testRunner, undefined,
+                    'This test requires testRunner');
+
+  assert_selection(
+    [
+      '<div contenteditable id="div1">|</div>',
+      '<div contenteditable id="div2">bar</div>'
+    ].join(''),
+    selection => {
+      const document = selection.document;
+      const source = document.getElementById('source');
+      const div1 = document.getElementById('div1');
+      const div2 = document.getElementById('div2');
+      div1.addEventListener('DOMNodeInserted', () => {
+        div2.focus();
+        document.execCommand('selectAll');
+        document.execCommand('delete');
+      });
+
+      selection.setClipboardData('foo');
+      testRunner.execCommand('paste'); // Must be user-initiated paste.
+      document.execCommand('undo');
+    },
+    [
+      '<div contenteditable id="div1">foo</div>',
+      '<div contenteditable id="div2">^bar|</div>'
+    ].join(''));
+}, 'Undo ordering maintained when pasting triggers another command with mutation event.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual-expected.txt
deleted file mode 100644
index 5bc31b4..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual-expected.txt
+++ /dev/null
@@ -1,448 +0,0 @@
-This is a testharness.js-based test.
-Found 444 tests; 442 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS touch pointerevent attributes 
-PASS PointerEvent Automation 
-PASS  touch pointerover's type should be pointerover 
-PASS  touch pointerover's button attribute is 0 when left mouse button is pressed. 
-PASS  touch pointerover's buttons attribute is 1 when left mouse button is pressed. 
-PASS  touch pointerover's ClientX and ClientY attributes are correct. 
-PASS  touch pointerover event pointerType is correct. 
-PASS  touch pointerover event is a PointerEvent event 
-PASS  touch pointerover.pointerId attribute exists 
-PASS  touch pointerover.pointerId is readonly 
-PASS  touch pointerover.pointerId IDL type long (JS type was number) 
-PASS  touch pointerover.width attribute exists 
-PASS  touch pointerover.width is readonly 
-PASS  touch pointerover.width IDL type float (JS type was number) 
-PASS  touch pointerover.height attribute exists 
-PASS  touch pointerover.height is readonly 
-PASS  touch pointerover.height IDL type float (JS type was number) 
-PASS  touch pointerover.pressure attribute exists 
-PASS  touch pointerover.pressure is readonly 
-PASS  touch pointerover.pressure IDL type float (JS type was number) 
-PASS  touch pointerover.tiltX attribute exists 
-PASS  touch pointerover.tiltX is readonly 
-PASS  touch pointerover.tiltX IDL type long (JS type was number) 
-PASS  touch pointerover.tiltY attribute exists 
-PASS  touch pointerover.tiltY is readonly 
-PASS  touch pointerover.tiltY IDL type long (JS type was number) 
-PASS  touch pointerover.pointerType attribute exists 
-PASS  touch pointerover.pointerType is readonly 
-PASS  touch pointerover.pointerType IDL type string (JS type was string) 
-PASS  touch pointerover.isPrimary attribute exists 
-PASS  touch pointerover.isPrimary is readonly 
-PASS  touch pointerover.isPrimary IDL type boolean (JS type was boolean) 
-PASS  touch pointerover.detail attribute exists 
-PASS  touch pointerover.detail is readonly 
-PASS  touch pointerover.detail IDL type long (JS type was number) 
-PASS  touch pointerover.detail value is 0. 
-PASS  touch pointerover.pressure value is valid 
-PASS  touch pointerover.isPrimary attribute is correct. 
-PASS  touch pointerenter's type should be pointerenter 
-PASS  touch pointerenter's button attribute is 0 when left mouse button is pressed. 
-PASS  touch pointerenter's buttons attribute is 1 when left mouse button is pressed. 
-PASS  touch pointerenter's ClientX and ClientY attributes are correct. 
-PASS  touch pointerenter event pointerType is correct. 
-PASS  touch pointerenter event is a PointerEvent event 
-PASS  touch pointerenter.pointerId attribute exists 
-PASS  touch pointerenter.pointerId is readonly 
-PASS  touch pointerenter.pointerId IDL type long (JS type was number) 
-PASS  touch pointerenter.width attribute exists 
-PASS  touch pointerenter.width is readonly 
-PASS  touch pointerenter.width IDL type float (JS type was number) 
-PASS  touch pointerenter.height attribute exists 
-PASS  touch pointerenter.height is readonly 
-PASS  touch pointerenter.height IDL type float (JS type was number) 
-PASS  touch pointerenter.pressure attribute exists 
-PASS  touch pointerenter.pressure is readonly 
-PASS  touch pointerenter.pressure IDL type float (JS type was number) 
-PASS  touch pointerenter.tiltX attribute exists 
-PASS  touch pointerenter.tiltX is readonly 
-PASS  touch pointerenter.tiltX IDL type long (JS type was number) 
-PASS  touch pointerenter.tiltY attribute exists 
-PASS  touch pointerenter.tiltY is readonly 
-PASS  touch pointerenter.tiltY IDL type long (JS type was number) 
-PASS  touch pointerenter.pointerType attribute exists 
-PASS  touch pointerenter.pointerType is readonly 
-PASS  touch pointerenter.pointerType IDL type string (JS type was string) 
-PASS  touch pointerenter.isPrimary attribute exists 
-PASS  touch pointerenter.isPrimary is readonly 
-PASS  touch pointerenter.isPrimary IDL type boolean (JS type was boolean) 
-PASS  touch pointerenter.detail attribute exists 
-PASS  touch pointerenter.detail is readonly 
-PASS  touch pointerenter.detail IDL type long (JS type was number) 
-PASS  touch pointerenter.detail value is 0. 
-PASS  touch pointerenter.pressure value is valid 
-PASS  touch pointerenter.isPrimary attribute is correct. 
-PASS  touch pointerenter.pointerId should be the same as previous pointer events for this active pointer. 
-PASS  touch pointerdown's type should be pointerdown 
-PASS  touch pointerdown's button attribute is 0 when left mouse button is pressed. 
-PASS  touch pointerdown's buttons attribute is 1 when left mouse button is pressed. 
-PASS  touch pointerdown's ClientX and ClientY attributes are correct. 
-PASS  touch pointerdown event pointerType is correct. 
-PASS  touch pointerdown event is a PointerEvent event 
-PASS  touch pointerdown.pointerId attribute exists 
-PASS  touch pointerdown.pointerId is readonly 
-PASS  touch pointerdown.pointerId IDL type long (JS type was number) 
-PASS  touch pointerdown.width attribute exists 
-PASS  touch pointerdown.width is readonly 
-PASS  touch pointerdown.width IDL type float (JS type was number) 
-PASS  touch pointerdown.height attribute exists 
-PASS  touch pointerdown.height is readonly 
-PASS  touch pointerdown.height IDL type float (JS type was number) 
-PASS  touch pointerdown.pressure attribute exists 
-PASS  touch pointerdown.pressure is readonly 
-PASS  touch pointerdown.pressure IDL type float (JS type was number) 
-PASS  touch pointerdown.tiltX attribute exists 
-PASS  touch pointerdown.tiltX is readonly 
-PASS  touch pointerdown.tiltX IDL type long (JS type was number) 
-PASS  touch pointerdown.tiltY attribute exists 
-PASS  touch pointerdown.tiltY is readonly 
-PASS  touch pointerdown.tiltY IDL type long (JS type was number) 
-PASS  touch pointerdown.pointerType attribute exists 
-PASS  touch pointerdown.pointerType is readonly 
-PASS  touch pointerdown.pointerType IDL type string (JS type was string) 
-PASS  touch pointerdown.isPrimary attribute exists 
-PASS  touch pointerdown.isPrimary is readonly 
-PASS  touch pointerdown.isPrimary IDL type boolean (JS type was boolean) 
-PASS  touch pointerdown.detail attribute exists 
-PASS  touch pointerdown.detail is readonly 
-PASS  touch pointerdown.detail IDL type long (JS type was number) 
-PASS  touch pointerdown.detail value is 0. 
-PASS  touch pointerdown.pressure value is valid 
-PASS  touch pointerdown.isPrimary attribute is correct. 
-PASS  touch pointerdown.pointerId should be the same as previous pointer events for this active pointer. 
-PASS  touch pointerup's type should be pointerup 
-PASS  touch pointerup's button attribute is 0 when left mouse button is pressed. 
-PASS  touch pointerup's buttons is 0 when mouse buttons are in released state. 
-PASS  touch pointerup's ClientX and ClientY attributes are correct. 
-PASS  touch pointerup event pointerType is correct. 
-PASS  touch pointerup event is a PointerEvent event 
-PASS  touch pointerup.pointerId attribute exists 
-PASS  touch pointerup.pointerId is readonly 
-PASS  touch pointerup.pointerId IDL type long (JS type was number) 
-PASS  touch pointerup.width attribute exists 
-PASS  touch pointerup.width is readonly 
-PASS  touch pointerup.width IDL type float (JS type was number) 
-PASS  touch pointerup.height attribute exists 
-PASS  touch pointerup.height is readonly 
-PASS  touch pointerup.height IDL type float (JS type was number) 
-PASS  touch pointerup.pressure attribute exists 
-PASS  touch pointerup.pressure is readonly 
-PASS  touch pointerup.pressure IDL type float (JS type was number) 
-PASS  touch pointerup.tiltX attribute exists 
-PASS  touch pointerup.tiltX is readonly 
-PASS  touch pointerup.tiltX IDL type long (JS type was number) 
-PASS  touch pointerup.tiltY attribute exists 
-PASS  touch pointerup.tiltY is readonly 
-PASS  touch pointerup.tiltY IDL type long (JS type was number) 
-PASS  touch pointerup.pointerType attribute exists 
-PASS  touch pointerup.pointerType is readonly 
-PASS  touch pointerup.pointerType IDL type string (JS type was string) 
-PASS  touch pointerup.isPrimary attribute exists 
-PASS  touch pointerup.isPrimary is readonly 
-PASS  touch pointerup.isPrimary IDL type boolean (JS type was boolean) 
-PASS  touch pointerup.detail attribute exists 
-PASS  touch pointerup.detail is readonly 
-PASS  touch pointerup.detail IDL type long (JS type was number) 
-PASS  touch pointerup.detail value is 0. 
-FAIL  touch pointerup.pressure value is valid assert_equals: pressure is 0 during pointerup expected 0 but got 1
-PASS  touch pointerup.isPrimary attribute is correct. 
-PASS  touch pointerup.pointerId should be the same as previous pointer events for this active pointer. 
-PASS  touch pointerout's type should be pointerout 
-PASS  touch pointerout's button attribute is 0 when left mouse button is pressed. 
-PASS  touch pointerout's buttons is 0 when mouse buttons are in released state. 
-PASS  touch pointerout's ClientX and ClientY attributes are correct. 
-PASS  touch pointerout event pointerType is correct. 
-PASS  touch pointerout event is a PointerEvent event 
-PASS  touch pointerout.pointerId attribute exists 
-PASS  touch pointerout.pointerId is readonly 
-PASS  touch pointerout.pointerId IDL type long (JS type was number) 
-PASS  touch pointerout.width attribute exists 
-PASS  touch pointerout.width is readonly 
-PASS  touch pointerout.width IDL type float (JS type was number) 
-PASS  touch pointerout.height attribute exists 
-PASS  touch pointerout.height is readonly 
-PASS  touch pointerout.height IDL type float (JS type was number) 
-PASS  touch pointerout.pressure attribute exists 
-PASS  touch pointerout.pressure is readonly 
-PASS  touch pointerout.pressure IDL type float (JS type was number) 
-PASS  touch pointerout.tiltX attribute exists 
-PASS  touch pointerout.tiltX is readonly 
-PASS  touch pointerout.tiltX IDL type long (JS type was number) 
-PASS  touch pointerout.tiltY attribute exists 
-PASS  touch pointerout.tiltY is readonly 
-PASS  touch pointerout.tiltY IDL type long (JS type was number) 
-PASS  touch pointerout.pointerType attribute exists 
-PASS  touch pointerout.pointerType is readonly 
-PASS  touch pointerout.pointerType IDL type string (JS type was string) 
-PASS  touch pointerout.isPrimary attribute exists 
-PASS  touch pointerout.isPrimary is readonly 
-PASS  touch pointerout.isPrimary IDL type boolean (JS type was boolean) 
-PASS  touch pointerout.detail attribute exists 
-PASS  touch pointerout.detail is readonly 
-PASS  touch pointerout.detail IDL type long (JS type was number) 
-PASS  touch pointerout.detail value is 0. 
-PASS  touch pointerout.pressure value is valid 
-PASS  touch pointerout.isPrimary attribute is correct. 
-PASS  touch pointerout.pointerId should be the same as previous pointer events for this active pointer. 
-PASS  touch pointerleave's type should be pointerleave 
-PASS  touch pointerleave's button attribute is 0 when left mouse button is pressed. 
-PASS  touch pointerleave's buttons is 0 when mouse buttons are in released state. 
-PASS  touch pointerleave's ClientX and ClientY attributes are correct. 
-PASS  touch pointerleave event pointerType is correct. 
-PASS  touch pointerleave event is a PointerEvent event 
-PASS  touch pointerleave.pointerId attribute exists 
-PASS  touch pointerleave.pointerId is readonly 
-PASS  touch pointerleave.pointerId IDL type long (JS type was number) 
-PASS  touch pointerleave.width attribute exists 
-PASS  touch pointerleave.width is readonly 
-PASS  touch pointerleave.width IDL type float (JS type was number) 
-PASS  touch pointerleave.height attribute exists 
-PASS  touch pointerleave.height is readonly 
-PASS  touch pointerleave.height IDL type float (JS type was number) 
-PASS  touch pointerleave.pressure attribute exists 
-PASS  touch pointerleave.pressure is readonly 
-PASS  touch pointerleave.pressure IDL type float (JS type was number) 
-PASS  touch pointerleave.tiltX attribute exists 
-PASS  touch pointerleave.tiltX is readonly 
-PASS  touch pointerleave.tiltX IDL type long (JS type was number) 
-PASS  touch pointerleave.tiltY attribute exists 
-PASS  touch pointerleave.tiltY is readonly 
-PASS  touch pointerleave.tiltY IDL type long (JS type was number) 
-PASS  touch pointerleave.pointerType attribute exists 
-PASS  touch pointerleave.pointerType is readonly 
-PASS  touch pointerleave.pointerType IDL type string (JS type was string) 
-PASS  touch pointerleave.isPrimary attribute exists 
-PASS  touch pointerleave.isPrimary is readonly 
-PASS  touch pointerleave.isPrimary IDL type boolean (JS type was boolean) 
-PASS  touch pointerleave.detail attribute exists 
-PASS  touch pointerleave.detail is readonly 
-PASS  touch pointerleave.detail IDL type long (JS type was number) 
-PASS  touch pointerleave.detail value is 0. 
-PASS  touch pointerleave.pressure value is valid 
-PASS  touch pointerleave.isPrimary attribute is correct. 
-PASS  touch pointerleave.pointerId should be the same as previous pointer events for this active pointer. 
-PASS Inner frame  touch pointerover's type should be pointerover 
-PASS Inner frame  touch pointerover's button attribute is 0 when left mouse button is pressed. 
-PASS Inner frame  touch pointerover's buttons attribute is 1 when left mouse button is pressed. 
-PASS Inner frame  touch pointerover's ClientX and ClientY attributes are correct. 
-PASS Inner frame  touch pointerover event pointerType is correct. 
-PASS Inner frame  touch pointerover event is a PointerEvent event 
-PASS Inner frame  touch pointerover.pointerId attribute exists 
-PASS Inner frame  touch pointerover.pointerId is readonly 
-PASS Inner frame  touch pointerover.pointerId IDL type long (JS type was number) 
-PASS Inner frame  touch pointerover.width attribute exists 
-PASS Inner frame  touch pointerover.width is readonly 
-PASS Inner frame  touch pointerover.width IDL type float (JS type was number) 
-PASS Inner frame  touch pointerover.height attribute exists 
-PASS Inner frame  touch pointerover.height is readonly 
-PASS Inner frame  touch pointerover.height IDL type float (JS type was number) 
-PASS Inner frame  touch pointerover.pressure attribute exists 
-PASS Inner frame  touch pointerover.pressure is readonly 
-PASS Inner frame  touch pointerover.pressure IDL type float (JS type was number) 
-PASS Inner frame  touch pointerover.tiltX attribute exists 
-PASS Inner frame  touch pointerover.tiltX is readonly 
-PASS Inner frame  touch pointerover.tiltX IDL type long (JS type was number) 
-PASS Inner frame  touch pointerover.tiltY attribute exists 
-PASS Inner frame  touch pointerover.tiltY is readonly 
-PASS Inner frame  touch pointerover.tiltY IDL type long (JS type was number) 
-PASS Inner frame  touch pointerover.pointerType attribute exists 
-PASS Inner frame  touch pointerover.pointerType is readonly 
-PASS Inner frame  touch pointerover.pointerType IDL type string (JS type was string) 
-PASS Inner frame  touch pointerover.isPrimary attribute exists 
-PASS Inner frame  touch pointerover.isPrimary is readonly 
-PASS Inner frame  touch pointerover.isPrimary IDL type boolean (JS type was boolean) 
-PASS Inner frame  touch pointerover.detail attribute exists 
-PASS Inner frame  touch pointerover.detail is readonly 
-PASS Inner frame  touch pointerover.detail IDL type long (JS type was number) 
-PASS Inner frame  touch pointerover.detail value is 0. 
-PASS Inner frame  touch pointerover.pressure value is valid 
-PASS Inner frame  touch pointerover.isPrimary attribute is correct. 
-PASS Inner frame  touch pointerenter's type should be pointerenter 
-PASS Inner frame  touch pointerenter's button attribute is 0 when left mouse button is pressed. 
-PASS Inner frame  touch pointerenter's buttons attribute is 1 when left mouse button is pressed. 
-PASS Inner frame  touch pointerenter's ClientX and ClientY attributes are correct. 
-PASS Inner frame  touch pointerenter event pointerType is correct. 
-PASS Inner frame  touch pointerenter event is a PointerEvent event 
-PASS Inner frame  touch pointerenter.pointerId attribute exists 
-PASS Inner frame  touch pointerenter.pointerId is readonly 
-PASS Inner frame  touch pointerenter.pointerId IDL type long (JS type was number) 
-PASS Inner frame  touch pointerenter.width attribute exists 
-PASS Inner frame  touch pointerenter.width is readonly 
-PASS Inner frame  touch pointerenter.width IDL type float (JS type was number) 
-PASS Inner frame  touch pointerenter.height attribute exists 
-PASS Inner frame  touch pointerenter.height is readonly 
-PASS Inner frame  touch pointerenter.height IDL type float (JS type was number) 
-PASS Inner frame  touch pointerenter.pressure attribute exists 
-PASS Inner frame  touch pointerenter.pressure is readonly 
-PASS Inner frame  touch pointerenter.pressure IDL type float (JS type was number) 
-PASS Inner frame  touch pointerenter.tiltX attribute exists 
-PASS Inner frame  touch pointerenter.tiltX is readonly 
-PASS Inner frame  touch pointerenter.tiltX IDL type long (JS type was number) 
-PASS Inner frame  touch pointerenter.tiltY attribute exists 
-PASS Inner frame  touch pointerenter.tiltY is readonly 
-PASS Inner frame  touch pointerenter.tiltY IDL type long (JS type was number) 
-PASS Inner frame  touch pointerenter.pointerType attribute exists 
-PASS Inner frame  touch pointerenter.pointerType is readonly 
-PASS Inner frame  touch pointerenter.pointerType IDL type string (JS type was string) 
-PASS Inner frame  touch pointerenter.isPrimary attribute exists 
-PASS Inner frame  touch pointerenter.isPrimary is readonly 
-PASS Inner frame  touch pointerenter.isPrimary IDL type boolean (JS type was boolean) 
-PASS Inner frame  touch pointerenter.detail attribute exists 
-PASS Inner frame  touch pointerenter.detail is readonly 
-PASS Inner frame  touch pointerenter.detail IDL type long (JS type was number) 
-PASS Inner frame  touch pointerenter.detail value is 0. 
-PASS Inner frame  touch pointerenter.pressure value is valid 
-PASS Inner frame  touch pointerenter.isPrimary attribute is correct. 
-PASS Inner frame  touch pointerenter.pointerId should be the same as previous pointer events for this active pointer. 
-PASS Inner frame  touch pointerdown's type should be pointerdown 
-PASS Inner frame  touch pointerdown's button attribute is 0 when left mouse button is pressed. 
-PASS Inner frame  touch pointerdown's buttons attribute is 1 when left mouse button is pressed. 
-PASS Inner frame  touch pointerdown's ClientX and ClientY attributes are correct. 
-PASS Inner frame  touch pointerdown event pointerType is correct. 
-PASS Inner frame  touch pointerdown event is a PointerEvent event 
-PASS Inner frame  touch pointerdown.pointerId attribute exists 
-PASS Inner frame  touch pointerdown.pointerId is readonly 
-PASS Inner frame  touch pointerdown.pointerId IDL type long (JS type was number) 
-PASS Inner frame  touch pointerdown.width attribute exists 
-PASS Inner frame  touch pointerdown.width is readonly 
-PASS Inner frame  touch pointerdown.width IDL type float (JS type was number) 
-PASS Inner frame  touch pointerdown.height attribute exists 
-PASS Inner frame  touch pointerdown.height is readonly 
-PASS Inner frame  touch pointerdown.height IDL type float (JS type was number) 
-PASS Inner frame  touch pointerdown.pressure attribute exists 
-PASS Inner frame  touch pointerdown.pressure is readonly 
-PASS Inner frame  touch pointerdown.pressure IDL type float (JS type was number) 
-PASS Inner frame  touch pointerdown.tiltX attribute exists 
-PASS Inner frame  touch pointerdown.tiltX is readonly 
-PASS Inner frame  touch pointerdown.tiltX IDL type long (JS type was number) 
-PASS Inner frame  touch pointerdown.tiltY attribute exists 
-PASS Inner frame  touch pointerdown.tiltY is readonly 
-PASS Inner frame  touch pointerdown.tiltY IDL type long (JS type was number) 
-PASS Inner frame  touch pointerdown.pointerType attribute exists 
-PASS Inner frame  touch pointerdown.pointerType is readonly 
-PASS Inner frame  touch pointerdown.pointerType IDL type string (JS type was string) 
-PASS Inner frame  touch pointerdown.isPrimary attribute exists 
-PASS Inner frame  touch pointerdown.isPrimary is readonly 
-PASS Inner frame  touch pointerdown.isPrimary IDL type boolean (JS type was boolean) 
-PASS Inner frame  touch pointerdown.detail attribute exists 
-PASS Inner frame  touch pointerdown.detail is readonly 
-PASS Inner frame  touch pointerdown.detail IDL type long (JS type was number) 
-PASS Inner frame  touch pointerdown.detail value is 0. 
-PASS Inner frame  touch pointerdown.pressure value is valid 
-PASS Inner frame  touch pointerdown.isPrimary attribute is correct. 
-PASS Inner frame  touch pointerdown.pointerId should be the same as previous pointer events for this active pointer. 
-PASS Inner frame  touch pointerup's type should be pointerup 
-PASS Inner frame  touch pointerup's button attribute is 0 when left mouse button is pressed. 
-PASS Inner frame  touch pointerup's buttons is 0 when mouse buttons are in released state. 
-PASS Inner frame  touch pointerup's ClientX and ClientY attributes are correct. 
-PASS Inner frame  touch pointerup event pointerType is correct. 
-PASS Inner frame  touch pointerup event is a PointerEvent event 
-PASS Inner frame  touch pointerup.pointerId attribute exists 
-PASS Inner frame  touch pointerup.pointerId is readonly 
-PASS Inner frame  touch pointerup.pointerId IDL type long (JS type was number) 
-PASS Inner frame  touch pointerup.width attribute exists 
-PASS Inner frame  touch pointerup.width is readonly 
-PASS Inner frame  touch pointerup.width IDL type float (JS type was number) 
-PASS Inner frame  touch pointerup.height attribute exists 
-PASS Inner frame  touch pointerup.height is readonly 
-PASS Inner frame  touch pointerup.height IDL type float (JS type was number) 
-PASS Inner frame  touch pointerup.pressure attribute exists 
-PASS Inner frame  touch pointerup.pressure is readonly 
-PASS Inner frame  touch pointerup.pressure IDL type float (JS type was number) 
-PASS Inner frame  touch pointerup.tiltX attribute exists 
-PASS Inner frame  touch pointerup.tiltX is readonly 
-PASS Inner frame  touch pointerup.tiltX IDL type long (JS type was number) 
-PASS Inner frame  touch pointerup.tiltY attribute exists 
-PASS Inner frame  touch pointerup.tiltY is readonly 
-PASS Inner frame  touch pointerup.tiltY IDL type long (JS type was number) 
-PASS Inner frame  touch pointerup.pointerType attribute exists 
-PASS Inner frame  touch pointerup.pointerType is readonly 
-PASS Inner frame  touch pointerup.pointerType IDL type string (JS type was string) 
-PASS Inner frame  touch pointerup.isPrimary attribute exists 
-PASS Inner frame  touch pointerup.isPrimary is readonly 
-PASS Inner frame  touch pointerup.isPrimary IDL type boolean (JS type was boolean) 
-PASS Inner frame  touch pointerup.detail attribute exists 
-PASS Inner frame  touch pointerup.detail is readonly 
-PASS Inner frame  touch pointerup.detail IDL type long (JS type was number) 
-PASS Inner frame  touch pointerup.detail value is 0. 
-FAIL Inner frame  touch pointerup.pressure value is valid assert_equals: pressure is 0 during pointerup expected 0 but got 1
-PASS Inner frame  touch pointerup.isPrimary attribute is correct. 
-PASS Inner frame  touch pointerup.pointerId should be the same as previous pointer events for this active pointer. 
-PASS Inner frame  touch pointerout's type should be pointerout 
-PASS Inner frame  touch pointerout's button attribute is 0 when left mouse button is pressed. 
-PASS Inner frame  touch pointerout's buttons is 0 when mouse buttons are in released state. 
-PASS Inner frame  touch pointerout's ClientX and ClientY attributes are correct. 
-PASS Inner frame  touch pointerout event pointerType is correct. 
-PASS Inner frame  touch pointerout event is a PointerEvent event 
-PASS Inner frame  touch pointerout.pointerId attribute exists 
-PASS Inner frame  touch pointerout.pointerId is readonly 
-PASS Inner frame  touch pointerout.pointerId IDL type long (JS type was number) 
-PASS Inner frame  touch pointerout.width attribute exists 
-PASS Inner frame  touch pointerout.width is readonly 
-PASS Inner frame  touch pointerout.width IDL type float (JS type was number) 
-PASS Inner frame  touch pointerout.height attribute exists 
-PASS Inner frame  touch pointerout.height is readonly 
-PASS Inner frame  touch pointerout.height IDL type float (JS type was number) 
-PASS Inner frame  touch pointerout.pressure attribute exists 
-PASS Inner frame  touch pointerout.pressure is readonly 
-PASS Inner frame  touch pointerout.pressure IDL type float (JS type was number) 
-PASS Inner frame  touch pointerout.tiltX attribute exists 
-PASS Inner frame  touch pointerout.tiltX is readonly 
-PASS Inner frame  touch pointerout.tiltX IDL type long (JS type was number) 
-PASS Inner frame  touch pointerout.tiltY attribute exists 
-PASS Inner frame  touch pointerout.tiltY is readonly 
-PASS Inner frame  touch pointerout.tiltY IDL type long (JS type was number) 
-PASS Inner frame  touch pointerout.pointerType attribute exists 
-PASS Inner frame  touch pointerout.pointerType is readonly 
-PASS Inner frame  touch pointerout.pointerType IDL type string (JS type was string) 
-PASS Inner frame  touch pointerout.isPrimary attribute exists 
-PASS Inner frame  touch pointerout.isPrimary is readonly 
-PASS Inner frame  touch pointerout.isPrimary IDL type boolean (JS type was boolean) 
-PASS Inner frame  touch pointerout.detail attribute exists 
-PASS Inner frame  touch pointerout.detail is readonly 
-PASS Inner frame  touch pointerout.detail IDL type long (JS type was number) 
-PASS Inner frame  touch pointerout.detail value is 0. 
-PASS Inner frame  touch pointerout.pressure value is valid 
-PASS Inner frame  touch pointerout.isPrimary attribute is correct. 
-PASS Inner frame  touch pointerout.pointerId should be the same as previous pointer events for this active pointer. 
-PASS Inner frame  touch pointerleave's type should be pointerleave 
-PASS Inner frame  touch pointerleave's button attribute is 0 when left mouse button is pressed. 
-PASS Inner frame  touch pointerleave's buttons is 0 when mouse buttons are in released state. 
-PASS Inner frame  touch pointerleave's ClientX and ClientY attributes are correct. 
-PASS Inner frame  touch pointerleave event pointerType is correct. 
-PASS Inner frame  touch pointerleave event is a PointerEvent event 
-PASS Inner frame  touch pointerleave.pointerId attribute exists 
-PASS Inner frame  touch pointerleave.pointerId is readonly 
-PASS Inner frame  touch pointerleave.pointerId IDL type long (JS type was number) 
-PASS Inner frame  touch pointerleave.width attribute exists 
-PASS Inner frame  touch pointerleave.width is readonly 
-PASS Inner frame  touch pointerleave.width IDL type float (JS type was number) 
-PASS Inner frame  touch pointerleave.height attribute exists 
-PASS Inner frame  touch pointerleave.height is readonly 
-PASS Inner frame  touch pointerleave.height IDL type float (JS type was number) 
-PASS Inner frame  touch pointerleave.pressure attribute exists 
-PASS Inner frame  touch pointerleave.pressure is readonly 
-PASS Inner frame  touch pointerleave.pressure IDL type float (JS type was number) 
-PASS Inner frame  touch pointerleave.tiltX attribute exists 
-PASS Inner frame  touch pointerleave.tiltX is readonly 
-PASS Inner frame  touch pointerleave.tiltX IDL type long (JS type was number) 
-PASS Inner frame  touch pointerleave.tiltY attribute exists 
-PASS Inner frame  touch pointerleave.tiltY is readonly 
-PASS Inner frame  touch pointerleave.tiltY IDL type long (JS type was number) 
-PASS Inner frame  touch pointerleave.pointerType attribute exists 
-PASS Inner frame  touch pointerleave.pointerType is readonly 
-PASS Inner frame  touch pointerleave.pointerType IDL type string (JS type was string) 
-PASS Inner frame  touch pointerleave.isPrimary attribute exists 
-PASS Inner frame  touch pointerleave.isPrimary is readonly 
-PASS Inner frame  touch pointerleave.isPrimary IDL type boolean (JS type was boolean) 
-PASS Inner frame  touch pointerleave.detail attribute exists 
-PASS Inner frame  touch pointerleave.detail is readonly 
-PASS Inner frame  touch pointerleave.detail IDL type long (JS type was number) 
-PASS Inner frame  touch pointerleave.detail value is 0. 
-PASS Inner frame  touch pointerleave.pressure value is valid 
-PASS Inner frame  touch pointerleave.isPrimary attribute is correct. 
-PASS Inner frame  touch pointerleave.pointerId should be the same as previous pointer events for this active pointer. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2-expected.html b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2-expected.html
index de773fc..3778f23 100644
--- a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2-expected.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
-<script src="../../../resorces/ahem.js"></script>
 <p>crbug.com/648342: The text should be on two lines.</p>
-<div style="width:260px; font-size: 12px; font-family: ahem, sans-serif;">
-    <br><br>Text Text <br> Text Text
+<div style="width:260px; font-size: 12px;">
+    <br><br>Text Text Text Text Text Text <br> Text Text Text
 </div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2.html b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2.html
index f93fce5..04fa07a 100644
--- a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2.html
+++ b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-2.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
-<script src="../../../resorces/ahem.js"></script>
 <p>crbug.com/648342: The text should be on two lines.</p>
-<div style="width:260px; font-size: 12px; font-family: ahem, sans-serif;">
-    <span></span><br><br><span><a><img src="../../../canvas/philip/images/transparent.png" align="right"></a>Text Text Text Text</span><br><span></span>
+<div style="width:260px; font-size: 12px;">
+    <span></span><br><br><span><a><img src="../../../canvas/philip/images/transparent.png" align="right"></a>Text Text Text Text Text Text Text Text Text</span><br><span></span>
 </div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-expected.html b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-expected.html
index 7396aa7..3778f23 100644
--- a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks-expected.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
-<script src="../../../resorces/ahem.js"></script>
 <p>crbug.com/648342: The text should be on two lines.</p>
-<div style="width:260px; font-size: 12px; font-family: ahem, sans-serif;">
-    <br><br>Text Text<br>Text Text
+<div style="width:260px; font-size: 12px;">
+    <br><br>Text Text Text Text Text Text <br> Text Text Text
 </div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks.html b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks.html
index 47a9d43..34083fc6 100644
--- a/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks.html
+++ b/third_party/WebKit/LayoutTests/fast/block/float/float-should-dirty-line-when-adjacent-to-line-breaks.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
-<script src="../../../resorces/ahem.js"></script>
 <p>crbug.com/648342: The text should be on two lines.</p>
-<div style="width:260px; font-size: 12px; font-family: ahem, sans-serif;">
-    <br><br><a><img src="../../../canvas/philip/images/transparent.png" align="right"></a>Text Text Text Text
+<div style="width:260px; font-size: 12px;">
+    <br><br><a><img src="../../../canvas/philip/images/transparent.png" align="right"></a>Text Text Text Text Text Text Text Text Text
 </div>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
deleted file mode 100644
index aeb83637..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is 255
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is 255
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is 255
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 76
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 76
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 76
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 200
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 49
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 199
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 70
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 70
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 69
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow.html
index 4e9f5df..ea50df6b 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow.html
@@ -1,9 +1,87 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-scale-strokePath-shadow.js"></script>
+<script>
+// Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '600');
+canvas.setAttribute('height', '600');
+var ctx = canvas.getContext('2d');
+
+ctx.scale(2, 2);
+ctx.shadowOffsetX = 100;
+ctx.shadowOffsetY = 100;
+ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
+ctx.lineWidth = 5;
+
+ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
+ctx.beginPath();
+ctx.moveTo(50, 50);
+ctx.lineTo(100, 50);
+ctx.lineTo(100, 100);
+ctx.lineTo(50, 100);
+ctx.lineTo(50, 50);
+ctx.stroke();
+
+ctx.shadowColor = 'rgba(255, 0, 0, 0.3)';
+ctx.beginPath();
+ctx.moveTo(50, 150);
+ctx.lineTo(100, 150);
+ctx.lineTo(100, 200);
+ctx.lineTo(50, 200);
+ctx.lineTo(50, 150);
+ctx.stroke();
+
+ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
+ctx.shadowBlur = 10;
+ctx.beginPath();
+ctx.moveTo(150, 50);
+ctx.lineTo(200, 50);
+ctx.lineTo(200, 100);
+ctx.lineTo(150, 100);
+ctx.lineTo(150, 50);
+ctx.stroke();
+
+ctx.shadowColor = 'rgba(255, 0, 0, 0.6)';
+ctx.beginPath();
+ctx.moveTo(150, 150);
+ctx.lineTo(200, 150);
+ctx.lineTo(200, 200);
+ctx.lineTo(150, 200);
+ctx.lineTo(150, 150);
+ctx.stroke();
+
+function testPixelShadowBlur(x, y, color)
+{
+    if (color.length == 4) {
+        assert_array_equals(ctx.getImageData(x, y, 1, 1).data, color);
+    } else {    // we expect to have [r, g, b, a, alphaApprox]
+        var data = ctx.getImageData(x, y, 1, 1).data;
+        assert_array_equals(data.slice(0,3), color.slice(0,3));
+        assert_approx_equals(data[3], color[3], color[4]);
+    }
+}
+
+var testPixelShadowScenarios = [
+    ['Verify solid shadow 1', 250, 200, [255, 0, 0, 255]],
+    ['Verify solid shadow 2', 300, 290, [255, 0, 0, 255]],
+    ['Verify solid shadow 3', 200, 250, [255, 0, 0, 255]],
+
+    ['Verify solid alpha shadow 1', 201, 405, [255, 0, 0, 76, 20]],
+    ['Verify solid alpha shadow 2', 201, 500, [255, 0, 0, 76, 20]],
+    ['Verify solid alpha shadow 3', 300, 499, [255, 0, 0, 76, 20]],
+
+    ['Verify blurry shadow 1', 398, 210, [255, 0, 0, 200, 20]],
+    ['Verify blurry shadow 2', 508, 250, [255, 0, 0, 49, 20]],
+    ['Verify blurry shadow 3', 450, 198, [255, 0, 0, 199, 20]],
+    
+    ['Verify blurry alpha shadow 1', 505, 450, [255, 0, 0, 70, 20]],
+    ['Verify blurry alpha shadow 2', 450, 405, [255, 0, 0, 70, 20]],
+];
+
+generate_tests(testPixelShadowBlur, testPixelShadowScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm-expected.txt
deleted file mode 100644
index 150d1db..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Tests to make sure we can assign to non-ctm effected properties with a non-invertible ctm set
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS ctx.fillStyle is "#008000"
-PASS imageData.data[0] is 0
-PASS imageData.data[1] is 128
-PASS imageData.data[2] is 0
-PASS ctx.strokeStyle is "#008000"
-PASS imageData.data[0] is 0
-PASS imageData.data[1] is 128
-PASS imageData.data[2] is 0
-PASS imageData.data[0] is 0
-PASS imageData.data[1] is 128
-PASS imageData.data[2] is 0
-PASS imageData.data[0] is 0
-PASS imageData.data[1] is 128
-PASS imageData.data[2] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm.html
index 89bd3324..541efc2 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-set-properties-with-non-invertible-ctm.html
@@ -1,9 +1,72 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-set-properties-with-non-invertible-ctm.js"></script>
+<script>
+var canvas = document.createElement("canvas");
+canvas.width = 100;
+canvas.height = 100;
+var ctx = canvas.getContext('2d');
+document.body.appendChild(canvas);
+
+function checkPixel(x, y, rgb) {
+    assert_array_equals(ctx.getImageData(x, y, 1, 1).data.slice(0,3), rgb);
+}
+
+test(function(t) {
+    // Test our ability to set fillStyle
+    ctx.save();
+    ctx.scale(0, 0);
+    ctx.fillStyle = "green";
+    assert_equals(ctx.fillStyle, "#008000");
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(50, 50, [0, 128, 0]);
+    ctx.restore();
+    
+    // Test our ability to set strokeStyle
+    ctx.save();
+    ctx.fillStyle = "red";
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.scale(0, 0);
+    ctx.strokeStyle = "green";
+    assert_equals(ctx.strokeStyle, "#008000");
+    ctx.lineWidth = 100;
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.strokeRect(0, 0, 100, 100);
+    checkPixel(50, 50, [0, 128, 0]);
+    ctx.restore();
+    
+    // test closePath
+    ctx.save();
+    ctx.fillStyle = "red";
+    ctx.fillRect(0, 0, 100, 100);
+    
+    ctx.beginPath();
+    ctx.strokeStyle = "green";
+    ctx.lineWidth = 100;
+    ctx.moveTo(-100, 50);
+    ctx.lineTo(-100, -100);
+    ctx.lineTo( 200, -100);
+    ctx.lineTo( 200, 50);
+    ctx.scale(0, 0);
+    ctx.closePath();
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.stroke();
+    ctx.restore();
+    checkPixel(50, 50, [0, 128, 0]);
+    
+    // Test beginPath behaviour
+    ctx.fillStyle = "green";
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.fillStyle = "red";
+    ctx.rect(0, 0, 100, 100);
+    ctx.scale(0, 0);
+    ctx.beginPath();
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.fill();
+    
+    checkPixel(50, 50, [0, 128, 0]);
+    
+}, "Tests to make sure we can assign to non-ctm effected properties with a non-invertible ctm set");
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform-expected.txt
deleted file mode 100644
index 4d98617..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-Series of tests to ensure correct behaviour of canvas.setTransform()
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Reset the CTM to the initial matrix
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-setTransform should not affect the current path
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-setTransform should not affect the CTM outside of save() and restore()
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-stop drawing on not-invertible CTM
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-setTransform with a not-invertible matrix should only stop the drawing up to the next restore()
-PASS imgdata[4] is 0
-PASS imgdata[5] is 0
-PASS imgdata[6] is 255
-setTransform should set transform although CTM is not-invertible
-PASS imgdata[4] is 0
-PASS imgdata[5] is 0
-PASS imgdata[6] is 255
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform.html
index 9978020..3819827 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-setTransform.html
@@ -1,9 +1,73 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-setTransform.js"></script>
+<script>
+var ctx = document.createElement('canvas').getContext('2d');
+
+function checkPixel(x, y, rgb) {
+    assert_array_equals(ctx.getImageData(x, y, 1, 1).data.slice(0,3), rgb);
+}
+
+test(function(t) {
+
+    ctx.beginPath();
+    ctx.scale(0.5, 0.5);
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.fillStyle = 'green';
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(2, 1, [0, 128, 0]);
+    
+    ctx.beginPath();
+    ctx.rect(0, 0, 100, 100);
+    ctx.save();
+    ctx.setTransform(0.5, 0, 0, 0.5, 10, 10);
+    ctx.fillStyle = 'red';
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.restore();
+    ctx.fillStyle = 'green';
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(2, 1, [0, 128, 0]);
+    
+    ctx.beginPath();
+    ctx.fillStyle = 'green';
+    ctx.save();
+    ctx.setTransform(0.5, 0, 0, 0.5, 0, 0);
+    ctx.fillStyle = 'red';
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.restore();
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(2, 1, [0, 128, 0]);
+    
+    ctx.beginPath();
+    ctx.fillStyle = 'green';
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.setTransform(0, 0, 0, 0, 0, 0);
+    ctx.fillStyle = 'red';
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(2, 1, [0, 128, 0]);
+    
+    ctx.beginPath();
+    ctx.resetTransform();
+    ctx.save();
+    ctx.setTransform(0, 0, 0, 0, 0, 0);
+    ctx.fillStyle = 'red';
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.restore();
+    ctx.fillStyle = 'blue';
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(2, 1, [0, 0, 255]);
+    
+    ctx.beginPath();
+    ctx.fillStyle = 'red';
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.setTransform(0, 0, 0, 0, 0, 0);
+    ctx.fillStyle = 'green';
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.fillStyle = 'blue';
+    ctx.fillRect(0, 0, 100, 100);
+    checkPixel(2, 1, [0, 0, 255]);
+    
+}, "Series of tests to ensure correct behaviour of canvas.setTransform()");
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow-expected.txt
deleted file mode 100644
index dd3f8e9..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Some tests for Canvas shadows
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow.html
index 4a2c176..fe72b80d 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-shadow.html
@@ -1,9 +1,32 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-shadow.js"></script>
+<script>
+var ctx = document.createElement('canvas').getContext('2d');
+
+function checkPixel(x, y, rgb) {
+    assert_array_equals(ctx.getImageData(x, y, 1, 1).data.slice(0,3), rgb);
+}
+
+test(function(t) {
+    
+    ctx.fillStyle = "green";
+    ctx.fillRect(0, 0, 100, 100);
+    ctx.shadowColor = "green";
+    ctx.shadowOffsetX = 0;
+    ctx.shadowOffsetY = 0;
+    ctx.shadowBlur = 0;
+    checkPixel(1, 0, [0, 128, 0]);
+    
+    ctx.clearRect(0, 0, 200, 50);
+    ctx.shadowColor = "green";
+    ctx.shadowOffsetX = 100;
+    ctx.shadowOffsetY = 0;
+    ctx.shadowBlur = 2;
+    ctx.fillStyle = "green";
+    ctx.fillRect(0, 0, 100, 50);
+    checkPixel(111, 10, [0, 128, 0]);
+    
+}, "Some tests for Canvas shadows");
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size-expected.txt
deleted file mode 100644
index f9fb57cd..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This test checks to see if the browser survives the attempted creation of an excessively large canvas.
-
-Survived canvas creation attempt. Width = 134217728
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size.html
index 38c3b44..b237a711 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-skia-excessive-size.html
@@ -1,37 +1,21 @@
-<head>
-<script>
-function print(message)
-{
-    var paragraph = document.createElement("li");
-    paragraph.appendChild(document.createTextNode(message));
-    document.getElementById("console").appendChild(paragraph);
-}
-function test()
-{
-    if (window.testRunner)
-        testRunner.dumpAsText();
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<canvas id="bigCanvas" width="134217728" height="1"></canvas>
 
+<script>
+function runTest() {
     var canvas = document.getElementById("bigCanvas");
     var width = canvas.width;
-    // We need to perform a context fetch to force allocation of
-    // canvas resources.
-    if (canvas.getContext)
-    {
-      var ctx = canvas.getContext("2d");
-      if (ctx == null)
-      {
-        print("Canvas 2d context = null!");
-      }
-    }
-
-    print("Survived canvas creation attempt. Width = " + width);
+    // We need to perform a context fetch to force allocation of canvas resources.
+    var ctx = canvas.getContext("2d");
+    assert_false(ctx == null);
+    assert_equals(canvas.width, 134217728);
 }
+
+async_test(t => {
+        window.onload = function() {
+            t.step(runTest);
+            t.done();
+        }
+}, 'Verifies if the browser survives the attempted creation of an excessively large canvas.');
 </script>
-</head>
-<body onload="test();">
-<canvas id="bigCanvas" width="134217728" height="1"></canvas>
-<p>This test checks to see if the browser survives the attempted creation
-of an excessively large canvas.</p>
-<hr>
-<p><ol id=console></ol></p>
-</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData-expected.txt
deleted file mode 100644
index ceb1bf4..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData-expected.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Test that the rendering context state is intact after a call to putImageData()
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Checking initial state for sanity
-PASS ctx.fillStyle is '#ff0000'
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-PASS imgdata[4] is 0
-PASS imgdata[5] is 0
-PASS imgdata[6] is 0
-PASS imgdata[7] is 0
-Calling putImageData()
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-Checking if state is intact
-PASS ctx.fillStyle is '#ff0000'
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData.html
index 7c555c0..fa5375c 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-state-intact-after-putImageData.html
@@ -1,9 +1,28 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="script-tests/canvas-state-intact-after-putImageData.js"></script>
-</body>
-</html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
+<script>
+test(function(t) {
+
+    var ctx = document.createElement('canvas').getContext('2d');
+    
+    ctx.fillStyle = 'red';
+    ctx.fillRect(0, 0, 1, 1);
+    
+    assert_equals(ctx.fillStyle, '#ff0000');
+    var imageData = ctx.getImageData(0, 0, 2, 1);
+    assert_array_equals(imageData.data.slice(0,4), [255, 0, 0, 255]);
+    assert_array_equals(imageData.data.slice(4), [0, 0, 0, 0]);
+    
+    ctx.putImageData(imageData, 1, 1);
+    imageData = ctx.getImageData(1, 1, 1, 1);
+    assert_array_equals(imageData.data, [255, 0, 0, 255]);
+    
+    assert_equals(ctx.fillStyle, '#ff0000');
+    
+    ctx.fillRect(2, 2, 1, 1);
+    data = ctx.getImageData(2, 2, 1, 1).data;
+    assert_array_equals(data, [255, 0, 0, 255]);
+
+}, "Test that the rendering context state is intact after a call to putImageData()");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill-expected.txt
deleted file mode 100644
index eceb92b2..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Series of tests to ensure correct behaviour for stroke() on an empty fillStyle() (alpha=0)
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.html
index 439f85c..f572d14 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.html
@@ -1,9 +1,17 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="canvas-stroke-empty-fill.js"></script>
-</body>
-</html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function(t) {
+    var ctx = document.createElement('canvas').getContext('2d');
+
+    ctx.fillStyle = 'rgba(0,0,0,0)';
+    ctx.strokeStyle = 'green';
+    ctx.lineWidth = 200;
+    ctx.moveTo(0,100);
+    ctx.lineTo(200,100);
+    ctx.stroke();
+    var imageData = ctx.getImageData(1, 0, 1, 1).data;
+    assert_array_equals(imageData.slice(0, 3), [0, 128, 0]);
+}, 'Verify correct behaviour for stroke() on an empty fillStyle() (alpha=0).');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.js b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.js
deleted file mode 100644
index 1ef09c22..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-empty-fill.js
+++ /dev/null
@@ -1,14 +0,0 @@
-description("Series of tests to ensure correct behaviour for stroke() on an empty fillStyle() (alpha=0)");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = 'rgba(0,0,0,0)';
-ctx.strokeStyle = 'green';
-ctx.lineWidth = 200;
-ctx.moveTo(0,100);
-ctx.lineTo(200,100);
-ctx.stroke();
-var imageData = ctx.getImageData(0, 0, 100, 100);
-var imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient-expected.txt
deleted file mode 100644
index a4f3cb9..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Series of tests to ensure that stroke() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient.html
index 1022fe1..3436cbc8 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-stroke-zeroSizeGradient.html
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-stroke-zeroSizeGradient.js"></script>
+<script>
+test(function(t) {
+    var ctx = document.createElement('canvas').getContext('2d');
+    
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 1, 1);
+    
+    var g = ctx.createLinearGradient(0, 0, 0, 0); // zero-length line (undefined direction);
+    g.addColorStop(0, '#f00');
+    g.addColorStop(1, '#f00');
+    ctx.strokeStyle = g;
+    ctx.rect(0, 0, 1 , 1);
+    ctx.stroke();
+    
+    assert_array_equals(ctx.getImageData(0, 0, 1, 1).data.slice(0,3), [0, 255, 0]);
+}, "Series of tests to ensure that stroke() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.");
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow-expected.txt
deleted file mode 100644
index d4ac238..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow-expected.txt
+++ /dev/null
@@ -1,97 +0,0 @@
-Ensure correct behavior of canvas with path stroke using a strokeStyle color with alpha and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 31
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow.html
index ddaacf4..b01883f 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow.html
@@ -1,9 +1,93 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokePath-alpha-shadow.js"></script>
+<script>
+
+// Ensure correct behavior of canvas with path stroke using a strokeStyle color with alpha and a shadow.
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '600');
+canvas.setAttribute('height', '1100');
+var ctx = canvas.getContext('2d');
+
+ctx.save();
+ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.shadowOffsetX = 250;
+ctx.lineWidth = 50;
+
+function strokePath(x, y) {
+    ctx.beginPath();
+    ctx.arc(x, y, 75, 0, Math.PI*2, true);
+    ctx.stroke();
+}
+
+// Alpha shadow.
+ctx.shadowBlur = 0;
+strokePath(150, 150);
+
+// Blurry shadow.
+ctx.shadowBlur = 10;
+strokePath(150, 400);
+
+ctx.rotate(Math.PI/2);
+
+// Rotated alpha shadow.
+ctx.shadowBlur = 0;
+strokePath(650, -150);
+
+// Rotated blurry shadow.
+ctx.shadowBlur = 10;
+strokePath(900, -150);
+
+ctx.restore();
+
+var imageData, data;
+ctx.fillStyle = 'black';
+
+function testPixelAlphaShadow(x, y, color)
+{
+    if (color.length == 4) {
+        assert_array_equals(ctx.getImageData(x, y, 1, 1).data, color);
+    } else {    // we expect to have [r, g, b, a, alphaTolerance]
+        var data = ctx.getImageData(x, y, 1, 1).data;
+        assert_array_equals(data.slice(0,3), color.slice(0,3));
+        assert_approx_equals(data[3], color[3], color[4]);
+    }
+    // Plot test point.
+    ctx.fillRect(x, y, 3, 3);
+}
+
+var alphaTolerance = 15;
+var testPixelAlphaShadowScenarios = [
+    ['Verify alpha shadow 1', 400, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 2', 400, 75, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 3', 400, 225, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 4', 325, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 5', 475, 150, [255, 0, 0, 64, alphaTolerance]],
+
+    ['Verify blurry shadow 1', 400, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 2', 400, 300, [255, 0, 0, 31, alphaTolerance]],
+    ['Verify blurry shadow 3', 400, 500, [255, 0, 0, 31, alphaTolerance]],
+    ['Verify blurry shadow 4', 300, 400, [255, 0, 0, 31, alphaTolerance]],
+    ['Verify blurry shadow 5', 500, 400, [255, 0, 0, 31, alphaTolerance]],
+
+    ['Verify rotated alpha shadow 1', 400, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 2', 400, 575, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 3', 400, 725, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 4', 325, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 5', 475, 650, [255, 0, 0, 64, alphaTolerance]],
+    
+    ['Verify rotated blurry shadow 1', 400, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 2', 400, 800, [255, 0, 0, 31, alphaTolerance]],
+    ['Verify rotated blurry shadow 3', 400, 1000, [255, 0, 0, 31, alphaTolerance]],
+    ['Verify rotated blurry shadow 2', 300, 900, [255, 0, 0, 31, alphaTolerance]],
+    ['Verify rotated blurry shadow 2', 500, 900, [255, 0, 0, 31, alphaTolerance]],
+    
+];
+
+generate_tests(testPixelAlphaShadow, testPixelAlphaShadowScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join-expected.txt
deleted file mode 100644
index 9db0ce3..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join-expected.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-Ensure correct behavior of canvas with path stroke with cap and join
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS data[0] is 0
-PASS data[0] is 255
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join.html
index 65542cd0..e304c7e 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-cap-join.html
@@ -1,9 +1,162 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokePath-cap-join.js"></script>
+<script>
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '700');
+canvas.setAttribute('height', '200');
+var ctx = canvas.getContext('2d');
+
+ctx.miterLimit = 5;
+ctx.lineWidth = 15;
+
+ctx.fillStyle="rgba(255, 255, 255, 1.0)";
+ctx.fillRect(0, 0, 700, 200);
+
+ctx.strokeStyle="rgba(0, 0, 0, 1.0)";
+ctx.lineJoin = "miter";
+ctx.lineCap = "round";
+
+ctx.translate(0, 50);
+ctx.save();
+
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 2);
+ctx.lineTo(50, 100);
+ctx.stroke();
+
+ctx.translate(60 ,0);
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 3);
+ctx.lineTo(50, 100);
+ctx.stroke();
+
+ctx.translate(90 ,0);
+ctx.save();
+ctx.rotate(0.2);
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 3);
+ctx.lineTo(50, 100);
+ctx.closePath();
+ctx.stroke();
+ctx.restore();
+
+ctx.restore();
+
+ctx.lineJoin = "bevel";
+ctx.lineCap = "square";
+
+ctx.translate(200, 0);
+ctx.save();
+
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 2);
+ctx.lineTo(50, 100);
+ctx.stroke();
+
+ctx.translate(60 ,0);
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 3);
+ctx.lineTo(50, 100);
+ctx.stroke();
+
+ctx.translate(90 ,0);
+ctx.save();
+ctx.rotate(0.2);
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 3);
+ctx.lineTo(50, 100);
+ctx.closePath();
+ctx.stroke();
+ctx.restore();
+
+ctx.restore();
+
+ctx.lineJoin = "round";
+ctx.lineCap = "butt";
+
+ctx.translate(200, 0);
+ctx.save();
+
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 2);
+ctx.lineTo(50, 100);
+ctx.stroke();
+
+ctx.translate(60 ,0);
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 3);
+ctx.lineTo(50, 100);
+ctx.stroke();
+
+ctx.translate(90 ,0);
+ctx.save();
+ctx.rotate(0.2);
+ctx.beginPath();
+ctx.moveTo(10, 100);
+ctx.lineTo(30, 3);
+ctx.lineTo(50, 100);
+ctx.closePath();
+ctx.stroke();
+ctx.restore();
+
+ctx.restore();
+
+function checkPixel(x, y, redComponent)
+{
+    assert_equals(ctx.getImageData(x, y, 1, 1).data[0], redComponent);
+}
+
+var testScenarios = [
+    ['Verify Join : miter, Cap : round. 1', 30, 51, 0],
+    ['Verify Join : miter, Cap : round. 2', 30, 49, 255],
+    ['Verify Join : miter, Cap : round. 3', 14, 154, 0],
+    ['Verify Join : miter, Cap : round. 4', 14, 157, 255],
+    ['Verify Join : miter, Cap : round. 5', 89, 22, 0],
+    ['Verify Join : miter, Cap : round. 6', 89, 12, 255],
+    ['Verify Join : miter, Cap : round. 7', 184, 29, 0],
+    ['Verify Join : miter, Cap : round. 8', 180, 27, 255],
+    ['Verify Join : miter, Cap : round. 9', 132, 152, 0],
+    ['Verify Join : miter, Cap : round. 10', 130, 157, 255],
+    
+    ['Verify Join : bevel, Cap : square. 1', 202, 154, 0],
+    ['Verify Join : bevel, Cap : square. 2', 201, 150, 255],
+    ['Verify Join : bevel, Cap : square. 3', 228, 52, 0],
+    ['Verify Join : bevel, Cap : square. 4', 225, 48, 255],
+    ['Verify Join : bevel, Cap : square. 5', 316, 154, 0],
+    ['Verify Join : bevel, Cap : square. 6', 316, 157, 255],
+    ['Verify Join : bevel, Cap : square. 7', 289, 52, 0],
+    ['Verify Join : bevel, Cap : square. 8', 289, 48, 255],
+    ['Verify Join : bevel, Cap : square. 9', 372, 58, 0],
+    ['Verify Join : bevel, Cap : square. 10', 373, 54, 255],
+    ['Verify Join : bevel, Cap : square. 11', 380, 159, 0],
+    ['Verify Join : bevel, Cap : square. 12', 383, 162, 255],
+    
+    ['Verify Join : round, Cap : butt. 1', 405, 147, 0],
+    ['Verify Join : round, Cap : butt. 2', 405, 151, 255],
+    ['Verify Join : round, Cap : butt. 3', 429, 46, 0],
+    ['Verify Join : round, Cap : butt. 4', 429, 43, 255],
+    ['Verify Join : round, Cap : butt. 5', 464, 146, 0],
+    ['Verify Join : round, Cap : butt. 6', 464, 150, 255],
+    ['Verify Join : round, Cap : butt. 7', 489, 46, 0],
+    ['Verify Join : round, Cap : butt. 8', 489, 43, 255],
+    ['Verify Join : round, Cap : butt. 9', 534, 151, 0],
+    ['Verify Join : round, Cap : butt. 10', 531, 153, 255],
+    ['Verify Join : round, Cap : butt. 11', 579, 52, 0],
+    ['Verify Join : round, Cap : butt. 12', 579, 48, 255],
+];
+
+generate_tests(checkPixel, testScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow-expected.txt
deleted file mode 100644
index cf5964f..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow-expected.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-Ensure correct behavior of canvas with strokePath using a gradient strokeStyle and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow.html
index 83a7832..2517bfb 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow.html
@@ -1,9 +1,125 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokePath-gradient-shadow.js"></script>
+<script>
+// Ensure correct behavior of canvas with strokePath using a gradient strokeStyle and a shadow.
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '600');
+canvas.setAttribute('height', '1100');
+var ctx = canvas.getContext('2d');
+
+var gradient = ctx.createLinearGradient(0, 0, 300, 0);
+gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
+gradient.addColorStop(1, 'rgba(0, 0, 255, 0.5)');
+
+ctx.save();
+ctx.strokeStyle = gradient;
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.shadowOffsetX = 250;
+ctx.lineWidth = 25;
+
+var side = 200;
+
+// Alpha shadow.
+ctx.shadowBlur = 0;
+ctx.beginPath();
+ctx.rect(50, 50, side, side);
+ctx.stroke();
+
+// Blurry shadow.
+ctx.shadowBlur = 10;
+ctx.beginPath();
+ctx.rect(50, 300, side, side);
+ctx.stroke();
+
+ctx.rotate(Math.PI / 2);
+
+// Rotated alpha shadow.
+ctx.shadowBlur = 0;
+ctx.beginPath();
+ctx.rect(550, -250, side, side);
+ctx.stroke();
+
+// Rotated blurry shadow.
+ctx.shadowBlur = 10;
+ctx.beginPath();
+ctx.rect(800, -250, side, side);
+ctx.stroke();
+
+ctx.restore();
+
+var imageData, data;
+ctx.fillStyle = 'black';
+
+function testPixelShadow(x, y, color)
+{
+    if (color.length == 4) {
+        assert_array_equals(ctx.getImageData(x, y, 1, 1).data, color);
+    } else {    // we expect to have [r, g, b, a, alphaApprox]
+        var data = ctx.getImageData(x, y, 1, 1).data;
+        assert_array_equals(data.slice(0,3), color.slice(0,3));
+        assert_approx_equals(data[3], color[3], color[4]);
+    }
+    // Plot test point.
+    ctx.fillRect(x, y, 3, 3);
+}
+
+var alphaTolerance = 15;
+var testScenarios = [
+    ['Verify alpha shadow 1' ,400, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 2' ,400, 75,  [0, 0, 0, 0]],
+    ['Verify alpha shadow 3' ,400, 225, [0, 0, 0, 0]],
+    ['Verify alpha shadow 4' ,325, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 5' ,475, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 6' ,400,  50, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 7' ,500, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 8' ,400, 250, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 9' ,300, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 10' ,400, 25,  [0, 0, 0, 0]],
+    ['Verify alpha shadow 11' ,525, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 12' ,400, 275, [0, 0, 0, 0]],
+    ['Verify blurry shadow 1' ,275, 150, [0, 0, 0, 0]],
+    ['Verify blurry shadow 2' ,400, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 3' ,400, 325, [0, 0, 0, 0]],
+    ['Verify blurry shadow 4' ,475, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 5' ,400, 475, [0, 0, 0, 0]],
+    ['Verify blurry shadow 6' ,325, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 7' ,400, 300, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 8' ,400, 500, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 9' ,300, 400, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 10' ,500, 400, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 11' ,525, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 12' ,275, 400, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 1' ,400, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 2' ,400, 575, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 3' ,400, 725, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 4' ,325, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 5' ,475, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 6' ,400, 550, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 7' ,500, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 8' ,400, 750, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 9' ,300, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 10' ,400, 525, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 11' ,525, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 12' ,400, 775, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 13' ,275, 650, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 1' ,400, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 2' ,400, 825, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 3' ,475, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 4' ,400, 975, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 5' ,325, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 6' ,400, 800,  [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 7' ,400, 1000, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 8' ,300, 900,  [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 9' ,500, 900,  [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 10' ,525, 900,  [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 11' ,275, 900,  [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 12' ,400, 1025, [0, 0, 0, 0]],
+];
+
+generate_tests(testPixelShadow, testScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow-expected.txt
deleted file mode 100644
index 6fb239dc..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow-expected.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-Ensure correct behavior of canvas with path stroke shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 20
-PASS data[2] is within 2 of 0
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 20
-PASS data[2] is within 2 of 0
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 20
-PASS data[2] is within 2 of 0
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 20
-PASS data[2] is within 2 of 0
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 0
-PASS data[2] is within 2 of 0
-PASS data[3] is not 255
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 0
-PASS data[2] is within 2 of 0
-PASS data[3] is not 255
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 0
-PASS data[2] is within 2 of 0
-PASS data[3] is not 255
-PASS data[0] is within 2 of 255
-PASS data[1] is within 2 of 0
-PASS data[2] is within 2 of 0
-PASS data[3] is not 255
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow.html
index 9d462aa..9b0e1016 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokePath-shadow.html
@@ -1,9 +1,64 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokePath-shadow.js"></script>
+<script>
+// Ensure correct behavior of canvas with path stroke shadow.
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '700');
+canvas.setAttribute('height', '700');
+var ctx = canvas.getContext('2d');
+
+ctx.beginPath();
+ctx.moveTo(300, 300);
+ctx.lineTo(300, 50);
+ctx.bezierCurveTo(200, 40, 75, 150, 30, 30);
+ctx.quadraticCurveTo(250, 75, 50, 300);
+ctx.shadowOffsetX = 350;
+ctx.shadowColor = 'rgba(255, 20, 0, 0.5)';
+ctx.shadowBlur = 0;
+ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
+ctx.lineWidth = 30;
+ctx.closePath();
+ctx.stroke();
+
+ctx.beginPath();
+ctx.moveTo(300,650);
+ctx.lineTo(300,400);
+ctx.bezierCurveTo(200, 390, 75, 500, 30, 380);
+ctx.quadraticCurveTo(250, 425, 50, 650);
+ctx.shadowOffsetX = 350;
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.shadowBlur = 30;
+ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
+ctx.lineWidth = 30;
+ctx.closePath();
+ctx.stroke();
+
+var colorTolerance = 2;
+function checkPixelWithTolerance(x, y, rgbNOTa) {
+    data = ctx.getImageData(x, y, 1, 1).data;
+    for (i = 0; i < 3; i++)
+        assert_approx_equals(data[i], rgbNOTa[i], colorTolerance);
+    if(rgbNOTa.length == 4)
+        assert_not_equals(data[3], rgbNOTa[3]);   
+}
+
+var testScenarios = [
+    ['Verify solid shadow 1', 650, 300, [255, 20, 0]],
+    ['Verify solid shadow 2', 650, 50, [255, 20, 0]],
+    ['Verify solid shadow 3', 380, 30, [255, 20, 0]],
+    ['Verify solid shadow 4', 400, 40, [255, 20, 0]],
+    
+    ['Verify blurry shadow 1', 640, 640, [255, 0, 0, 255]],
+    ['Verify blurry shadow 2', 650, 400, [255, 0, 0, 255]],
+    ['Verify blurry shadow 3', 380, 380, [255, 0, 0, 255]],
+    ['Verify blurry shadow 4', 350, 380, [255, 0, 0, 255]],
+
+];
+
+generate_tests(checkPixelWithTolerance, testScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow-expected.txt
deleted file mode 100644
index 67726ad7..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow-expected.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-Ensure correct behavior of canvas with strokeRect using a semi-transparent solid strokeStyle and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow.html
index fbbdee9..52b07ff 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow.html
@@ -1,9 +1,116 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokeRect-alpha-shadow.js"></script>
+<script>
+// Ensure correct behavior of canvas with strokeRect using a semi-transparent solid strokeStyle and a shadow.
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '600');
+canvas.setAttribute('height', '1100');
+var ctx = canvas.getContext('2d');
+
+ctx.save();
+ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.shadowOffsetX = 250;
+ctx.lineWidth = 25;
+
+var side = 200;
+
+// Alpha shadow.
+ctx.shadowBlur = 0;
+ctx.strokeRect(50, 50, side, side);
+
+// Blurry shadow.
+ctx.shadowBlur = 10;
+ctx.strokeRect(50, 300, side, side);
+
+ctx.rotate(Math.PI / 2);
+
+// Rotated alpha shadow.
+ctx.shadowBlur = 0;
+ctx.strokeRect(550, -250, side, side);
+
+// Rotated blurry shadow.
+ctx.shadowBlur = 10;
+ctx.strokeRect(800, -250, side, side);
+
+ctx.restore();
+
+var imageData, data;
+ctx.fillStyle = 'black';
+
+function testPixelAlphaShadow(x, y, color)
+{
+    if (color.length == 4) {
+        assert_array_equals(ctx.getImageData(x, y, 1, 1).data, color);
+    } else {    // we expect to have [r, g, b, a, alphaApprox]
+        var data = ctx.getImageData(x, y, 1, 1).data;
+        assert_array_equals(data.slice(0,3), color.slice(0,3));
+        assert_approx_equals(data[3], color[3], color[4]);
+    }
+    // Plot test point.
+    ctx.fillRect(x, y, 3, 3);
+}
+
+var alphaTolerance = 15;
+var testScenarios = [
+    ['Verify alpha shadow 1' , 400, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 2' , 400, 75, [0, 0, 0, 0]],
+    ['Verify alpha shadow 3' , 400, 225, [0, 0, 0, 0]],
+    ['Verify alpha shadow 4' , 325, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 5' , 475, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 6' , 400, 50, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 7' , 500, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 8' , 400, 250, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 9' , 300, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 10' , 400, 25, [0, 0, 0, 0]],
+    ['Verify alpha shadow 11' , 525, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 12' , 400, 275, [0, 0, 0, 0]],
+    ['Verify alpha shadow 13' , 275, 150, [0, 0, 0, 0]],
+
+    ['Verify blurry shadow 1' , 400, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 2' , 400, 325, [0, 0, 0, 0]],
+    ['Verify blurry shadow 3' , 475, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 4' , 400, 475, [0, 0, 0, 0]],
+    ['Verify blurry shadow 5' , 325, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 6' , 400, 300, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 7' , 400, 500, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 8' , 300, 400, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 9' , 500, 400, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 10' , 525, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 11' , 275, 400, [0, 0, 0, 0]],
+
+    ['Verify rotated alpha shadow 1' , 400, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 2' , 400, 575, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 3' , 400, 725, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 4' , 325, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 5' , 475, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 6' , 400, 550, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 7' , 500, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 8' , 400, 750, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 9' , 300, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 10' , 400, 525, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 11' , 525, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 12' , 400, 775, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 13' , 275, 650, [0, 0, 0, 0]],
+
+    ['Verify rotated blurry shadow 1' , 400, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 2' , 400, 825, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 3' , 475, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 4' , 400, 975, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 5' , 325, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 6' , 400, 800, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 7' , 400, 1000, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 8' , 300, 900, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 9' , 500, 900, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 10' , 525, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 11' , 275, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 12' , 400, 1025, [0, 0, 0, 0]],
+];
+
+generate_tests(testPixelAlphaShadow, testScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-expected.txt
deleted file mode 100644
index e941567..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Series of tests to ensure correct behaviour of canvas.strokeRect()
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Test canvas.strokeRect() with solid green.
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-Test canvas.strokeRect() with a pattern.
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-Test canvas.strokeRect() with a gradient.
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-Test canvas.strokeRect() with height = width = 0 and lineWidth = 2.
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-Test canvas.strokeRect() with height = width = 0, lineWidth = 2, and shadow.
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow-expected.txt
deleted file mode 100644
index 7747bc15..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow-expected.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-Ensure correct behavior of canvas with strokeRect using a gradient strokeStyle and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow.html
index 009a6e3..489149e7 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow.html
@@ -1,9 +1,120 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokeRect-gradient-shadow.js"></script>
+<script>
+// Ensure correct behavior of canvas with strokeRect using a gradient strokeStyle and a shadow.
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '600');
+canvas.setAttribute('height', '1100');
+var ctx = canvas.getContext('2d');
+
+var gradient = ctx.createLinearGradient(0, 0, 300, 0);
+gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
+gradient.addColorStop(1, 'rgba(0, 0, 255, 0.5)');
+
+ctx.save();
+ctx.strokeStyle = gradient;
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.shadowOffsetX = 250;
+ctx.lineWidth = 25;
+
+var side = 200;
+
+// Alpha shadow.
+ctx.shadowBlur = 0;
+ctx.strokeRect(50, 50, side, side);
+
+// Blurry shadow.
+ctx.shadowBlur = 10;
+ctx.strokeRect(50, 300, side, side);
+
+ctx.rotate(Math.PI / 2);
+
+// Rotated alpha shadow.
+ctx.shadowBlur = 0;
+ctx.strokeRect(550, -250, side, side);
+
+// Rotated blurry shadow.
+ctx.shadowBlur = 10;
+ctx.strokeRect(800, -250, side, side);
+
+ctx.restore();
+
+var imageData, data;
+ctx.fillStyle = 'black';
+
+function testPixelAlphaShadow(x, y, color)
+{
+    if (color.length == 4) {
+        assert_array_equals(ctx.getImageData(x, y, 1, 1).data, color);
+    } else {    // we expect to have [r, g, b, a, alphaApprox]
+        var data = ctx.getImageData(x, y, 1, 1).data;
+        assert_array_equals(data.slice(0,3), color.slice(0,3));
+        assert_approx_equals(data[3], color[3], color[4]);
+    }
+    // Plot test point.
+    ctx.fillRect(x, y, 3, 3);
+}
+
+var alphaTolerance = 15;
+var testScenarios = [
+    ['Verify alpha shadow 1' , 400, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 2' , 400, 75, [0, 0, 0, 0]],
+    ['Verify alpha shadow 3' , 400, 225, [0, 0, 0, 0]],
+    ['Verify alpha shadow 4' , 325, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 5' , 475, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 6' , 400, 50, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 7' , 500, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 8' , 400, 250, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 9' , 300, 150, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify alpha shadow 10' , 400, 25, [0, 0, 0, 0]],
+    ['Verify alpha shadow 11' , 525, 150, [0, 0, 0, 0]],
+    ['Verify alpha shadow 12' , 400, 275, [0, 0, 0, 0]],
+    ['Verify alpha shadow 13' , 275, 150, [0, 0, 0, 0]],
+
+    ['Verify blurry shadow 1' , 400, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 2' , 400, 325, [0, 0, 0, 0]],
+    ['Verify blurry shadow 3' , 475, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 4' , 400, 475, [0, 0, 0, 0]],
+    ['Verify blurry shadow 5' , 325, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 6' , 400, 300, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 7' , 400, 500, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 8' , 300, 400, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 9' , 500, 400, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify blurry shadow 10' , 525, 400, [0, 0, 0, 0]],
+    ['Verify blurry shadow 11' , 275, 400, [0, 0, 0, 0]],
+
+    ['Verify rotated alpha shadow 1' , 400, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 2' , 400, 575, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 3' , 400, 725, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 4' , 325, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 5' , 475, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 6' , 400, 550, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 7' , 500, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 8' , 400, 750, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 9' , 300, 650, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated alpha shadow 10' , 400, 525, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 11' , 525, 650, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 12' , 400, 775, [0, 0, 0, 0]],
+    ['Verify rotated alpha shadow 13' , 275, 650, [0, 0, 0, 0]],
+
+    ['Verify rotated blurry shadow 1' , 400, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 2' , 400, 825, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 3' , 475, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 4' , 400, 975, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 5' , 325, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 6' , 400, 800, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 7' , 400, 1000, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 8' , 300, 900, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 9' , 500, 900, [255, 0, 0, 64, alphaTolerance]],
+    ['Verify rotated blurry shadow 10' , 525, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 11' , 275, 900, [0, 0, 0, 0]],
+    ['Verify rotated blurry shadow 12' , 400, 1025, [0, 0, 0, 0]],
+];
+
+generate_tests(testPixelAlphaShadow, testScenarios);
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient-expected.txt
deleted file mode 100644
index b072c0e..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Series of tests to ensure that strokeRect() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient.html
index 6a7c50f..bbd923e 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect-zeroSizeGradient.html
@@ -1,9 +1,19 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="script-tests/canvas-strokeRect-zeroSizeGradient.js"></script>
-</body>
-</html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function(t) {
+    var ctx = document.createElement('canvas').getContext('2d');
+    
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 1, 1);
+    
+    var g = ctx.createLinearGradient(0, 0, 0, 0); // zero-length line (undefined direction);
+    g.addColorStop(0, '#f00');
+    g.addColorStop(1, '#f00');
+    ctx.strokeStyle = g;
+    ctx.strokeRect(0, 0, 1 , 1);
+    
+    assert_array_equals(ctx.getImageData(0, 0, 1, 1).data.slice(0,3), [0, 255, 0]);
+}, "Series of tests to ensure that strokeRect() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.");
+</script>
+    
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect.html
index 1a5580b..b71b155 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeRect.html
@@ -1,9 +1,61 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokeRect.js"></script>
+<script>
+
+var ctx = document.createElement('canvas').getContext('2d');
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 100;
+var ctx2 = canvas2.getContext('2d');
+
+test(function(t) {   
+    ctx.beginPath();
+    ctx.strokeStyle = 'green';
+    ctx.lineWidth = 100;
+    ctx.strokeRect(50, 0, 100, 100);
+    assert_array_equals(ctx.getImageData(2, 1, 1, 1).data.slice(0,3), [0, 128, 0]);
+}, "Verify the correct behaviour of canvas.strokeRect() with solid green");
+
+test(function(t) {
+    ctx.clearRect(0, 0, 100, 100);   
+    ctx2.fillStyle = 'green';
+    ctx2.fillRect(0, 0, 100, 100);
+    var pattern = ctx.createPattern(canvas2, 'repeat');
+    ctx.strokeStyle = 'pattern';
+    ctx.lineWidth = 100;
+    ctx.strokeRect(50, 0, 100, 100);
+    assert_array_equals(ctx.getImageData(2, 1, 1, 1).data.slice(0,3), [0, 128, 0]);   
+}, "Verify the correct behaviour of canvas.strokeRect() with a pattern");
+
+test(function(t) {
+    ctx.clearRect(0, 0, 100, 100);    
+    var gradient = ctx.createLinearGradient(0, 0, 0, 100);
+    gradient.addColorStop(0, "green");
+    gradient.addColorStop(1, "green");
+    ctx.strokeStyle = 'gradient';
+    ctx.lineWidth = 100;
+    ctx.strokeRect(50, 0, 100, 100);
+    assert_array_equals(ctx.getImageData(2, 1, 1, 1).data.slice(0,3), [0, 128, 0]);
+}, "Verify the correct behaviour of canvas.strokeRect() with a gradient");
+
+test(function(t) {
+    ctx.clearRect(0, 0, 100, 100);    
+    ctx.strokeStyle = 'red';
+    ctx.lineWidth = 2;
+    ctx.strokeRect(0, 0, 0, 0);
+    assert_array_equals(ctx.getImageData(0, 0, 1, 1).data.slice(0,3), [0, 0, 0]);
+}, "Verify the correct behaviour of canvas.strokeRect() with height = width = 0 and lineWidth = 2");
+
+test(function(t) {
+    ctx.shadowOffsetX = 5;
+    ctx.shadowOffsetY = 5;
+    ctx.shadowColor = 'blue';
+    ctx.strokeStyle = 'red';
+    ctx.lineWidth = 2;
+    ctx.strokeRect(0, 0, 0, 0);
+    assert_array_equals(ctx.getImageData(0, 0, 1, 1).data.slice(0,3), [0, 0, 0]);
+}, "Verify the correct behaviour of canvas.strokeRect()  with height = width = 0, lineWidth = 2, and shadow");
+
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth-expected.txt
deleted file mode 100644
index 7e271d0c..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Series of tests to ensure that strokeText() does not display any text when maxWidth is invalid.
-
-On success, you will see no "FAIL" messages, followed by "TEST COMPLETE".
-
-
-Test canvas.strokeText() with maxWidth zero
-Test canvas.strokeText() with maxWidth -1
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth.html
index 91d9640..30fe35f 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-invalid-maxWidth.html
@@ -1,10 +1,62 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokeText-invalid-maxWidth.js"></script>
+<script>
+test(function(t) {
+
+    var canvas = document.createElement('canvas');
+    var ctx = canvas.getContext('2d');
+    var canvasWidth = 100;
+    var canvasHeight = 50;
+    canvas.setWidth = canvasWidth;
+    canvas.setHeight = canvasHeight;
+    
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, canvasWidth, canvasHeight);
+    ctx.font = '35px Arial, sans-serif';
+    
+    ctx.strokeStyle = '#f00';
+    ctx.strokeText("fail fail fail fail fail", 5, 35, 0);
+    
+    var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
+    var w = imageData.width, h = imageData.height, d = imageData.data;
+    var testPassed = true;
+    var expectedColor = [0, 255, 0, 255];
+    mainLoop1:
+    for (var i = 0; i < h; ++i) {
+        for (var k = 0; k < 4; ++k) {
+            var j = w;
+            while (--j > 0 && d[4 * (w * i + j) + k] == expectedColor[k]);
+            testPassed = testPassed && j == 0;
+            if(!testPassed)
+                break mainLoop1;
+    
+        }
+    }
+    assert_true(testPassed);
+    
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, canvasWidth, canvasHeight);
+    
+    ctx.strokeStyle = '#f00';
+    ctx.strokeText("fail fail fail fail fail", 5, 35, -1);
+    
+    imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
+    d = imageData.data;
+    testPassed = true;
+    mainLoop2:
+    for (var i = 0; i < h; ++i) {
+        for (var k = 0; k < 4; ++k) {
+            var j = w;
+            while (--j > 0 && d[4 * (w * i + j) + k] == expectedColor[k]);
+            testPassed = testPassed && j == 0;
+            if(!testPassed)
+                break mainLoop2;
+        }
+    }
+    assert_true(testPassed);
+
+}, 'Series of tests to ensure that strokeText() does not display any text when maxWidth is invalid.');
+</script>
 </body>
-</html>
 
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow-expected.txt
deleted file mode 100644
index 4628590..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Test that strokeText() doesn't produce a filled shadow.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[0] is 0
-PASS imgdata[1] is 128
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow.html
index 370edc7b..a2474bb 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-strokes-shadow.html
@@ -1,9 +1,23 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokeText-strokes-shadow.js"></script>
+<script>
+test(function(t) {
+    var ctx = document.createElement('canvas').getContext('2d');
+    
+    ctx.fillStyle = 'green';
+    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+    
+    // Stroke an 'I' with its shadow in the upper left corner.
+    ctx.strokeStyle = 'white';
+    ctx.lineWidth = 2;
+    ctx.shadowColor = 'red';
+    ctx.shadowOffsetX = -15;
+    ctx.shadowOffsetY = 0;
+    ctx.font = '128px sans-serif';
+    ctx.strokeText("I", 0, 50);
+    
+    assert_array_equals(ctx.getImageData(0, 0, 1, 1).data, [0, 128, 0, 255]);
+}, "Test that strokeText() doesn't produce a filled shadow.");
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient-expected.txt
deleted file mode 100644
index 66abbc42..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Series of tests to ensure that strokeText() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient.html
index 0dff8ad..01e20eea8 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-strokeText-zeroSizeGradient.html
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/canvas-strokeText-zeroSizeGradient.js"></script>
+<script>
+test(function(t) {
+    var ctx = document.createElement('canvas').getContext('2d');
+    
+    ctx.fillStyle = '#0f0';
+    ctx.fillRect(0, 0, 1, 1);
+    
+    var g = ctx.createLinearGradient(0, 0, 0, 0); // zero-length line (undefined direction);
+    g.addColorStop(0, '#f00');
+    g.addColorStop(1, '#f00');
+    ctx.strokeStyle = g;
+    ctx.font = '1px sans-serif';
+    ctx.strokeText("AA", 0, 1);
+
+    assert_array_equals(ctx.getImageData(0, 0, 1, 1).data.slice(0,3), [0, 255, 0]);
+}, "Series of tests to ensure that strokeText() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.");
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
deleted file mode 100644
index 2c3f0ba..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
+++ /dev/null
@@ -1,153 +0,0 @@
-description("Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.");
-
-function print(message, color)
-{
-    var paragraph = document.createElement("div");
-    paragraph.appendChild(document.createTextNode(message));
-    paragraph.style.fontFamily = "monospace";
-    if (color)
-        paragraph.style.color = color;
-    document.getElementById("console").appendChild(paragraph);
-}
-
-function shouldBeAround(a, b)
-{
-    var evalA;
-    try {
-        evalA = eval(a);
-    } catch(e) {
-        evalA = e;
-    }
-
-    if (Math.abs(evalA - b) < 20)
-        print("PASS " + a + " is around " + b , "green")
-    else
-        print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
-}
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '600');
-canvas.setAttribute('height', '600');
-var ctx = canvas.getContext('2d');
-
-ctx.scale(2, 2);
-ctx.shadowOffsetX = 100;
-ctx.shadowOffsetY = 100;
-ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
-ctx.lineWidth = 5;
-
-ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
-ctx.beginPath();
-ctx.moveTo(50, 50);
-ctx.lineTo(100, 50);
-ctx.lineTo(100, 100);
-ctx.lineTo(50, 100);
-ctx.lineTo(50, 50);
-ctx.stroke();
-
-ctx.shadowColor = 'rgba(255, 0, 0, 0.3)';
-ctx.beginPath();
-ctx.moveTo(50, 150);
-ctx.lineTo(100, 150);
-ctx.lineTo(100, 200);
-ctx.lineTo(50, 200);
-ctx.lineTo(50, 150);
-ctx.stroke();
-
-ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
-ctx.shadowBlur = 10;
-ctx.beginPath();
-ctx.moveTo(150, 50);
-ctx.lineTo(200, 50);
-ctx.lineTo(200, 100);
-ctx.lineTo(150, 100);
-ctx.lineTo(150, 50);
-ctx.stroke();
-
-ctx.shadowColor = 'rgba(255, 0, 0, 0.6)';
-ctx.beginPath();
-ctx.moveTo(150, 150);
-ctx.lineTo(200, 150);
-ctx.lineTo(200, 200);
-ctx.lineTo(150, 200);
-ctx.lineTo(150, 150);
-ctx.stroke();
-
-var d; // imageData.data
-
-// Verify solid shadow.
-d = ctx.getImageData(250, 200, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBe('d[3]', '255');
-
-d = ctx.getImageData(300, 290, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBe('d[3]', '255');
-
-d = ctx.getImageData(200, 250, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBe('d[3]', '255');
-
-// Verify solid alpha shadow.
-d = ctx.getImageData(201, 405, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '76');
-
-d = ctx.getImageData(201, 500, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '76');
-
-d = ctx.getImageData(300, 499, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '76');
-
-// Verify blurry shadow.
-d = ctx.getImageData(398, 210, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '200');
-
-d = ctx.getImageData(508, 250, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '49');
-
-d = ctx.getImageData(450, 198, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '199');
-
-// Verify blurry alpha shadow.
-d = ctx.getImageData(505, 450, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '70');
-
-d = ctx.getImageData(505, 450, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '70');
-
-d = ctx.getImageData(450, 405, 1, 1).data;
-shouldBe('d[0]', '255');
-shouldBe('d[1]', '0');
-shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '69');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-set-properties-with-non-invertible-ctm.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-set-properties-with-non-invertible-ctm.js
deleted file mode 100644
index a1955b5..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-set-properties-with-non-invertible-ctm.js
+++ /dev/null
@@ -1,68 +0,0 @@
-description("Tests to make sure we can assign to non-ctm effected properties with a non-invertible ctm set");
-var canvas = document.createElement("canvas");
-canvas.width = 100;
-canvas.height = 100;
-var ctx = canvas.getContext('2d');
-document.body.appendChild(canvas);
-
-function testPixel(x,y, r, g, b) {
-    imageData = ctx.getImageData(x, y, 1, 1);
-    shouldBe("imageData.data[0]", ""+r);
-    shouldBe("imageData.data[1]", ""+g);
-    shouldBe("imageData.data[2]", ""+b);
-}
-
-// Test our ability to set fillStyle
-ctx.save();
-ctx.scale(0, 0);
-ctx.fillStyle = "green";
-shouldBe('ctx.fillStyle', '"#008000"');
-ctx.setTransform(1, 0, 0, 1, 0, 0);
-ctx.fillRect(0,0,100,100);
-testPixel(50, 50, 0, 128, 0);
-ctx.restore();
-
-// Test our ability to set strokeStyle
-ctx.save();
-ctx.fillStyle = "red";
-ctx.fillRect(0,0,100,100);
-ctx.scale(0, 0);
-ctx.strokeStyle = "green";
-shouldBe('ctx.strokeStyle', '"#008000"');
-ctx.lineWidth = 100;
-ctx.setTransform(1, 0, 0, 1, 0, 0);
-ctx.strokeRect(0,0,100,100);
-testPixel(50, 50, 0, 128, 0);
-ctx.restore();
-
-
-// test closePath
-ctx.save();
-ctx.fillStyle = "red";
-ctx.fillRect(0,0,100,100);
-
-ctx.beginPath();
-ctx.strokeStyle = "green";
-ctx.lineWidth = 100;
-ctx.moveTo(-100,   50);
-ctx.lineTo(-100, -100);
-ctx.lineTo( 200, -100);
-ctx.lineTo( 200,   50);
-ctx.scale(0, 0);
-ctx.closePath();
-ctx.setTransform(1, 0, 0, 1, 0, 0);
-ctx.stroke();
-ctx.restore();
-testPixel(50, 50, 0, 128, 0);
-
-// Test beginPath behaviour
-ctx.fillStyle = "green";
-ctx.fillRect(0,0,100,100);
-ctx.fillStyle = "red";
-ctx.rect(0,0,100,100);
-ctx.scale(0,0);
-ctx.beginPath();
-ctx.setTransform(1, 0, 0, 1, 0, 0);
-ctx.fill();
-
-testPixel(50, 50, 0, 128, 0);
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-setTransform.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-setTransform.js
deleted file mode 100644
index e2768bc3..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-setTransform.js
+++ /dev/null
@@ -1,97 +0,0 @@
-description("Series of tests to ensure correct behaviour of canvas.setTransform()");
-var ctx = document.createElement('canvas').getContext('2d');
-
-debug("Reset the CTM to the initial matrix");
-ctx.beginPath();
-ctx.scale(0.5, 0.5);
-ctx.setTransform(1, 0, 0, 1, 0, 0);
-ctx.fillStyle = 'green';
-ctx.fillRect(0, 0, 100, 100);
-
-var imageData = ctx.getImageData(1, 1, 98, 98);
-var imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-debug("setTransform should not affect the current path");
-ctx.beginPath();
-ctx.rect(0,0,100,100);
-ctx.save();
-ctx.setTransform(0.5, 0, 0, 0.5, 10, 10);
-ctx.fillStyle = 'red';
-ctx.fillRect(0, 0, 100, 100);
-ctx.restore();
-ctx.fillStyle = 'green';
-ctx.fillRect(0, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-debug("setTransform should not affect the CTM outside of save() and restore()");
-ctx.beginPath();
-ctx.fillStyle = 'green';
-ctx.save();
-ctx.setTransform(0.5, 0, 0, 0.5, 0, 0);
-ctx.fillStyle = 'red';
-ctx.fillRect(0, 0, 100, 100);
-ctx.restore();
-ctx.fillRect(0, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-
-debug("stop drawing on not-invertible CTM");
-ctx.beginPath();
-ctx.fillStyle = 'green';
-ctx.fillRect(0, 0, 100, 100);
-ctx.setTransform(0, 0, 0, 0, 0, 0);
-ctx.fillStyle = 'red';
-ctx.fillRect(0, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-debug("setTransform with a not-invertible matrix should only stop the drawing up to the next restore()");
-ctx.beginPath();
-ctx.resetTransform();
-ctx.save();
-ctx.setTransform(0, 0, 0, 0, 0, 0);
-ctx.fillStyle = 'red';
-ctx.fillRect(0, 0, 100, 100);
-ctx.restore();
-ctx.fillStyle = 'blue';
-ctx.fillRect(0, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "0");
-shouldBe("imgdata[6]", "255");
-
-debug("setTransform should set transform although CTM is not-invertible");
-ctx.beginPath();
-ctx.fillStyle = 'red';
-ctx.fillRect(0, 0, 100, 100);
-ctx.setTransform(0, 0, 0, 0, 0, 0);
-ctx.fillStyle = 'green';
-ctx.fillRect(0, 0, 100, 100);
-ctx.setTransform(1, 0, 0, 1, 0, 0);
-ctx.fillStyle = 'blue';
-ctx.fillRect(0, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "0");
-shouldBe("imgdata[6]", "255");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-shadow.js
deleted file mode 100644
index 673d7c1..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-shadow.js
+++ /dev/null
@@ -1,32 +0,0 @@
-description("Some tests for Canvas shadows");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = "green";
-ctx.fillRect(0,0,100,100);
-
-ctx.shadowColor = "green";
-ctx.shadowOffsetX = 0;
-ctx.shadowOffsetY = 0;
-ctx.shadowBlur = 0;
-
-var imageData = ctx.getImageData(0, 0, 200, 50);
-var imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-ctx.clearRect(0,0,200,50);
-
-ctx.shadowColor = "green";
-ctx.shadowOffsetX = 100;
-ctx.shadowOffsetY = 0;
-ctx.shadowBlur = 2;
-
-ctx.fillStyle = "green";
-ctx.fillRect(0,0,100,50);
-
-imageData = ctx.getImageData(110, 10, 80, 30);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-state-intact-after-putImageData.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-state-intact-after-putImageData.js
deleted file mode 100644
index 50282df..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-state-intact-after-putImageData.js
+++ /dev/null
@@ -1,38 +0,0 @@
-description("Test that the rendering context state is intact after a call to putImageData()");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = 'red';
-ctx.fillRect(0, 0, 1, 1);
-
-debug("Checking initial state for sanity");
-var imageData = ctx.getImageData(0, 0, 2, 1);
-var imgdata = imageData.data;
-shouldBe("ctx.fillStyle", "'#ff0000'");
-shouldBe("imgdata[0]", "255");
-shouldBe("imgdata[1]", "0");
-shouldBe("imgdata[2]", "0");
-shouldBe("imgdata[3]", "255");
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "0");
-shouldBe("imgdata[6]", "0");
-shouldBe("imgdata[7]", "0");
-
-debug("Calling putImageData()");
-ctx.putImageData(imageData, 1, 1);
-imageData = ctx.getImageData(1, 1, 1, 1);
-imgdata = imageData.data;
-shouldBe("imgdata[0]", "255");
-shouldBe("imgdata[1]", "0");
-shouldBe("imgdata[2]", "0");
-shouldBe("imgdata[3]", "255");
-
-debug("Checking if state is intact");
-shouldBe("ctx.fillStyle", "'#ff0000'");
-
-ctx.fillRect(2, 2, 1, 1);
-imageData = ctx.getImageData(2, 2, 1, 1);
-imgdata = imageData.data;
-shouldBe("imgdata[0]", "255");
-shouldBe("imgdata[1]", "0");
-shouldBe("imgdata[2]", "0");
-shouldBe("imgdata[3]", "255");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-stroke-zeroSizeGradient.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-stroke-zeroSizeGradient.js
deleted file mode 100644
index febdf1e8..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-stroke-zeroSizeGradient.js
+++ /dev/null
@@ -1,18 +0,0 @@
-description("Series of tests to ensure that stroke() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 1, 1);
-
-var g = ctx.createLinearGradient(0, 0, 0, 0); // zero-length line (undefined direction);
-g.addColorStop(0, '#f00');
-g.addColorStop(1, '#f00');
-ctx.strokeStyle = g;
-ctx.rect(0, 0, 1 ,1);
-ctx.stroke();
-
-var imageData = ctx.getImageData(0, 0, 1, 1);
-var imgdata = imageData.data;
-shouldBe("imgdata[0]", "0");
-shouldBe("imgdata[1]", "255");
-shouldBe("imgdata[2]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-alpha-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-alpha-shadow.js
deleted file mode 100644
index e438fe7..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-alpha-shadow.js
+++ /dev/null
@@ -1,113 +0,0 @@
-description("Ensure correct behavior of canvas with path stroke using a strokeStyle color with alpha and a shadow");
-
-function print(message, color)
-{
-    var paragraph = document.createElement("div");
-    paragraph.appendChild(document.createTextNode(message));
-    paragraph.style.fontFamily = "monospace";
-    if (color)
-        paragraph.style.color = color;
-    document.getElementById("console").appendChild(paragraph);
-}
-
-function shouldBeAround(a, b)
-{
-    var evalA;
-    try {
-        evalA = eval(a);
-    } catch(e) {
-        evalA = e;
-    }
-
-    if (Math.abs(evalA - b) < 15)
-        print("PASS " + a + " is around " + b , "green")
-    else
-        print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
-}
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '600');
-canvas.setAttribute('height', '1100');
-var ctx = canvas.getContext('2d');
-
-ctx.save();
-ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
-ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
-ctx.shadowOffsetX = 250;
-ctx.lineWidth = 50;
-
-function strokePath(x, y) {
-    ctx.beginPath();
-    ctx.arc(x, y, 75, 0, Math.PI*2, true);
-    ctx.stroke();
-}
-
-// Alpha shadow.
-ctx.shadowBlur = 0;
-strokePath(150, 150);
-
-// Blurry shadow.
-ctx.shadowBlur = 10;
-strokePath(150, 400);
-
-ctx.rotate(Math.PI/2);
-
-// Rotated alpha shadow.
-ctx.shadowBlur = 0;
-strokePath(650, -150);
-
-// Rotated blurry shadow.
-ctx.shadowBlur = 10;
-strokePath(900, -150);
-
-ctx.restore();
-
-var imageData, data;
-ctx.fillStyle = 'black';
-
-function test(alphaTestFunction, x, y, r, g, b, a) {
-    // Get pixel.
-    imageData = ctx.getImageData(x, y, 1, 1);
-    data = imageData.data;
-    // Test pixel color components.
-    shouldBe('data[0]', r+'');
-    shouldBe('data[1]', g+'');
-    shouldBe('data[2]', b+'');
-    alphaTestFunction('data[3]', a+'');
-    // Plot test point.
-    ctx.fillRect(x, y, 3, 3);
-}
-
-print('Verifying alpha shadow...');
-test(shouldBe, 400, 150, 0, 0, 0, 0);
-test(shouldBeAround, 400, 75, 255,  0, 0, 64);
-test(shouldBeAround, 400, 225, 255, 0, 0, 64);
-test(shouldBeAround, 325, 150, 255, 0, 0, 64);
-test(shouldBeAround, 475, 150, 255, 0, 0, 64);
-
-print(' ');
-print('Verifying blurry shadow...');
-test(shouldBe, 400, 400, 0, 0, 0, 0);
-test(shouldBeAround, 400, 300, 255, 0, 0, 31);
-test(shouldBeAround, 400, 500, 255, 0, 0, 31);
-test(shouldBeAround, 300, 400, 255, 0, 0, 31);
-test(shouldBeAround, 500, 400, 255, 0, 0, 31);
-
-print(' ');
-print('Verifying rotated alpha shadow...');
-test(shouldBe, 400, 650, 0, 0, 0, 0);
-test(shouldBeAround, 400, 575, 255, 0, 0, 64);
-test(shouldBeAround, 400, 725, 255, 0, 0, 64);
-test(shouldBeAround, 325, 650, 255, 0, 0, 64);
-test(shouldBeAround, 475, 650, 255, 0, 0, 64);
-
-print(' ');
-print('Verifying rotated blurry shadow...');
-test(shouldBe, 400, 900, 0, 0, 0, 0);
-test(shouldBeAround, 400, 800, 255, 0, 0, 31);
-test(shouldBeAround, 400, 1000, 255, 0, 0, 31);
-test(shouldBeAround, 300, 900, 255, 0, 0, 31);
-test(shouldBeAround, 500, 900, 255, 0, 0, 31);
-
-print(' ');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-cap-join.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-cap-join.js
deleted file mode 100644
index ff6c609b..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-cap-join.js
+++ /dev/null
@@ -1,252 +0,0 @@
-description("Ensure correct behavior of canvas with path stroke with cap and join");
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '700');
-canvas.setAttribute('height', '200');
-var ctx = canvas.getContext('2d');
-
-ctx.miterLimit = 5;
-ctx.lineWidth = 15;
-
-ctx.fillStyle="rgba(255, 255, 255, 1.0)";
-ctx.fillRect(0, 0, 700, 200);
-
-ctx.strokeStyle="rgba(0, 0, 0, 1.0)";
-ctx.lineJoin = "miter";
-ctx.lineCap = "round";
-
-ctx.translate(0, 50);
-ctx.save();
-
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 2);
-ctx.lineTo(50, 100);
-ctx.stroke();
-
-ctx.translate(60 ,0);
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 3);
-ctx.lineTo(50, 100);
-ctx.stroke();
-
-ctx.translate(90 ,0);
-ctx.save();
-ctx.rotate(0.2);
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 3);
-ctx.lineTo(50, 100);
-ctx.closePath();
-ctx.stroke();
-ctx.restore();
-
-ctx.restore();
-
-ctx.lineJoin = "bevel";
-ctx.lineCap = "square";
-
-ctx.translate(200, 0);
-ctx.save();
-
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 2);
-ctx.lineTo(50, 100);
-ctx.stroke();
-
-ctx.translate(60 ,0);
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 3);
-ctx.lineTo(50, 100);
-ctx.stroke();
-
-ctx.translate(90 ,0);
-ctx.save();
-ctx.rotate(0.2);
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 3);
-ctx.lineTo(50, 100);
-ctx.closePath();
-ctx.stroke();
-ctx.restore();
-
-ctx.restore();
-
-ctx.lineJoin = "round";
-ctx.lineCap = "butt";
-
-ctx.translate(200, 0);
-ctx.save();
-
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 2);
-ctx.lineTo(50, 100);
-ctx.stroke();
-
-ctx.translate(60 ,0);
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 3);
-ctx.lineTo(50, 100);
-ctx.stroke();
-
-ctx.translate(90 ,0);
-ctx.save();
-ctx.rotate(0.2);
-ctx.beginPath();
-ctx.moveTo(10, 100);
-ctx.lineTo(30, 3);
-ctx.lineTo(50, 100);
-ctx.closePath();
-ctx.stroke();
-ctx.restore();
-
-ctx.restore();
-
-var imageData, data;
-
-// Verify Join : miter, Cap : round.
-imageData = ctx.getImageData(30, 51, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(30, 49, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(14, 154, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(14, 157, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(89, 22, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(89, 12, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(184, 29, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(180, 27, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(132, 152, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(130, 157, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-// Verify Join : bevel, Cap : square.
-imageData = ctx.getImageData(202, 154, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(201, 150, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(228, 52, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(225, 48, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(316, 154, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(316, 157, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(289, 52, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(289, 48, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(372, 58, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(373, 54, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(380, 159, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(383, 162, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-// Verify Join : round, Cap : butt.
-imageData = ctx.getImageData(405, 147, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(405, 151, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(429, 46, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(429, 43, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(464, 146, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(464, 150, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(489, 46, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(489, 43, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(534, 151, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(531, 153, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
-imageData = ctx.getImageData(579, 52, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '0');
-
-imageData = ctx.getImageData(579, 48, 1, 1);
-data = imageData.data;
-shouldBe('data[0]', '255');
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-gradient-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-gradient-shadow.js
deleted file mode 100644
index 560c552..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-gradient-shadow.js
+++ /dev/null
@@ -1,162 +0,0 @@
-description("Ensure correct behavior of canvas with strokePath using a gradient strokeStyle and a shadow");
-
-function print(message, color)
-{
-    var paragraph = document.createElement("div");
-    paragraph.appendChild(document.createTextNode(message));
-    paragraph.style.fontFamily = "monospace";
-    if (color)
-        paragraph.style.color = color;
-    document.getElementById("console").appendChild(paragraph);
-}
-
-function shouldBeAround(a, b)
-{
-    var evalA;
-    try {
-        evalA = eval(a);
-    } catch(e) {
-        evalA = e;
-    }
-
-    if (Math.abs(evalA - b) < 15)
-        print("PASS " + a + " is around " + b , "green")
-    else
-        print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
-}
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '600');
-canvas.setAttribute('height', '1100');
-var ctx = canvas.getContext('2d');
-
-var gradient = ctx.createLinearGradient(0, 0, 300, 0);
-gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
-gradient.addColorStop(1, 'rgba(0, 0, 255, 0.5)');
-
-ctx.save();
-ctx.strokeStyle = gradient;
-ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
-ctx.shadowOffsetX = 250;
-ctx.lineWidth = 25;
-
-var side = 200;
-
-// Alpha shadow.
-ctx.shadowBlur = 0;
-ctx.beginPath();
-ctx.rect(50, 50, side, side);
-ctx.stroke();
-
-// Blurry shadow.
-ctx.shadowBlur = 10;
-ctx.beginPath();
-ctx.rect(50, 300, side, side);
-ctx.stroke();
-
-ctx.rotate(Math.PI / 2);
-
-// Rotated alpha shadow.
-ctx.shadowBlur = 0;
-ctx.beginPath();
-ctx.rect(550, -250, side, side);
-ctx.stroke();
-
-// Rotated blurry shadow.
-ctx.shadowBlur = 10;
-ctx.beginPath();
-ctx.rect(800, -250, side, side);
-ctx.stroke();
-
-ctx.restore();
-
-var imageData, data;
-ctx.fillStyle = 'black';
-
-function test(alphaTestFunction, x, y, r, g, b, a) {
-    // Get pixel.
-    imageData = ctx.getImageData(x, y, 1, 1);
-    data = imageData.data;
-    // Test pixel color components.
-    shouldBe('data[0]', r+'');
-    shouldBe('data[1]', g+'');
-    shouldBe('data[2]', b+'');
-    alphaTestFunction('data[3]', a+'');
-    // Plot test point.
-    ctx.fillRect(x, y, 3, 3);
-}
-
-print('Verifying alpha shadow...');
-test(shouldBe, 400, 150, 0, 0, 0, 0);
-
-test(shouldBe, 400, 75,  0, 0, 0, 0);
-test(shouldBe, 400, 225, 0, 0, 0, 0);
-test(shouldBe, 325, 150, 0, 0, 0, 0);
-test(shouldBe, 475, 150, 0, 0, 0, 0);
-
-test(shouldBeAround, 400,  50, 255, 0, 0, 64);
-test(shouldBeAround, 500, 150, 255, 0, 0, 64);
-test(shouldBeAround, 400, 250, 255, 0, 0, 64);
-test(shouldBeAround, 300, 150, 255, 0, 0, 64);
-
-test(shouldBe, 400, 25,  0, 0, 0, 0);
-test(shouldBe, 525, 150, 0, 0, 0, 0);
-test(shouldBe, 400, 275, 0, 0, 0, 0);
-test(shouldBe, 275, 150, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying blurry shadow...');
-test(shouldBe, 400, 400, 0, 0, 0, 0);
-
-test(shouldBe, 400, 325, 0, 0, 0, 0);
-test(shouldBe, 475, 400, 0, 0, 0, 0);
-test(shouldBe, 400, 475, 0, 0, 0, 0);
-test(shouldBe, 325, 400, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 300, 255, 0, 0, 64);
-test(shouldBeAround, 400, 500, 255, 0, 0, 64);
-test(shouldBeAround, 300, 400, 255, 0, 0, 64);
-test(shouldBeAround, 500, 400, 255, 0, 0, 64);
-
-test(shouldBe, 525, 400, 0, 0, 0, 0);
-test(shouldBe, 275, 400, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying rotated alpha shadow...');
-test(shouldBe, 400, 650, 0, 0, 0, 0);
-
-test(shouldBe, 400, 575, 0, 0, 0, 0);
-test(shouldBe, 400, 725, 0, 0, 0, 0);
-test(shouldBe, 325, 650, 0, 0, 0, 0);
-test(shouldBe, 475, 650, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 550, 255, 0, 0, 64);
-test(shouldBeAround, 500, 650, 255, 0, 0, 64);
-test(shouldBeAround, 400, 750, 255, 0, 0, 64);
-test(shouldBeAround, 300, 650, 255, 0, 0, 64);
-
-test(shouldBe, 400, 525, 0, 0, 0, 0);
-test(shouldBe, 525, 650, 0, 0, 0, 0);
-test(shouldBe, 400, 775, 0, 0, 0, 0);
-test(shouldBe, 275, 650, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying rotated blurry shadow...');
-test(shouldBe, 400, 900, 0, 0, 0, 0);
-
-test(shouldBe, 400, 825, 0, 0, 0, 0);
-test(shouldBe, 475, 900, 0, 0, 0, 0);
-test(shouldBe, 400, 975, 0, 0, 0, 0);
-test(shouldBe, 325, 900, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 800,  255, 0, 0, 64);
-test(shouldBeAround, 400, 1000, 255, 0, 0, 64);
-test(shouldBeAround, 300, 900,  255, 0, 0, 64);
-test(shouldBeAround, 500, 900,  255, 0, 0, 64);
-
-test(shouldBe, 525, 900,  0, 0, 0, 0);
-test(shouldBe, 275, 900,  0, 0, 0, 0);
-test(shouldBe, 400, 1025, 0, 0, 0, 0);
-
-print(' ');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-shadow.js
deleted file mode 100644
index 01f43c17..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokePath-shadow.js
+++ /dev/null
@@ -1,105 +0,0 @@
-description("Ensure correct behavior of canvas with path stroke shadow");
-
-function print(message, color)
-{
-    var paragraph = document.createElement("div");
-    paragraph.appendChild(document.createTextNode(message));
-    paragraph.style.fontFamily = "monospace";
-    if (color)
-        paragraph.style.color = color;
-    document.getElementById("console").appendChild(paragraph);
-}
-
-// Level of tolerance we expect of most pixel comparisons in this test.
-function shouldBeAlmost(_a, _b)
-{
-    shouldBeCloseTo(_a, _b, 2);
-}
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '700');
-canvas.setAttribute('height', '700');
-var ctx = canvas.getContext('2d');
-
-ctx.beginPath();
-ctx.moveTo(300, 300);
-ctx.lineTo(300, 50);
-ctx.bezierCurveTo(200, 40, 75, 150, 30, 30);
-ctx.quadraticCurveTo(250, 75, 50, 300);
-ctx.shadowOffsetX = 350;
-ctx.shadowColor = 'rgba(255, 20, 0, 0.5)';
-ctx.shadowBlur = 0;
-ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
-ctx.lineWidth = 30;
-ctx.closePath();
-ctx.stroke();
-
-ctx.beginPath();
-ctx.moveTo(300,650);
-ctx.lineTo(300,400);
-ctx.bezierCurveTo(200, 390, 75, 500, 30, 380);
-ctx.quadraticCurveTo(250, 425, 50, 650);
-ctx.shadowOffsetX = 350;
-ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
-ctx.shadowBlur = 30;
-ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
-ctx.lineWidth = 30;
-ctx.closePath();
-ctx.stroke();
-
-var imageData, data;
-
-// Verify solid shadow.
-imageData = ctx.getImageData(650, 300, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 20);
-shouldBeAlmost('data[2]', 0);
-
-imageData = ctx.getImageData(650, 50, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 20);
-shouldBeAlmost('data[2]', 0);
-
-imageData = ctx.getImageData(380, 30, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 20);
-shouldBeAlmost('data[2]', 0);
-
-imageData = ctx.getImageData(400, 40, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 20);
-shouldBeAlmost('data[2]', 0);
-
-// Verify blurry shadow.
-imageData = ctx.getImageData(640, 640, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 0);
-shouldBeAlmost('data[2]', 0);
-shouldNotBe('data[3]', '255');
-
-imageData = ctx.getImageData(650, 400, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 0);
-shouldBeAlmost('data[2]', 0);
-shouldNotBe('data[3]', '255');
-
-imageData = ctx.getImageData(380, 380, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 0);
-shouldBeAlmost('data[2]', 0);
-shouldNotBe('data[3]', '255');
-
-imageData = ctx.getImageData(350, 380, 1, 1);
-data = imageData.data;
-shouldBeAlmost('data[0]', 255);
-shouldBeAlmost('data[1]', 0);
-shouldBeAlmost('data[2]', 0);
-shouldNotBe('data[3]', '255');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-alpha-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-alpha-shadow.js
deleted file mode 100644
index f3fdfb2..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-alpha-shadow.js
+++ /dev/null
@@ -1,150 +0,0 @@
-description("Ensure correct behavior of canvas with strokeRect using a semi-transparent solid strokeStyle and a shadow");
-
-function print(message, color)
-{
-    var paragraph = document.createElement("div");
-    paragraph.appendChild(document.createTextNode(message));
-    paragraph.style.fontFamily = "monospace";
-    if (color)
-        paragraph.style.color = color;
-    document.getElementById("console").appendChild(paragraph);
-}
-
-function shouldBeAround(a, b)
-{
-    var evalA;
-    try {
-        evalA = eval(a);
-    } catch(e) {
-        evalA = e;
-    }
-
-    if (Math.abs(evalA - b) < 15)
-        print("PASS " + a + " is around " + b , "green")
-    else
-        print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
-}
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '600');
-canvas.setAttribute('height', '1100');
-var ctx = canvas.getContext('2d');
-
-ctx.save();
-ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
-ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
-ctx.shadowOffsetX = 250;
-ctx.lineWidth = 25;
-
-var side = 200;
-
-// Alpha shadow.
-ctx.shadowBlur = 0;
-ctx.strokeRect(50, 50, side, side);
-
-// Blurry shadow.
-ctx.shadowBlur = 10;
-ctx.strokeRect(50, 300, side, side);
-
-ctx.rotate(Math.PI / 2);
-
-// Rotated alpha shadow.
-ctx.shadowBlur = 0;
-ctx.strokeRect(550, -250, side, side);
-
-// Rotated blurry shadow.
-ctx.shadowBlur = 10;
-ctx.strokeRect(800, -250, side, side);
-
-ctx.restore();
-
-var imageData, data;
-ctx.fillStyle = 'black';
-
-function test(alphaTestFunction, x, y, r, g, b, a) {
-    // Get pixel.
-    imageData = ctx.getImageData(x, y, 1, 1);
-    data = imageData.data;
-    // Test pixel color components.
-    shouldBe('data[0]', r+'');
-    shouldBe('data[1]', g+'');
-    shouldBe('data[2]', b+'');
-    alphaTestFunction('data[3]', a+'');
-    // Plot test point.
-    ctx.fillRect(x, y, 3, 3);
-}
-
-print('Verifying alpha shadow...');
-test(shouldBe, 400, 150, 0, 0, 0, 0);
-
-test(shouldBe, 400, 75,  0, 0, 0, 0);
-test(shouldBe, 400, 225, 0, 0, 0, 0);
-test(shouldBe, 325, 150, 0, 0, 0, 0);
-test(shouldBe, 475, 150, 0, 0, 0, 0);
-
-test(shouldBeAround, 400,  50, 255, 0, 0, 64);
-test(shouldBeAround, 500, 150, 255, 0, 0, 64);
-test(shouldBeAround, 400, 250, 255, 0, 0, 64);
-test(shouldBeAround, 300, 150, 255, 0, 0, 64);
-
-test(shouldBe, 400, 25,  0, 0, 0, 0);
-test(shouldBe, 525, 150, 0, 0, 0, 0);
-test(shouldBe, 400, 275, 0, 0, 0, 0);
-test(shouldBe, 275, 150, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying blurry shadow...');
-test(shouldBe, 400, 400, 0, 0, 0, 0);
-
-test(shouldBe, 400, 325, 0, 0, 0, 0);
-test(shouldBe, 475, 400, 0, 0, 0, 0);
-test(shouldBe, 400, 475, 0, 0, 0, 0);
-test(shouldBe, 325, 400, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 300, 255, 0, 0, 64);
-test(shouldBeAround, 400, 500, 255, 0, 0, 64);
-test(shouldBeAround, 300, 400, 255, 0, 0, 64);
-test(shouldBeAround, 500, 400, 255, 0, 0, 64);
-
-test(shouldBe, 525, 400, 0, 0, 0, 0);
-test(shouldBe, 275, 400, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying rotated alpha shadow...');
-test(shouldBe, 400, 650, 0, 0, 0, 0);
-
-test(shouldBe, 400, 575, 0, 0, 0, 0);
-test(shouldBe, 400, 725, 0, 0, 0, 0);
-test(shouldBe, 325, 650, 0, 0, 0, 0);
-test(shouldBe, 475, 650, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 550, 255, 0, 0, 64);
-test(shouldBeAround, 500, 650, 255, 0, 0, 64);
-test(shouldBeAround, 400, 750, 255, 0, 0, 64);
-test(shouldBeAround, 300, 650, 255, 0, 0, 64);
-
-test(shouldBe, 400, 525, 0, 0, 0, 0);
-test(shouldBe, 525, 650, 0, 0, 0, 0);
-test(shouldBe, 400, 775, 0, 0, 0, 0);
-test(shouldBe, 275, 650, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying rotated blurry shadow...');
-test(shouldBe, 400, 900, 0, 0, 0, 0);
-
-test(shouldBe, 400, 825, 0, 0, 0, 0);
-test(shouldBe, 475, 900, 0, 0, 0, 0);
-test(shouldBe, 400, 975, 0, 0, 0, 0);
-test(shouldBe, 325, 900, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 800,  255, 0, 0, 64);
-test(shouldBeAround, 400, 1000, 255, 0, 0, 64);
-test(shouldBeAround, 300, 900,  255, 0, 0, 64);
-test(shouldBeAround, 500, 900,  255, 0, 0, 64);
-
-test(shouldBe, 525, 900,  0, 0, 0, 0);
-test(shouldBe, 275, 900,  0, 0, 0, 0);
-test(shouldBe, 400, 1025, 0, 0, 0, 0);
-
-print(' ');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-gradient-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-gradient-shadow.js
deleted file mode 100644
index 9a4e820..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-gradient-shadow.js
+++ /dev/null
@@ -1,154 +0,0 @@
-description("Ensure correct behavior of canvas with strokeRect using a gradient strokeStyle and a shadow");
-
-function print(message, color)
-{
-    var paragraph = document.createElement("div");
-    paragraph.appendChild(document.createTextNode(message));
-    paragraph.style.fontFamily = "monospace";
-    if (color)
-        paragraph.style.color = color;
-    document.getElementById("console").appendChild(paragraph);
-}
-
-function shouldBeAround(a, b)
-{
-    var evalA;
-    try {
-        evalA = eval(a);
-    } catch(e) {
-        evalA = e;
-    }
-
-    if (Math.abs(evalA - b) < 15)
-        print("PASS " + a + " is around " + b , "green")
-    else
-        print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
-}
-
-var canvas = document.createElement('canvas');
-document.body.appendChild(canvas);
-canvas.setAttribute('width', '600');
-canvas.setAttribute('height', '1100');
-var ctx = canvas.getContext('2d');
-
-var gradient = ctx.createLinearGradient(0, 0, 300, 0);
-gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
-gradient.addColorStop(1, 'rgba(0, 0, 255, 0.5)');
-
-ctx.save();
-ctx.strokeStyle = gradient;
-ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
-ctx.shadowOffsetX = 250;
-ctx.lineWidth = 25;
-
-var side = 200;
-
-// Alpha shadow.
-ctx.shadowBlur = 0;
-ctx.strokeRect(50, 50, side, side);
-
-// Blurry shadow.
-ctx.shadowBlur = 10;
-ctx.strokeRect(50, 300, side, side);
-
-ctx.rotate(Math.PI / 2);
-
-// Rotated alpha shadow.
-ctx.shadowBlur = 0;
-ctx.strokeRect(550, -250, side, side);
-
-// Rotated blurry shadow.
-ctx.shadowBlur = 10;
-ctx.strokeRect(800, -250, side, side);
-
-ctx.restore();
-
-var imageData, data;
-ctx.fillStyle = 'black';
-
-function test(alphaTestFunction, x, y, r, g, b, a) {
-    // Get pixel.
-    imageData = ctx.getImageData(x, y, 1, 1);
-    data = imageData.data;
-    // Test pixel color components.
-    shouldBe('data[0]', r+'');
-    shouldBe('data[1]', g+'');
-    shouldBe('data[2]', b+'');
-    alphaTestFunction('data[3]', a+'');
-    // Plot test point.
-    ctx.fillRect(x, y, 3, 3);
-}
-
-print('Verifying alpha shadow...');
-test(shouldBe, 400, 150, 0, 0, 0, 0);
-
-test(shouldBe, 400, 75,  0, 0, 0, 0);
-test(shouldBe, 400, 225, 0, 0, 0, 0);
-test(shouldBe, 325, 150, 0, 0, 0, 0);
-test(shouldBe, 475, 150, 0, 0, 0, 0);
-
-test(shouldBeAround, 400,  50, 255, 0, 0, 64);
-test(shouldBeAround, 500, 150, 255, 0, 0, 64);
-test(shouldBeAround, 400, 250, 255, 0, 0, 64);
-test(shouldBeAround, 300, 150, 255, 0, 0, 64);
-
-test(shouldBe, 400, 25,  0, 0, 0, 0);
-test(shouldBe, 525, 150, 0, 0, 0, 0);
-test(shouldBe, 400, 275, 0, 0, 0, 0);
-test(shouldBe, 275, 150, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying blurry shadow...');
-test(shouldBe, 400, 400, 0, 0, 0, 0);
-
-test(shouldBe, 400, 325, 0, 0, 0, 0);
-test(shouldBe, 475, 400, 0, 0, 0, 0);
-test(shouldBe, 400, 475, 0, 0, 0, 0);
-test(shouldBe, 325, 400, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 300, 255, 0, 0, 64);
-test(shouldBeAround, 400, 500, 255, 0, 0, 64);
-test(shouldBeAround, 300, 400, 255, 0, 0, 64);
-test(shouldBeAround, 500, 400, 255, 0, 0, 64);
-
-test(shouldBe, 525, 400, 0, 0, 0, 0);
-test(shouldBe, 275, 400, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying rotated alpha shadow...');
-test(shouldBe, 400, 650, 0, 0, 0, 0);
-
-test(shouldBe, 400, 575, 0, 0, 0, 0);
-test(shouldBe, 400, 725, 0, 0, 0, 0);
-test(shouldBe, 325, 650, 0, 0, 0, 0);
-test(shouldBe, 475, 650, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 550, 255, 0, 0, 64);
-test(shouldBeAround, 500, 650, 255, 0, 0, 64);
-test(shouldBeAround, 400, 750, 255, 0, 0, 64);
-test(shouldBeAround, 300, 650, 255, 0, 0, 64);
-
-test(shouldBe, 400, 525, 0, 0, 0, 0);
-test(shouldBe, 525, 650, 0, 0, 0, 0);
-test(shouldBe, 400, 775, 0, 0, 0, 0);
-test(shouldBe, 275, 650, 0, 0, 0, 0);
-
-print(' ');
-print('Verifying rotated blurry shadow...');
-test(shouldBe, 400, 900, 0, 0, 0, 0);
-
-test(shouldBe, 400, 825, 0, 0, 0, 0);
-test(shouldBe, 475, 900, 0, 0, 0, 0);
-test(shouldBe, 400, 975, 0, 0, 0, 0);
-test(shouldBe, 325, 900, 0, 0, 0, 0);
-
-test(shouldBeAround, 400, 800,  255, 0, 0, 64);
-test(shouldBeAround, 400, 1000, 255, 0, 0, 64);
-test(shouldBeAround, 300, 900,  255, 0, 0, 64);
-test(shouldBeAround, 500, 900,  255, 0, 0, 64);
-
-test(shouldBe, 525, 900,  0, 0, 0, 0);
-test(shouldBe, 275, 900,  0, 0, 0, 0);
-test(shouldBe, 400, 1025, 0, 0, 0, 0);
-
-print(' ');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-zeroSizeGradient.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-zeroSizeGradient.js
deleted file mode 100644
index 8aedab3..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect-zeroSizeGradient.js
+++ /dev/null
@@ -1,17 +0,0 @@
-description("Series of tests to ensure that strokeRect() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 1, 1);
-
-var g = ctx.createLinearGradient(0, 0, 0, 0); // zero-length line (undefined direction);
-g.addColorStop(0, '#f00');
-g.addColorStop(1, '#f00');
-ctx.strokeStyle = g;
-ctx.strokeRect(0, 0, 1 ,1);
-
-var imageData = ctx.getImageData(0, 0, 1, 1);
-var imgdata = imageData.data;
-shouldBe("imgdata[0]", "0");
-shouldBe("imgdata[1]", "255");
-shouldBe("imgdata[2]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect.js
deleted file mode 100644
index 75a6f5d..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeRect.js
+++ /dev/null
@@ -1,80 +0,0 @@
-description("Series of tests to ensure correct behaviour of canvas.strokeRect()");
-var ctx = document.createElement('canvas').getContext('2d');
-
-// stroke rect with solid green
-debug("Test canvas.strokeRect() with solid green.");
-ctx.beginPath();
-ctx.strokeStyle = 'green';
-ctx.lineWidth = 100;
-ctx.strokeRect(50, 0, 100, 100);
-
-var imageData = ctx.getImageData(1, 1, 98, 98);
-var imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-ctx.clearRect(0, 0, 100, 100);
-
-// stroke rect with a pattern
-debug("Test canvas.strokeRect() with a pattern.");
-var canvas2 = document.createElement('canvas');
-canvas2.width = 100;
-canvas2.height = 100;
-var ctx2 = canvas2.getContext('2d');
-ctx2.fillStyle = 'green';
-ctx2.fillRect(0, 0, 100, 100);
-var pattern = ctx.createPattern(canvas2, 'repeat');
-ctx.strokeStyle = 'pattern';
-ctx.lineWidth = 100;
-ctx.strokeRect(50, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-ctx.clearRect(0, 0, 100, 100);
-
-// stroke rect with gradient
-debug("Test canvas.strokeRect() with a gradient.");
-var gradient = ctx.createLinearGradient(0, 0, 0, 100);
-gradient.addColorStop(0, "green");
-gradient.addColorStop(1, "green");
-ctx.strokeStyle = 'gradient';
-ctx.lineWidth = 100;
-ctx.strokeRect(50, 0, 100, 100);
-
-imageData = ctx.getImageData(1, 1, 98, 98);
-imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "128");
-shouldBe("imgdata[6]", "0");
-
-ctx.clearRect(0, 0, 100, 100);
-
-// stroke rect with height = width = 0 and lineWidth = 2.
-debug("Test canvas.strokeRect() with height = width = 0 and lineWidth = 2.");
-ctx.strokeStyle = 'red';
-ctx.lineWidth = 2;
-ctx.strokeRect(0, 0, 0, 0);
-imageData = ctx.getImageData(0, 0, 1, 1);
-imgdata = imageData.data;
-shouldBe("imgdata[0]", "0");
-shouldBe("imgdata[1]", "0");
-shouldBe("imgdata[2]", "0");
-
-// stroke rect with height = width = 0, lineWidth = 2, and shadow.
-debug("Test canvas.strokeRect() with height = width = 0, lineWidth = 2, and shadow.");
-ctx.shadowOffsetX = 5;
-ctx.shadowOffsetY = 5;
-ctx.shadowColor = 'blue';
-ctx.strokeStyle = 'red';
-ctx.lineWidth = 2;
-ctx.strokeRect(0, 0, 0, 0);
-imageData = ctx.getImageData(0, 0, 1, 1);
-imgdata = imageData.data;
-shouldBe("imgdata[0]", "0");
-shouldBe("imgdata[1]", "0");
-shouldBe("imgdata[2]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-invalid-maxWidth.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-invalid-maxWidth.js
deleted file mode 100644
index 0c76a872..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-invalid-maxWidth.js
+++ /dev/null
@@ -1,46 +0,0 @@
-descriptionQuiet("Series of tests to ensure that strokeText() does not display any text when maxWidth is invalid.");
-
-var canvas = document.createElement('canvas');
-var ctx = canvas.getContext('2d');
-var canvasWidth = 100;
-var canvasHeight = 50;
-canvas.setWidth = canvasWidth;
-canvas.setHeight = canvasHeight;
-
-
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, canvasWidth, canvasHeight);
-ctx.font = '35px Arial, sans-serif';
-
-debug("Test canvas.strokeText() with maxWidth zero");
-ctx.strokeStyle = '#f00';
-ctx.strokeText("fail fail fail fail fail", 5, 35, 0);
-
-var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
-var w = imageData.width, h = imageData.height, d = imageData.data;
-for (var i = 0; i < h; ++i) {
-    for (var j = 0; j < w; ++j) {
-        if (d[4 * (w * i + j) + 0] != 0) shouldBe("d[4 * (w * i + j) + 0]", "0"); 
-        if (d[4 * (w * i + j) + 1] != 255) shouldBe("d[4 * (w * i + j) + 1]", "255"); 
-        if (d[4 * (w * i + j) + 2] != 0) shouldBe("d[4 * (w * i + j) + 2]", "0"); 
-        if (d[4 * (w * i + j) + 3] != 255) shouldBe("d[4 * (w * i + j) + 3]", "255");
-    }
-}
-
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, canvasWidth, canvasHeight);
-debug("Test canvas.strokeText() with maxWidth -1");
-ctx.strokeStyle = '#f00';
-ctx.strokeText("fail fail fail fail fail", 5, 35, -1);
-
-var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
-var w = imageData.width, h = imageData.height, d = imageData.data;
-for (var i = 0; i < h; ++i) {
-    for (var j = 0; j < w; ++j) {
-        if (d[4 * (w * i + j) + 0] != 0) shouldBe("d[4 * (w * i + j) + 0]", "0"); 
-        if (d[4 * (w * i + j) + 1] != 255) shouldBe("d[4 * (w * i + j) + 1]", "255"); 
-        if (d[4 * (w * i + j) + 2] != 0) shouldBe("d[4 * (w * i + j) + 2]", "0"); 
-        if (d[4 * (w * i + j) + 3] != 255) shouldBe("d[4 * (w * i + j) + 3]", "255");
-    }
-}
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-strokes-shadow.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-strokes-shadow.js
deleted file mode 100644
index ec0887e..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-strokes-shadow.js
+++ /dev/null
@@ -1,21 +0,0 @@
-description("Test that strokeText() doesn't produce a filled shadow.");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = 'green';
-ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
-
-// Stroke an 'I' with its shadow in the upper left corner.
-ctx.strokeStyle = 'white';
-ctx.lineWidth = 2;
-ctx.shadowColor = 'red';
-ctx.shadowOffsetX = -15;
-ctx.shadowOffsetY = 0;
-ctx.font = '128px sans-serif';
-ctx.strokeText("I", 0, 50);
-
-imageData = ctx.getImageData(0, 0, 1, 1);
-imgdata = imageData.data;
-shouldBe("imgdata[0]", "0");
-shouldBe("imgdata[1]", "128");
-shouldBe("imgdata[2]", "0");
-shouldBe("imgdata[3]", "255");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-zeroSizeGradient.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-zeroSizeGradient.js
deleted file mode 100644
index 722e1b1f..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-strokeText-zeroSizeGradient.js
+++ /dev/null
@@ -1,19 +0,0 @@
-description("Series of tests to ensure that strokeText() paints nothing on canvas when the strokeStyle is set to a zero-size gradient.");
-var ctx = document.createElement('canvas').getContext('2d');
-
-ctx.fillStyle = '#0f0';
-ctx.fillRect(0, 0, 1, 1);
-
-var g = ctx.createLinearGradient(0, 0, 0, 0); // zero-length line (undefined direction);
-g.addColorStop(0, '#f00');
-g.addColorStop(1, '#f00');
-ctx.strokeStyle = g;
-ctx.font = '1px sans-serif';
-ctx.strokeText("AA", 0, 1);
-
-var imageData = ctx.getImageData(0, 0, 1, 1);
-var imgdata = imageData.data;
-shouldBe("imgdata[0]", "0");
-shouldBe("imgdata[1]", "255");
-shouldBe("imgdata[2]", "0");
-
diff --git a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-offscreencanvas.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-offscreencanvas.html
new file mode 100644
index 0000000..5b4349f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-offscreencanvas.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<script src =../../resources/testharness.js></script>
+<script src =../../resources/testharnessreport.js></script>
+<script>
+
+function draw2d(canvas) {
+  var ctx = canvas.getContext('2d');
+  ctx.fillStyle = 'green';
+  ctx.fillRect(0, 0, canvas.width, canvas.height);
+  return ctx;
+};
+
+function drawWebGL(canvas) {
+  var gl = canvas.getContext('webgl');
+  gl.clearColor(0, 1, 0, 1);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+  return gl;
+};
+
+// Run captureStream() after transferControlToOffscreen().
+var testOffScreenCanvasCommits = function(drawFunction, message) {
+  async_test(function(test) {
+    var canvas = document.createElement('canvas');
+    var offscreen = canvas.transferControlToOffscreen();
+
+    var recorder = new MediaRecorder(canvas.captureStream());
+    recorder.ondataavailable = test.step_func_done(function(event) {
+      assert_true(event.data.size > 0, 'Recorded data size should be > 0');
+    });
+    recorder.start(0);
+
+    var ctx = drawFunction(offscreen);
+    ctx.commit();
+  }), message;
+};
+
+testOffScreenCanvasCommits(draw2d,
+                           'capture of an OffscreenCanvas with 2D context');
+testOffScreenCanvasCommits(drawWebGL,
+                           'capture of an OffscreenCanvas with WebGL context');
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/override-referrer-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/override-referrer-expected.txt
new file mode 100644
index 0000000..385a335
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/override-referrer-expected.txt
@@ -0,0 +1,3 @@
+
+Referrers: ["referrer.com","127.0.0.1"]
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/override-referrer.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/override-referrer.html
new file mode 100644
index 0000000..3526740
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/override-referrer.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="inspector-protocol-test.js"></script>
+<script>
+
+function test()
+{
+    let referrers = [];
+
+    InspectorTest.eventHandler["Network.requestWillBeSent"] = onRequestWillBeSent;
+    enableNetwork();
+
+    function enableNetwork()
+    {
+        InspectorTest.sendCommandOrDie("Network.enable", {}, didEnableNetwork);
+    }
+
+    function didEnableNetwork()
+    {
+        // Prepare for a "reload" to avoid having the test harness loaded by
+        // image.html initiate the test again.
+        InspectorTest.evaluateInPage(
+            "prepareForReload(), window.location.href", navigate);
+    }
+
+    function navigate(currentUrl)
+    {
+        let url = currentUrl.replace(
+            "override-referrer.html", "resources/image.html");
+        InspectorTest.sendCommandOrDie("Page.navigate", {
+          url: url,
+          referrer: "http://referrer.com/"
+        });
+    }
+
+    function onRequestWillBeSent(event)
+    {
+        let params = event.params;
+        let referrer = params.request.headers.Referer;
+        if (!referrer)
+          return;
+
+        referrers.push(InspectorTest.parseURL(referrer).host);
+        if (referrers.length === 2) {
+          // Only log the list the found referrers at the end of the test.
+          // Otherwise the first one will be lost because the target page is in
+          // the middle of loading.
+          InspectorTest.log("Referrers: " + JSON.stringify(referrers));
+          testRunner.logToStderr(JSON.stringify(referrers));
+          InspectorTest.completeTest();
+        }
+    }
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests that the navigation referrer can be overridden.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/image.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/image.html
new file mode 100644
index 0000000..f8fedac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/image.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<!-- We also need to include the inspector test harness here to ensure the test
+     completes normally after navigating to this page. -->
+<script src="../inspector-protocol-test.js"></script>
+<body onload="runTest()">
+<img src="image.png">
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/image.png b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/image.png
new file mode 100644
index 0000000..98d3988
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/image.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.html b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.html
index 862adcd..073b8e9 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/domdebugger-setInnerHTML.html
@@ -13,7 +13,7 @@
     InspectorTest.sendCommand("Debugger.enable", {});
     InspectorTest.sendCommand("DOM.enable", {});
     InspectorTest.sendCommand("DOMDebugger.enable", {});
-    InspectorTest.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {"eventName":"setInnerHTML"});
+    InspectorTest.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {"eventName":"Element.setInnerHTML"});
     InspectorTest.sendCommand("Runtime.evaluate", { "expression": "modifyHTML()" });
     InspectorTest.eventHandler["Debugger.paused"] = handleDebuggerPausedOne;
 
diff --git a/third_party/WebKit/LayoutTests/inspector/components/cookies-table.html b/third_party/WebKit/LayoutTests/inspector/components/cookies-table.html
index b14f799..ce9d6c9c 100644
--- a/third_party/WebKit/LayoutTests/inspector/components/cookies-table.html
+++ b/third_party/WebKit/LayoutTests/inspector/components/cookies-table.html
@@ -9,7 +9,7 @@
   }
 
   function createCookie(data) {
-    const cookie = new SDK.Cookie(null, data.name, data.value);
+    const cookie = new SDK.Cookie(data.name, data.value);
     for (let key in data) {
       if (key === 'name' || key === 'value')
         continue;
@@ -20,7 +20,7 @@
   }
 
   function createSortAndDumpCookies(cookieData, column, isAsc) {
-    const table = new CookieTable.CookiesTable(true);
+    const table = new CookieTable.CookiesTable(SDK.targetManager.mainTarget(), true);
     const cookies = cookieData.map(createCookie);
     table._dataGrid = {isSortOrderAscending: () => isAsc, sortColumnId: () => column};
     table._sortCookies(cookies);
diff --git a/third_party/WebKit/LayoutTests/inspector/cookie-resource-match.html b/third_party/WebKit/LayoutTests/inspector/cookie-resource-match.html
index 1a99947..57cddc1 100644
--- a/third_party/WebKit/LayoutTests/inspector/cookie-resource-match.html
+++ b/third_party/WebKit/LayoutTests/inspector/cookie-resource-match.html
@@ -54,7 +54,7 @@
     for (var i = 0; i < cookies.length; ++i) {
         var cookieResult = [];
         for (var j = 0; j < resourceURLs.length; ++j) {
-            if (SDK.Cookies.cookieMatchesResourceURL(cookies[i], resourceURLs[j]))
+            if (SDK.CookieModel.cookieMatchesResourceURL(cookies[i], resourceURLs[j]))
                 cookieResult.push(j);
         }
         InspectorTest.addResult("[" + cookieResult + "]");
@@ -75,7 +75,8 @@
             secure: secure,
             session: true
         };
-        return SDK.Cookies._parseProtocolCookie(SDK.targetManager.mainTarget(), protocolCookie);
+        var target = SDK.targetManager.mainTarget();
+        return SDK.CookieModel._parseProtocolCookie(protocolCookie);
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/containing-block-warning-expected.txt b/third_party/WebKit/LayoutTests/intersection-observer/containing-block-warning-expected.txt
deleted file mode 100644
index 0e792b4..0000000
--- a/third_party/WebKit/LayoutTests/intersection-observer/containing-block-warning-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE WARNING: line 9: IntersectionObserver.observe(target): target element is not a descendant of root.
-
diff --git a/third_party/WebKit/LayoutTests/intersection-observer/containing-block-warning.html b/third_party/WebKit/LayoutTests/intersection-observer/containing-block-warning.html
deleted file mode 100644
index 6cb8fca..0000000
--- a/third_party/WebKit/LayoutTests/intersection-observer/containing-block-warning.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<div id="root"></div>
-<div id="target"></div>
-<script>
-if (self.testRunner)
-  testRunner.dumpAsText();
-var root = document.getElementById("root");
-var target = document.getElementById("target");
-new IntersectionObserver(c => {}, {root: root}).observe(target);
-</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index 0735e28a..014c0c2e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index 0735e28a..014c0c2e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index 6966ca6..0302c21 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt
index 5537e7e..5d437fe 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt
@@ -4,7 +4,6 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-SecurityError
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index 6966ca6..0302c21 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt
new file mode 100644
index 0000000..5d437fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/webfont/popup-menu-load-webfont-after-open-expected.txt
@@ -0,0 +1,10 @@
+
+Test that fonts loaded after a popup menu is opened triggers a style recalc.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle-expected.txt
deleted file mode 100644
index bbabbaf4..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle-expected.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-This test checks the SVGAnimatedAngle API - utilizing the orientAngle property of SVGMarkerElement
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-
-Check initial orientAngle value
-PASS markerElement.orientAngle.toString() is "[object SVGAnimatedAngle]"
-PASS markerElement.orientAngle.baseVal.toString() is "[object SVGAngle]"
-PASS markerElement.orientAngle.baseVal.value is 0
-
-Check that angles are dynamic, caching value in a local variable and modifying it, should take effect
-PASS numRef.value is 100
-PASS markerElement.orientAngle.baseVal.value is 100
-
-Check that assigning to baseVal has no effect, as no setter is defined
-PASS markerElement.orientAngle.baseVal = -1 is -1
-PASS markerElement.orientAngle.baseVal = 'aString' is "aString"
-PASS markerElement.orientAngle.baseVal = markerElement is markerElement
-
-Check that the orientAngle value remained 100, and the baseVal type has not been changed
-PASS markerElement.orientAngle.baseVal.toString() is "[object SVGAngle]"
-PASS markerElement.orientAngle.baseVal.value is 100
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle.html b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle.html
index 04e91f3d..9ff380f 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle.html
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedAngle.html
@@ -1,11 +1,33 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGAnimatedAngle.js"></script>
-</body>
-</html>
+<!DOCTYPE HTML>
+<title>SVGAnimatedAngle interface - utilizing the orientAngle property of SVGMarkerElement</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  // This test checks the SVGAnimatedAngle API - utilizing the orientAngle property of SVGMarkerElement.
+
+  var markerElement = document.createElementNS("http://www.w3.org/2000/svg", "marker");
+
+  // Check initial orientAngle value.
+  assert_true(markerElement.orientAngle instanceof SVGAnimatedAngle);
+  assert_true(markerElement.orientAngle.baseVal instanceof SVGAngle);
+  assert_equals(markerElement.orientAngle.baseVal.value, 0);
+
+  // Check that angles are dynamic, caching value in a local variable and modifying it, should take effect.
+  var numRef = markerElement.orientAngle.baseVal;
+  numRef.value = 100;
+  assert_equals(numRef.value, 100);
+  assert_equals(markerElement.orientAngle.baseVal.value, 100);
+
+  // Check that assigning to baseVal has no effect, as no setter is defined.
+  markerElement.orientAngle.baseVal = -1;
+  assert_equals(markerElement.orientAngle.baseVal.value, 100);
+  markerElement.orientAngle.baseVal = 'aString';
+  assert_equals(markerElement.orientAngle.baseVal.value, 100);
+  markerElement.orientAngle.baseVal = markerElement;
+  assert_equals(markerElement.orientAngle.baseVal.value, 100);
+
+  // Check that the orientAngle baseVal type has not been changed.
+  assert_true(markerElement.orientAngle.baseVal instanceof SVGAngle);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean-expected.txt
deleted file mode 100644
index b3ba058..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean-expected.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-This test checks the SVGAnimatedBoolean API - utilizing the preserveAlpha property of SVGFEConvolveMatrixElement
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-
-Check initial preserveAlpha value
-PASS convElement.preserveAlpha.baseVal is false
-
-Set value to true
-PASS convElement.preserveAlpha.baseVal = true is true
-
-Caching baseVal in local variable
-PASS baseVal is true
-
-Modify local baseVal variable to true
-PASS baseVal = false is false
-
-Assure that convElement.preserveAlpha has not been changed, but the local baseVal variable
-PASS baseVal is false
-PASS convElement.preserveAlpha.baseVal is true
-
-Check assigning values of various types
-PASS convElement.preserveAlpha.baseVal = convElement.preserveAlpha is convElement.preserveAlpha
-PASS convElement.preserveAlpha.baseVal is true
-PASS convElement.preserveAlpha.baseVal = null is null
-PASS convElement.preserveAlpha.baseVal is false
-PASS convElement.preserveAlpha.baseVal = 'aString' is 'aString'
-PASS convElement.preserveAlpha.baseVal is true
-PASS convElement.preserveAlpha.baseVal = convElement is convElement
-PASS convElement.preserveAlpha.baseVal is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean.html b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean.html
index 179b16e..6571564 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean.html
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedBoolean.html
@@ -1,11 +1,45 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGAnimatedBoolean.js"></script>
-</body>
-</html>
+<!DOCTYPE HTML>
+<title>SVGAnimatedBoolean interface - utilizing the preserveAlpha property of SVGFEConvolveMatrixElement</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  // This test checks the SVGAnimatedBoolean API - utilizing the preserveAlpha property of SVGFEConvolveMatrixElement.
+
+  var convElement = document.createElementNS("http://www.w3.org/2000/svg", "feConvolveMatrix");
+  // Check initial preserveAlpha value.
+  assert_false(convElement.preserveAlpha.baseVal);
+
+  // Set value to true.
+  convElement.preserveAlpha.baseVal = true;
+  assert_true(convElement.preserveAlpha.baseVal);
+
+  // Caching baseVal in local variable.
+  var baseVal = convElement.preserveAlpha.baseVal;
+  assert_true(baseVal);
+
+  // Modify local baseVal variable to false.
+  baseVal = false;
+
+  // Assure that convElement.preserveAlpha has not been changed, but the local baseVal variable.
+  assert_false(baseVal);
+  assert_true(convElement.preserveAlpha.baseVal);
+
+  // Check assigning values of various types.
+  // ECMA-262, 9.2, "ToBoolean"
+  convElement.preserveAlpha.baseVal = convElement.preserveAlpha;
+  assert_true(convElement.preserveAlpha.baseVal);
+
+  convElement.preserveAlpha.baseVal = null;
+  assert_false(convElement.preserveAlpha.baseVal);
+
+  convElement.preserveAlpha.baseVal = 'aString';
+  assert_true(convElement.preserveAlpha.baseVal);
+
+  convElement.preserveAlpha.baseVal = false;
+  assert_false(convElement.preserveAlpha.baseVal);
+
+  convElement.preserveAlpha.baseVal = convElement;
+  assert_true(convElement.preserveAlpha.baseVal);
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger-expected.txt
deleted file mode 100644
index 946283a..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger-expected.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-This test checks the SVGAnimatedInteger API - utilizing the targetX property of SVGFEConvolveMatrix
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-
-Check initial targetX value
-PASS feConvolveMatrix.targetX.toString() is "[object SVGAnimatedInteger]"
-PASS typeof(feConvolveMatrix.targetX.baseVal) is "number"
-PASS feConvolveMatrix.targetX.baseVal is 0
-
-Check that integers are static, caching value in a local variable and modifying it, should have no effect
-PASS numRef is 100
-PASS feConvolveMatrix.targetX.baseVal is 0
-
-Check assigning various valid and invalid values
-PASS feConvolveMatrix.targetX.baseVal = -1 is -1
-PASS feConvolveMatrix.targetX.baseVal = 300 is 300
-PASS feConvolveMatrix.targetX.baseVal = 'aString' is 'aString'
-PASS feConvolveMatrix.targetX.baseVal is 0
-PASS feConvolveMatrix.targetX.baseVal = feConvolveMatrix is feConvolveMatrix
-PASS feConvolveMatrix.targetX.baseVal is 0
-PASS feConvolveMatrix.targetX.baseVal = 300 is 300
-
-Check that the targetX value remained 300
-PASS feConvolveMatrix.targetX.baseVal is 300
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger.html b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger.html
index 88fdda8..8a12a99 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger.html
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedInteger.html
@@ -1,11 +1,35 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGAnimatedInteger.js"></script>
-</body>
-</html>
+<!DOCTYPE HTML>
+<title>SVGAnimatedInteger interface - utilizing the targetX property of SVGFEConvolveMatrix</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  // This test checks the SVGAnimatedInteger API - utilizing the targetX property of SVGFEConvolveMatrix.
+
+  var feConvolveMatrix = document.createElementNS("http://www.w3.org/2000/svg", "feConvolveMatrix");
+
+  // Check initial targetX value.
+  assert_true(feConvolveMatrix.targetX instanceof SVGAnimatedInteger);
+  assert_equals(typeof(feConvolveMatrix.targetX.baseVal), "number");
+  assert_equals(feConvolveMatrix.targetX.baseVal, 0);
+
+  // Check that integers are static, caching value in a local variable and modifying it, should have no effect.
+  var numRef = feConvolveMatrix.targetX.baseVal;
+  numRef = 100;
+  assert_equals(numRef, 100);
+  assert_equals(feConvolveMatrix.targetX.baseVal, 0);
+
+  // Check assigning various valid and invalid values.
+  feConvolveMatrix.targetX.baseVal = -1;
+  assert_equals(feConvolveMatrix.targetX.baseVal, -1); // Negative values are allowed from SVG DOM, but should lead to an error when rendering (disable the filter)
+  feConvolveMatrix.targetX.baseVal = 300;
+  assert_equals(feConvolveMatrix.targetX.baseVal, 300);
+  // ECMA-262, 9.5, "ToInt32"
+  feConvolveMatrix.targetX.baseVal = 'aString';
+  assert_equals(feConvolveMatrix.targetX.baseVal, 0);
+  feConvolveMatrix.targetX.baseVal = feConvolveMatrix;
+  assert_equals(feConvolveMatrix.targetX.baseVal, 0);
+  feConvolveMatrix.targetX.baseVal = 300;
+  assert_equals(feConvolveMatrix.targetX.baseVal, 300);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio-expected.txt
deleted file mode 100644
index 4ca3994..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio-expected.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-This test checks the SVGAnimatedPreserveAspectRatio API - utilizing the preserveAspectRatio property of SVGSVGElement
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-
-Check initial preserveAspectRatio value
-PASS svgElement.preserveAspectRatio.toString() is "[object SVGAnimatedPreserveAspectRatio]"
-PASS svgElement.preserveAspectRatio.baseVal.toString() is "[object SVGPreserveAspectRatio]"
-PASS svgElement.preserveAspectRatio.baseVal.align is SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID
-PASS svgElement.preserveAspectRatio.baseVal.meetOrSlice is SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET
-
-Check that preserveAspectRatios are dynamic, caching value in a local variable and modifying it, should take effect
-PASS aspectRef.align is SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN
-PASS aspectRef.meetOrSlice is SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE
-PASS svgElement.preserveAspectRatio.baseVal.align is SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN
-PASS svgElement.preserveAspectRatio.baseVal.meetOrSlice is SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE
-
-Check that assigning to baseVal has no effect, as no setter is defined
-PASS svgElement.preserveAspectRatio.baseVal = -1 is -1
-PASS svgElement.preserveAspectRatio.baseVal = 'aString' is "aString"
-PASS svgElement.preserveAspectRatio.baseVal = svgElement is svgElement
-
-Check that the preserveAspectRatio align/meetOrSlice remained xMaxYMin/slice, and the baseVal type has not been changed
-PASS svgElement.preserveAspectRatio.baseVal.toString() is "[object SVGPreserveAspectRatio]"
-PASS svgElement.preserveAspectRatio.baseVal.align is SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN
-PASS svgElement.preserveAspectRatio.baseVal.meetOrSlice is SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio.html b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio.html
index 617929b..1e0f223 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio.html
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedPreserveAspectRatio.html
@@ -1,11 +1,41 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGAnimatedPreserveAspectRatio.js"></script>
-</body>
-</html>
+<!DOCTYPE HTML>
+<title>SVGAnimatedPreserveAspectRatio interface - utilizing the preserveAspectRatio property of SVGSVGElement</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  // This test checks the SVGAnimatedPreserveAspectRatio API - utilizing the preserveAspectRatio property of SVGSVGElement.
+
+  var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+
+  // Check initial preserveAspectRatio value.
+  assert_true(svgElement.preserveAspectRatio instanceof SVGAnimatedPreserveAspectRatio);
+  assert_true(svgElement.preserveAspectRatio.baseVal instanceof SVGPreserveAspectRatio);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.meetOrSlice, SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET);
+
+  // Check that preserveAspectRatios are dynamic, caching value in a local variable and modifying it, should take effect;
+  var aspectRef = svgElement.preserveAspectRatio.baseVal;
+  aspectRef.align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN;
+  aspectRef.meetOrSlice = SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE;
+  assert_equals(aspectRef.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN);
+  assert_equals(aspectRef.meetOrSlice, SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.meetOrSlice, SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE);
+
+  // Check that assigning to baseVal has no effect, as no setter is defined.
+  // And the preserveAspectRatio align/meetOrSlice remained xMaxYMin/slice.
+  svgElement.preserveAspectRatio.baseVal = -1;
+  assert_equals(svgElement.preserveAspectRatio.baseVal.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.meetOrSlice, SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE);
+  svgElement.preserveAspectRatio.baseVal = 'aString';
+  assert_equals(svgElement.preserveAspectRatio.baseVal.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.meetOrSlice, SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE);
+  svgElement.preserveAspectRatio.baseVal = svgElement;
+  assert_equals(svgElement.preserveAspectRatio.baseVal.align, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN);
+  assert_equals(svgElement.preserveAspectRatio.baseVal.meetOrSlice, SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE);
+
+  // Check that the preserveAspectRatio baseVal type has not been changed.
+  assert_true(svgElement.preserveAspectRatio.baseVal instanceof SVGPreserveAspectRatio);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect-expected.txt
deleted file mode 100644
index 8946c41..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect-expected.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-This test checks the SVGAnimatedRect API - utilizing the viewBox property of SVGSVGElement
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-
-Check initial viewBox value
-PASS svgElement.viewBox.toString() is "[object SVGAnimatedRect]"
-PASS svgElement.viewBox.baseVal.toString() is "[object SVGRect]"
-PASS svgElement.viewBox.baseVal.x is 0
-
-Check that rects are dynamic, caching value in a local variable and modifying it, should take effect
-PASS numRef.x is 100
-PASS svgElement.viewBox.baseVal.x is 100
-
-Check that assigning to baseVal has no effect, as no setter is defined
-PASS svgElement.viewBox.baseVal = -1 is -1
-PASS svgElement.viewBox.baseVal = 'aString' is "aString"
-PASS svgElement.viewBox.baseVal = svgElement is svgElement
-
-Check that the viewBox x remained 100, and the baseVal type has not been changed
-PASS svgElement.viewBox.baseVal.toString() is "[object SVGRect]"
-PASS svgElement.viewBox.baseVal.x is 100
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect.html b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect.html
index 9c030dc..8a9376a 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect.html
+++ b/third_party/WebKit/LayoutTests/svg/dom/SVGAnimatedRect.html
@@ -1,11 +1,33 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<script src="script-tests/SVGAnimatedRect.js"></script>
-</body>
-</html>
+<!DOCTYPE HTML>
+<title>SVGAnimatedRect interface - utilizing the viewBox property of SVGSVGElement</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  // This test checks the SVGAnimatedRect API - utilizing the viewBox property of SVGSVGElement.
+
+  var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+
+  // Check initial viewBox value.
+  assert_true(svgElement.viewBox instanceof SVGAnimatedRect);
+  assert_true(svgElement.viewBox.baseVal instanceof SVGRect);
+  assert_equals(svgElement.viewBox.baseVal.x, 0);
+
+  // Check that rects are dynamic, caching value in a local variable and modifying it, should take effect.
+  var numRef = svgElement.viewBox.baseVal;
+  numRef.x = 100;
+  assert_equals(numRef.x, 100);
+  assert_equals(svgElement.viewBox.baseVal.x, 100);
+
+  // Check that assigning to baseVal has no effect, as no setter is defined.
+  svgElement.viewBox.baseVal = -1;
+  assert_equals(svgElement.viewBox.baseVal.x, 100);
+  svgElement.viewBox.baseVal = 'aString';
+  assert_equals(svgElement.viewBox.baseVal.x, 100);
+  svgElement.viewBox.baseVal = svgElement;
+  assert_equals(svgElement.viewBox.baseVal.x, 100);
+
+  // Check that the viewBox baseVal type has not been changed.
+  assert_true(svgElement.viewBox.baseVal instanceof SVGRect);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedAngle.js b/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedAngle.js
deleted file mode 100644
index 9fa2bb1..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedAngle.js
+++ /dev/null
@@ -1,29 +0,0 @@
-description("This test checks the SVGAnimatedAngle API - utilizing the orientAngle property of SVGMarkerElement");
-
-var markerElement = document.createElementNS("http://www.w3.org/2000/svg", "marker");
-
-debug("");
-debug("Check initial orientAngle value");
-shouldBeEqualToString("markerElement.orientAngle.toString()", "[object SVGAnimatedAngle]");
-shouldBeEqualToString("markerElement.orientAngle.baseVal.toString()", "[object SVGAngle]");
-shouldBe("markerElement.orientAngle.baseVal.value", "0");
-
-debug("");
-debug("Check that angles are dynamic, caching value in a local variable and modifying it, should take effect");
-var numRef = markerElement.orientAngle.baseVal;
-numRef.value = 100;
-shouldBe("numRef.value", "100");
-shouldBe("markerElement.orientAngle.baseVal.value", "100");
-
-debug("");
-debug("Check that assigning to baseVal has no effect, as no setter is defined");
-shouldBe("markerElement.orientAngle.baseVal = -1", "-1");
-shouldBeEqualToString("markerElement.orientAngle.baseVal = 'aString'", "aString");
-shouldBe("markerElement.orientAngle.baseVal = markerElement", "markerElement");
-
-debug("");
-debug("Check that the orientAngle value remained 100, and the baseVal type has not been changed");
-shouldBeEqualToString("markerElement.orientAngle.baseVal.toString()", "[object SVGAngle]");
-shouldBe("markerElement.orientAngle.baseVal.value", "100");
-
-successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedBoolean.js b/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedBoolean.js
deleted file mode 100644
index e0d6ac6..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedBoolean.js
+++ /dev/null
@@ -1,39 +0,0 @@
-description("This test checks the SVGAnimatedBoolean API - utilizing the preserveAlpha property of SVGFEConvolveMatrixElement");
-
-var convElement = document.createElementNS("http://www.w3.org/2000/svg", "feConvolveMatrix");
-debug("");
-debug("Check initial preserveAlpha value");
-shouldBe("convElement.preserveAlpha.baseVal", "false");
-
-debug("");
-debug("Set value to true");
-shouldBe("convElement.preserveAlpha.baseVal = true", "true");
-
-debug("");
-debug("Caching baseVal in local variable");
-var baseVal = convElement.preserveAlpha.baseVal;
-shouldBe("baseVal", "true");
-
-debug("");
-debug("Modify local baseVal variable to true");
-shouldBeFalse("baseVal = false");
-
-debug("");
-debug("Assure that convElement.preserveAlpha has not been changed, but the local baseVal variable");
-shouldBe("baseVal", "false");
-shouldBe("convElement.preserveAlpha.baseVal", "true");
-
-debug("");
-debug("Check assigning values of various types");
-// ECMA-262, 9.2, "ToBoolean"
-shouldBe("convElement.preserveAlpha.baseVal = convElement.preserveAlpha", "convElement.preserveAlpha");
-shouldBe("convElement.preserveAlpha.baseVal", "true");
-shouldBeNull("convElement.preserveAlpha.baseVal = null");
-shouldBe("convElement.preserveAlpha.baseVal", "false");
-shouldBe("convElement.preserveAlpha.baseVal = 'aString'", "'aString'");
-shouldBe("convElement.preserveAlpha.baseVal", "true");
-convElement.preserveAlpha.baseVal = false;
-shouldBe("convElement.preserveAlpha.baseVal = convElement", "convElement");
-shouldBe("convElement.preserveAlpha.baseVal", "true");
-
-successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedInteger.js b/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedInteger.js
deleted file mode 100644
index 9c63af0..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedInteger.js
+++ /dev/null
@@ -1,33 +0,0 @@
-description("This test checks the SVGAnimatedInteger API - utilizing the targetX property of SVGFEConvolveMatrix");
-
-var feConvolveMatrix = document.createElementNS("http://www.w3.org/2000/svg", "feConvolveMatrix");
-
-debug("");
-debug("Check initial targetX value");
-shouldBeEqualToString("feConvolveMatrix.targetX.toString()", "[object SVGAnimatedInteger]");
-shouldBeEqualToString("typeof(feConvolveMatrix.targetX.baseVal)", "number");
-shouldBe("feConvolveMatrix.targetX.baseVal", "0");
-
-debug("");
-debug("Check that integers are static, caching value in a local variable and modifying it, should have no effect");
-var numRef = feConvolveMatrix.targetX.baseVal;
-numRef = 100;
-shouldBe("numRef", "100");
-shouldBe("feConvolveMatrix.targetX.baseVal", "0");
-
-debug("");
-debug("Check assigning various valid and invalid values");
-shouldBe("feConvolveMatrix.targetX.baseVal = -1", "-1"); // Negative values are allowed from SVG DOM, but should lead to an error when rendering (disable the filter)
-shouldBe("feConvolveMatrix.targetX.baseVal = 300", "300");
-// ECMA-262, 9.5, "ToInt32"
-shouldBe("feConvolveMatrix.targetX.baseVal = 'aString'", "'aString'");
-shouldBe("feConvolveMatrix.targetX.baseVal", "0");
-shouldBe("feConvolveMatrix.targetX.baseVal = feConvolveMatrix", "feConvolveMatrix");
-shouldBe("feConvolveMatrix.targetX.baseVal", "0");
-shouldBe("feConvolveMatrix.targetX.baseVal = 300", "300");
-
-debug("");
-debug("Check that the targetX value remained 300");
-shouldBe("feConvolveMatrix.targetX.baseVal", "300");
-
-successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedPreserveAspectRatio.js b/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedPreserveAspectRatio.js
deleted file mode 100644
index ea790d1d..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedPreserveAspectRatio.js
+++ /dev/null
@@ -1,34 +0,0 @@
-description("This test checks the SVGAnimatedPreserveAspectRatio API - utilizing the preserveAspectRatio property of SVGSVGElement");
-
-var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
-
-debug("");
-debug("Check initial preserveAspectRatio value");
-shouldBeEqualToString("svgElement.preserveAspectRatio.toString()", "[object SVGAnimatedPreserveAspectRatio]");
-shouldBeEqualToString("svgElement.preserveAspectRatio.baseVal.toString()", "[object SVGPreserveAspectRatio]");
-shouldBe("svgElement.preserveAspectRatio.baseVal.align", "SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID");
-shouldBe("svgElement.preserveAspectRatio.baseVal.meetOrSlice", "SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET");
-
-debug("");
-debug("Check that preserveAspectRatios are dynamic, caching value in a local variable and modifying it, should take effect");
-var aspectRef = svgElement.preserveAspectRatio.baseVal;
-aspectRef.align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN;
-aspectRef.meetOrSlice = SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE;
-shouldBe("aspectRef.align", "SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN");
-shouldBe("aspectRef.meetOrSlice", "SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE");
-shouldBe("svgElement.preserveAspectRatio.baseVal.align", "SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN");
-shouldBe("svgElement.preserveAspectRatio.baseVal.meetOrSlice", "SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE");
-
-debug("");
-debug("Check that assigning to baseVal has no effect, as no setter is defined");
-shouldBe("svgElement.preserveAspectRatio.baseVal = -1", "-1");
-shouldBeEqualToString("svgElement.preserveAspectRatio.baseVal = 'aString'", "aString");
-shouldBe("svgElement.preserveAspectRatio.baseVal = svgElement", "svgElement");
-
-debug("");
-debug("Check that the preserveAspectRatio align/meetOrSlice remained xMaxYMin/slice, and the baseVal type has not been changed");
-shouldBeEqualToString("svgElement.preserveAspectRatio.baseVal.toString()", "[object SVGPreserveAspectRatio]");
-shouldBe("svgElement.preserveAspectRatio.baseVal.align", "SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN");
-shouldBe("svgElement.preserveAspectRatio.baseVal.meetOrSlice", "SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE");
-
-successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedRect.js b/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedRect.js
deleted file mode 100644
index 5cb7d03d..0000000
--- a/third_party/WebKit/LayoutTests/svg/dom/script-tests/SVGAnimatedRect.js
+++ /dev/null
@@ -1,29 +0,0 @@
-description("This test checks the SVGAnimatedRect API - utilizing the viewBox property of SVGSVGElement");
-
-var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
-
-debug("");
-debug("Check initial viewBox value");
-shouldBeEqualToString("svgElement.viewBox.toString()", "[object SVGAnimatedRect]");
-shouldBeEqualToString("svgElement.viewBox.baseVal.toString()", "[object SVGRect]");
-shouldBe("svgElement.viewBox.baseVal.x", "0");
-
-debug("");
-debug("Check that rects are dynamic, caching value in a local variable and modifying it, should take effect");
-var numRef = svgElement.viewBox.baseVal;
-numRef.x = 100;
-shouldBe("numRef.x", "100");
-shouldBe("svgElement.viewBox.baseVal.x", "100");
-
-debug("");
-debug("Check that assigning to baseVal has no effect, as no setter is defined");
-shouldBe("svgElement.viewBox.baseVal = -1", "-1");
-shouldBeEqualToString("svgElement.viewBox.baseVal = 'aString'", "aString");
-shouldBe("svgElement.viewBox.baseVal = svgElement", "svgElement");
-
-debug("");
-debug("Check that the viewBox x remained 100, and the baseVal type has not been changed");
-shouldBeEqualToString("svgElement.viewBox.baseVal.toString()", "[object SVGRect]");
-shouldBe("svgElement.viewBox.baseVal.x", "100");
-
-successfullyParsed = true;
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-shadow-expected.txt
deleted file mode 100644
index dd3f8e9..0000000
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-shadow-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Some tests for Canvas shadows
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-PASS imgdata[4] is 0
-PASS imgdata[5] is 128
-PASS imgdata[6] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokePath-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokePath-gradient-shadow-expected.txt
deleted file mode 100644
index cf5964f..0000000
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokePath-gradient-shadow-expected.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-Ensure correct behavior of canvas with strokePath using a gradient strokeStyle and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokeRect-alpha-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokeRect-alpha-shadow-expected.txt
deleted file mode 100644
index 67726ad7..0000000
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokeRect-alpha-shadow-expected.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-Ensure correct behavior of canvas with strokeRect using a semi-transparent solid strokeStyle and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokeRect-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokeRect-gradient-shadow-expected.txt
deleted file mode 100644
index 7747bc15..0000000
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-strokeRect-gradient-shadow-expected.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-Ensure correct behavior of canvas with strokeRect using a gradient strokeStyle and a shadow
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Verifying alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated alpha shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-Verifying rotated blurry shadow...
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 255
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is around 64
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
-PASS data[0] is 0
-PASS data[1] is 0
-PASS data[2] is 0
-PASS data[3] is 0
- 
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
index c073424..19017c6d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/BiquadFilter/biquadfilternode-basic-expected.txt
@@ -1,7 +1,7 @@
 CONSOLE WARNING: line 49: The provided value '99' is not a valid enum value of type BiquadFilterType.
 This is a testharness.js-based test.
 PASS # AUDIT TASK RUNNER STARTED. 
-PASS > [test] Basic tests for BiquadFilterNode 
+PASS > [test]  
 PASS   Number of inputs is equal to 1. 
 PASS   Number of outputs is equal to 1. 
 PASS   Default filter type is equal to lowpass. 
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic-expected.txt
deleted file mode 100644
index 605503a..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic-expected.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Test attribute and basic functionality of StereoPannerNode.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS panner.numberOfInputs === 1 is true
-PASS panner.numberOfOutputs === 1 is true
-PASS panner.pan.defaultValue === 0.0 is true
-PASS panner.pan.value === 0.0 is true
-PASS panner.pan.value === 1.0 is true
-PASS panner.channelCount = 1 did not throw exception.
-PASS panner.channelCount = 3 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': The channelCount provided (3) is outside the range [1, 2]..
-PASS panner.channelCountMode = "explicit" did not throw exception.
-PASS panner.channelCountMode = "max" threw exception NotSupportedError: Failed to set the 'channelCountMode' property on 'AudioNode': StereoPanner: 'max' is not allowed.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
index 2457555..e9939fb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-basic.html
@@ -2,41 +2,44 @@
 <html>
 
 <head>
-  <script src="../../resources/js-test.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script> 
   <script src="../resources/audit-util.js"></script>
-  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/audit.js"></script>
 </head>
 
 <body>
-  <div id="description"></div>
-  <div id="console"></div>
   <script>
-    description("Test attribute and basic functionality of StereoPannerNode.");
+    let audit = Audit.createTaskRunner();
 
-    function checkAttributes() {
-      window.jsTestIsAsync = true;
+    audit.define('test', (task, should) => {
+      task.describe('Attributes and basic functionality of StereoPannerNode');
 
-      var context = new AudioContext();
-      var panner = context.createStereoPanner();
-      window.panner = panner;
+      let context = new AudioContext();
+      let panner = context.createStereoPanner();
 
-      shouldBeTrue('panner.numberOfInputs === 1');
-      shouldBeTrue('panner.numberOfOutputs === 1');
-      shouldBeTrue('panner.pan.defaultValue === 0.0');
-      shouldBeTrue('panner.pan.value === 0.0');
-      panner.pan.value = 1.0;
-      shouldBeTrue('panner.pan.value === 1.0');
+      should(panner.numberOfInputs, 'panner.numberOfInputs').beEqualTo(1);
+      should(panner.numberOfOutputs, 'panner.numberOfOutputs').beEqualTo(1);
+      should(panner.pan.defaultValue, 'panner.pan.defaultValue').beEqualTo(0.0);
+      should(() => panner.pan.value = 1.0, 'panner.pan.value = 1.0').notThrow();
+      should(panner.pan.value, 'panner.pan.value').beEqualTo(1.0);
 
-      shouldNotThrow('panner.channelCount = 1');
-      shouldThrow('panner.channelCount = 3');
-      shouldNotThrow('panner.channelCountMode = "explicit"');
-      shouldThrow('panner.channelCountMode = "max"');
+      should(() => panner.channelCount = 1, 'panner.channelCount = 1')
+          .notThrow();
+      should(() => panner.channelCount = 3, 'panner.channelCount = 3').throw();
+      should(
+          () => panner.channelCountMode = 'explicit',
+          'panner.channelCountMode = "explicit"')
+          .notThrow();
+      should(
+          () => panner.channelCountMode = 'max',
+          'panner.channelCountMode = "max"')
+          .throw();
 
-      finishJSTest();
-    }
+      task.done();
+    });
 
-    checkAttributes();
-    successfullyParsed = true;
+    audit.run();
   </script>
 </body>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch-expected.txt b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch-expected.txt
deleted file mode 100644
index a8c4d8eb..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-Test if StereoPannerNode producing glitches by crossing zero.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS Transition found between sample #2175 and #17854.
-PASS Channel #0 has no glitch above the threshold of 0.0005.
-PASS Channel #1 has no glitch above the threshold of 0.0005.
-PASS Channel #0 equals [1.156434465040231,1.1562937736154582,...] with an element-wise tolerance of 1e-7.
-PASS Channel #1 equals [0.9876883405951378,0.987710613656166,...] with an element-wise tolerance of 1e-7.
-PASS Transition found between sample #2175 and #17854.
-PASS Channel #0 has no glitch above the threshold of 0.0005.
-PASS Channel #1 has no glitch above the threshold of 0.0005.
-PASS Channel #0 equals [0.9876883405951378,0.987710613656166,...] with an element-wise tolerance of 1e-7.
-PASS Channel #1 equals [1.156434465040231,1.156293773615458,...] with an element-wise tolerance of 1e-7.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
index 65947be0..faccd038 100644
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-no-glitch.html
@@ -2,16 +2,14 @@
 <html>
 
 <head>
-  <script src="../../resources/js-test.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script> 
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
 </head>
 
 <body>
   <script>
-    description('Test if StereoPannerNode producing glitches by crossing zero.');
-    window.jsTestIsAsync = true;
-
     var sampleRate = 44100;
     var renderDuration = 0.5;
 
@@ -42,7 +40,8 @@
       // samples are identical, the transition has not started.
       while (chanL[index-1] === chanL[index] || chanR[index-1] === chanR[index]) {
         if (++index >= input.length) {
-          testFailed('No transition found in the channel data.');
+          Should(false, 'Transition in the channel data')
+            .summarize('found', 'not found');
           return null;
         }
       }
@@ -52,13 +51,16 @@
       // the transition is still ongoing.
       while (chanL[index-1] !== chanL[index] || chanR[index-1] !== chanR[index]) {
         if (++index >= input.length) {
-          testFailed('A transition found but the buffer ended prematurely.');
+          Should(false, 'Transition found')
+            .summarize('', 'but the buffer ended prematurely');
           return null;
         }
       }
       end = index;
 
-      testPassed('Transition found between sample #' + start + ' and #' + end + '.');
+      Should('Transition found between sample #' + start + ' and #' + end,
+        true)
+        .summarize('correctly', 'incorrectly');
 
       return {
         left: chanL.subarray(start, end),
@@ -171,7 +173,6 @@
 
     audit.defineTask('finish-test', function (done) {
       done();
-      finishJSTest();
     });
 
     audit.runTasks(
@@ -179,8 +180,6 @@
       'positive-to-negative',
       'finish-test'
     );
-
-    successfullyParsed = true;
   </script>
 </body>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning-expected.txt b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning-expected.txt
deleted file mode 100644
index befcc60..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning-expected.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-CONSOLE WARNING: line 125: StereoPanner.pan.value -1.0625 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value -1.04104 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value -1.01957 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value 1.01957 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value 1.04104 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value 1.0625 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value -1.0625 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value -1.04104 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value -1.01957 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value 1.01957 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value 1.04104 outside nominal range [-1, 1]; value will be clamped.
-CONSOLE WARNING: line 125: StereoPanner.pan.value 1.0625 outside nominal range [-1, 1]; value will be clamped.
-Test panning model of StereoPannerNode.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS Number of impulses matches the number of panner nodes.
-PASS All impulses at expected offsets.
-PASS Left channel gain values are correct.
-PASS Right channel gain values are correct.
-PASS Test for mono input: passed.
-PASS Number of impulses matches the number of panner nodes.
-PASS All impulses at expected offsets.
-PASS Left channel gain values are correct.
-PASS Right channel gain values are correct.
-PASS Test for stereo input: passed.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
index a2711440..3b9d766a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
+++ b/third_party/WebKit/LayoutTests/webaudio/StereoPanner/stereopannernode-panning.html
@@ -2,18 +2,15 @@
 <html>
 
 <head>
-  <script src="../../resources/js-test.js"></script>
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script> 
   <script src="../resources/audit-util.js"></script>
   <script src="../resources/audio-testing.js"></script>
   <script src="../resources/stereopanner-testing.js"></script>
 </head>
 
 <body>
-  <div id="description"></div>
-  <div id="console"></div>
   <script>
-    description('Test panning model of StereoPannerNode.');
-    window.jsTestIsAsync = true;
 
     var audit = Audit.createTaskRunner();
 
@@ -27,12 +24,9 @@
 
     audit.defineTask('finish-test', function (done) {
       done();
-      finishJSTest();
     });
 
     audit.runTasks('mono-test', 'stereo-test', 'finish-test');
-
-    successfullyParsed = true;
   </script>
 </body>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audit.js b/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
index 940cff5..399137d3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
@@ -970,11 +970,36 @@
    */
   class Task {
 
+    /**
+     * Task constructor.
+     * @param  {Object} taskRunner Reference of associated task runner.
+     * @param  {String||Object} taskLabel Task label if a string is given. This
+     *                                    parameter can be a dictionary with the
+     *                                    following fields.
+     * @param  {String} taskLabel.label Task label.
+     * @param  {String} taskLabel.description Description of task.
+     * @param  {Function} taskFunction Task function to be performed.
+     * @return {Object} Task object.
+     */
     constructor (taskRunner, taskLabel, taskFunction) {
       this._taskRunner = taskRunner;
       this._taskFunction = taskFunction;
-      this._label = taskLabel;
-      this._description = '';
+
+      if (typeof taskLabel === 'string') {
+        this._label = taskLabel;
+        this._description = null;
+      } else if (typeof taskLabel === 'object') {
+        if (typeof taskLabel.label !== 'string') {
+          _throwException('Task.constructor:: task label must be string.');
+        }
+        this._label = taskLabel.label;
+        this._description = (typeof taskLabel.description === 'string')
+            ? taskLabel.description : null;
+      } else {
+        _throwException('Task.constructor:: task label must be a string or ' +
+                        'a dictionary.');
+      }
+
       this._state = TaskState.PENDING;
       this._result = true;
 
@@ -982,12 +1007,12 @@
       this._failedAssertions = 0;
     }
 
-    // Set the description of this task. This is printed out in the test
-    // result.
-    describe (message) {
-      this._description = message;
-      _logPassed('> [' + this._label + '] '
-          + this._description);
+    // TODO(hongchan): This does not have any effect. Remove this method and fix
+    // layout test files use it.
+    describe (message) {}
+
+    get label () {
+      return this._label;
     }
 
     get state () {
@@ -1011,6 +1036,11 @@
     // task function.
     run () {
       this._state = TaskState.STARTED;
+
+      // Print out the task entry with label and description.
+      _logPassed('> [' + this._label + '] '
+          + (this._description ? this._description : ''));
+
       this._taskFunction(
           this,
           this.should.bind(this));
@@ -1103,14 +1133,16 @@
       done();
     }
 
+    // |taskLabel| can be either a string or a dictionary. See Task constructor
+    // for the detail.
     define (taskLabel, taskFunction) {
-      if (this._tasks.hasOwnProperty(taskLabel)) {
+      let task = new Task(this, taskLabel, taskFunction);
+      if (this._tasks.hasOwnProperty(task.label)) {
         _throwException('Audit.define:: Duplicate task definition.');
         return;
       }
-
-      this._tasks[taskLabel] = new Task(this, taskLabel, taskFunction);
-      this._taskSequence.push(taskLabel);
+      this._tasks[task.label] = task;
+      this._taskSequence.push(task.label);
     }
 
     // Start running all the tasks scheduled. Multiple task names can be passed
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/stereopanner-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/stereopanner-testing.js
index 60d947b..0e573e9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/stereopanner-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/stereopanner-testing.js
@@ -176,59 +176,23 @@
 
 
   Test.prototype.showResult = function () {
-    if (this.impulseIndex === gNodesToCreate) {
-      testPassed('Number of impulses matches the number of panner nodes.');
-    } else {
-      testFailed('Number of impulses is incorrect. (Found '
-        + this.impulseIndex
-        + ' but expected '
-        + gNodesToCreate
-        + ')'
-      );
-      this.success = false;
-    }
+    Should("Number of impulses found", this.impulseIndex)
+      .beEqualTo(gNodesToCreate);
 
-    if (this.errors.length === 0) {
-      testPassed('All impulses at expected offsets.');
-    } else {
-      testFailed(this.errors.length + ' timing errors found in '
-        + this.nodesToCreate + ' panner nodes.'
-      );
-      for (var i = 0; i < this.errors.length; i++) {
-        testFailed('Impulse at sample ' + this.errors[i].actual
-          + ' but expected ' + this.errors[i].expected
-        );
-      }
-      this.success = false;
-    }
+    Should("Number of impulse at the wrong offset", this.errors.length)
+      .beEqualTo(0);
 
-    if (this.maxErrorL <= this.maxAllowedError) {
-      testPassed('Left channel gain values are correct.');
-    } else {
-      testFailed('Left channel gain values are incorrect.  Max error = '
-        + this.maxErrorL + ' at time ' + this.onsets[this.maxErrorIndexL]
-        + ' (threshold = ' + this.maxAllowedError + ')'
-      );
-      this.success = false;
-    }
+    Should("Left channel error magnitude", this.maxErrorL)
+      .beLessThanOrEqualTo(this.maxAllowedError);
 
-    if (this.maxErrorR <= this.maxAllowedError) {
-      testPassed('Right channel gain values are correct.');
-    } else {
-      testFailed('Right channel gain values are incorrect.  Max error = '
-        + this.maxErrorR + ' at time ' + this.onsets[this.maxErrorIndexR]
-        + ' (threshold = ' + this.maxAllowedError + ')'
-      );
-      this.success = false;
-    }
+    Should("Right channel error magnitude", this.maxErrorR)
+      .beLessThanOrEqualTo(this.maxAllowedError);
   };
 
 
   Test.prototype.finish = function () {
-    if (this.success)
-      testPassed(this.description + ': passed.');
-    else
-      testFailed(this.description + ': failed.');
+    Should(this.description, this.success)
+      .summarize('passed', 'failed');
   };
 
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt
index 92d5047..6114440 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt
@@ -32,6 +32,10 @@
 PASS   Suspending OAC with no argument rejected correctly with TypeError. 
 PASS   Start OAC rendering resolved correctly. 
 PASS < [basic] All assertions passed. (total 20 assertions) 
-PASS # AUDIT TASK RUNNER FINISHED: 2 tasks ran successfully. 
+PASS > [dummy-label-string]  
+PASS < [dummy-label-string] All assertions passed. (total 0 assertions) 
+PASS > [dummy-label-object]  
+PASS < [dummy-label-object] All assertions passed. (total 0 assertions) 
+PASS # AUDIT TASK RUNNER FINISHED: 4 tasks ran successfully. 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html
index b74e0aba..ea959d5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html
@@ -20,59 +20,62 @@
 
 
     // Basic assertions.
-    audit.define('basic-failure', function (task, should) {
-      task.describe('Testing basic assertion failures.');
+    audit.define({
+        label: 'basic-failure',
+        description: 'Testing basic assertion failures.'
+      }, function (task, should) {
+        should(function () { var foo = bar; }, 'Setting foo to bar').notThrow();
+        should(function () { var foo = 0; }).throw('ReferenceError');
+        should(3 > 5, '3 < 5').beTrue();
+        should(true).beFalse();
+        should(1, 'The number of channels').beEqualTo(2);
+        should(1).notBeEqualTo(1);
+        should(typeof 3.141592, 'typeof 3.141592').beEqualTo('string');
+        should(1).beGreaterThan(2);
+        should(1).beGreaterThanOrEqualTo(2);
+        should(2).beLessThan(1);
+        should(2).beLessThanOrEqualTo(1);
+        should(should(1).beEqualTo(2), 'should(1).beEqualTo(2)').beTrue();
+        should(false, 'The message is').message('truthful!', 'false!');
 
-      should(function () { var foo = bar; }, 'Setting foo to bar').notThrow();
-      should(function () { var foo = 0; }).throw('ReferenceError');
-      should(3 > 5, '3 < 5').beTrue();
-      should(true).beFalse();
-      should(1, 'The number of channels').beEqualTo(2);
-      should(1).notBeEqualTo(1);
-      should(typeof 3.141592, 'typeof 3.141592').beEqualTo('string');
-      should(1).beGreaterThan(2);
-      should(1).beGreaterThanOrEqualTo(2);
-      should(2).beLessThan(1);
-      should(2).beLessThanOrEqualTo(1);
-      should(should(1).beEqualTo(2), 'should(1).beEqualTo(2)').beTrue();
-      should(false, 'The message is').message('truthful!', 'false!');
-
-      let oac = new OfflineAudioContext(1, 128, 44100);
-      Promise.all([
-          should(oac.decodeAudioData(), 'Decoding audio data with no argument')
-            .beResolved(),
-          should(oac.startRendering(), 'Start OAC rendering').beRejected(),
-          should(oac.suspend(), 'Suspending OAC with no argument')
-            .beRejectedWith('IndexSizeError')
-        ]).then(task.done.bind(task));
-    });
+        let oac = new OfflineAudioContext(1, 128, 44100);
+        Promise.all([
+            should(oac.decodeAudioData(), 'Decoding audio data with no argument')
+              .beResolved(),
+            should(oac.startRendering(), 'Start OAC rendering').beRejected(),
+            should(oac.suspend(), 'Suspending OAC with no argument')
+              .beRejectedWith('IndexSizeError')
+          ]).then(task.done.bind(task));
+      }
+    );
 
 
     // Numerical assertions.
-    audit.define('numerical-failures', function (task, should) {
-      task.describe('Testing numerical assertion failures.');
-
-      should(0).beCloseTo(0.1, { threshold: 0 });
-      should(59, 'The measured decibel').beCloseTo(62, { threshold: 0.01 });
-      should([1, 8, 11, 18, 6, 5, 5, 5, 123, 49]).beConstantValueOf(5);
-      should([0, 0, 0]).notBeConstantValueOf(0);
-      should([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
-        .beEqualToArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
-      should([1, 1, 1, 1, 2, 2, 3, 3, 3]).containValues([1, 3, 2]);
-      should([0.5, 0.5, 0.55, 0.5, 0.45, 0.5]).notGlitch(0.04);
-      should([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9])
-        .beCloseToArray([0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], {
-            absoluteThreshold: 0.02
-          });
-      should([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9])
-        .beCloseToArray([0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], {
-            relativeThreshold: 0.1
-          });
-      should([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9])
-        .beCloseToArray([0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], {
-            absoluteThreshold: 0.02,
-            relativeThreshold: 0.1
-          });
+    audit.define({
+        label: 'numerical-failures',
+        description: 'Testing numerical assertion failures.'
+      }, function (task, should) {
+        should(0).beCloseTo(0.1, { threshold: 0 });
+        should(59, 'The measured decibel').beCloseTo(62, { threshold: 0.01 });
+        should([1, 8, 11, 18, 6, 5, 5, 5, 123, 49]).beConstantValueOf(5);
+        should([0, 0, 0]).notBeConstantValueOf(0);
+        should([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+          .beEqualToArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+        should([1, 1, 1, 1, 2, 2, 3, 3, 3]).containValues([1, 3, 2]);
+        should([0.5, 0.5, 0.55, 0.5, 0.45, 0.5]).notGlitch(0.04);
+        should([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9])
+          .beCloseToArray([0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], {
+              absoluteThreshold: 0.02
+            });
+        should([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9])
+          .beCloseToArray([0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], {
+              relativeThreshold: 0.1
+            });
+        should([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9])
+          .beCloseToArray([0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1], {
+              absoluteThreshold: 0.02,
+              relativeThreshold: 0.1
+            });
 
       // Tests extra info
       should([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
@@ -82,7 +85,6 @@
       task.done();
     });
 
-
     // With no argument, this executes all tasks in the order defined.
     audit.run();
   </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html
index e83cb2f..27bc852 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html
@@ -12,53 +12,69 @@
 
 
     // Basic assertion testing.
-    audit.define('basic', function (task, should) {
-      task.describe('Simple unit tests for basic assertions.');
+    audit.define({
+        label: 'basic',
+        description: 'Simple unit tests for basic assertions.'
+      }, function (task, should) {
+        should(OfflineAudioContext, 'OfflineAudioContext').exist();
+        should(function () { var foo1 = 0; }, 'Setting foo1 to 0').notThrow();
+        should(function () { var foo2 = bar; }).throw();
+        should(function () { var foo3 = bar; }).throw('ReferenceError');
+        should(() => { should(); }, 'Calling should() with no argument')
+            .throw('Error');
+        should(3 < 5, '3 < 5').beTrue();
+        should(false).beFalse();
+        should(1).beEqualTo(1)
+        should(1).notBeEqualTo(2)
+        should(typeof AudioContext.prototype).beEqualTo('object');
+        should(2).beGreaterThan(1);
+        should(2).beGreaterThanOrEqualTo(2);
+        should(1).beLessThan(2);
+        should(1).beLessThanOrEqualTo(1);
+        should(should(1).beEqualTo(1), 'should(1).beEqualTo(1)').beTrue();
+        should(true, 'The message is').message('truthful!', 'false!');
 
-      should(OfflineAudioContext, 'OfflineAudioContext').exist();
-      should(function () { var foo1 = 0; }, 'Setting foo1 to 0').notThrow();
-      should(function () { var foo2 = bar; }).throw();
-      should(function () { var foo3 = bar; }).throw('ReferenceError');
-      should(() => { should(); }, 'Calling should() with no argument')
-          .throw('Error');
-      should(3 < 5, '3 < 5').beTrue();
-      should(false).beFalse();
-      should(1).beEqualTo(1)
-      should(1).notBeEqualTo(2)
-      should(typeof AudioContext.prototype).beEqualTo('object');
-      should(2).beGreaterThan(1);
-      should(2).beGreaterThanOrEqualTo(2);
-      should(1).beLessThan(2);
-      should(1).beLessThanOrEqualTo(1);
-      should(should(1).beEqualTo(1), 'should(1).beEqualTo(1)').beTrue();
-      should(true, 'The message is').message('truthful!', 'false!');
-
-      let oac = new OfflineAudioContext(1, 128, 44100);
-      Promise.all([
-          should(oac.startRendering(), 'Start OAC rendering').beResolved(),
-          should(oac.decodeAudioData(), 'Decoding audio data with no argument')
-            .beRejected(),
-          should(oac.suspend(), 'Suspending OAC with no argument')
-            .beRejectedWith('TypeError')
-        ]).then(task.done.bind(task));
-    });
+        let oac = new OfflineAudioContext(1, 128, 44100);
+        Promise.all([
+            should(oac.startRendering(), 'Start OAC rendering').beResolved(),
+            should(oac.decodeAudioData(), 'Decoding audio data with no argument')
+              .beRejected(),
+            should(oac.suspend(), 'Suspending OAC with no argument')
+              .beRejectedWith('TypeError')
+          ]).then(task.done.bind(task));
+      }
+    );
 
 
     // Advanced, mostly array-based numerical testing. Note that some codes
     // are commented out to avoid the trybot failure. These failures are
     // intentional, to demonstrate how the detailed failure report works.
-    audit.define('numerical', function (task, should) {
-      task.describe('Numerical assertion unit test.');
+    audit.define({
+        label: 'numerical',
+        description: 'Numerical assertion unit test.'
+      }, function (task, should) {
+        should(2.3).beCloseTo(2, { threshold: 0.3 });
+        should([1, 1, 1]).beConstantValueOf(1);
+        should([1, 0, 1]).notBeConstantValueOf(1);
+        should([1, 0, 0, 1]).notBeConstantValueOf(1);
+        should([1, 1, 1]).beEqualToArray([1, 1, 1]);
+        should([1, 1, 1, 1, 2, 2, 3, 3, 3])
+          .containValues([1, 2, 3], 'one, two, three');
+        should([0.5, 0.5, 0.55, 0.5, 0.45, 0.5]).notGlitch(0.06);
+        task.done();
+      }
+    );
 
-      should(2.3).beCloseTo(2, { threshold: 0.3 });
-      should([1, 1, 1]).beConstantValueOf(1);
-      should([1, 0, 1]).notBeConstantValueOf(1);
-      should([1, 0, 0, 1]).notBeConstantValueOf(1);
-      should([1, 1, 1]).beEqualToArray([1, 1, 1]);
-      should([1, 1, 1, 1, 2, 2, 3, 3, 3])
-        .containValues([1, 2, 3], 'one, two, three');
-      should([0.5, 0.5, 0.55, 0.5, 0.45, 0.5]).notGlitch(0.06);
 
+    // The task headline needs to be printed even if there is no description is
+    // given.
+    audit.define('dummy-label-string', function (task) {
+      task.done();
+    });
+
+
+    // Test the same thing in a differen way.
+    audit.define({ label: 'dummy-label-object' }, function (task) {
       task.done();
     });
 
@@ -67,15 +83,13 @@
     // runs. If you would like to see how failure cases get printed, include
     // this task and launch the task runner.
     audit.define('empty', function (task, should) {
-      task.describe('This is an empty task.');
-
       task.done();
     });
 
 
     // You can enumerate tasks you want to execute in the order, or simply pass
     // no argument to run all the defined tasks.
-    audit.run('numerical', 'basic');
+    audit.run('numerical', 'basic', 'dummy-label-string', 'dummy-label-object');
   </script>
 </body>
 </html>
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 d471baa..0f46396 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -6763,6 +6763,15 @@
     method set
     method toString
     method values
+interface USB : EventTarget
+    attribute @@toStringTag
+    getter onconnect
+    getter ondisconnect
+    method constructor
+    method getDevices
+    method requestDevice
+    setter onconnect
+    setter ondisconnect
 interface USBAlternateInterface
     attribute @@toStringTag
     getter alternateSetting
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 00416e2..dbc53e9 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -3198,7 +3198,7 @@
       this, PerformanceMonitor::kDiscouragedAPIUse,
       "Avoid using document.write().", 0, nullptr);
   InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-      this, "document.write", true);
+      this, "Document.write", true);
   m_parser->insert(text);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 36834df6..5145d37 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2755,10 +2755,6 @@
             .rootEditableElement())
       return;
 
-    // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
-    // needs to be audited.  See http://crbug.com/590369 for more details.
-    document().updateStyleAndLayoutIgnorePendingStylesheets();
-
     // FIXME: We should restore the previous selection if there is one.
     // Passing DoNotSetFocus as this function is called after
     // FocusController::setFocusedElement() and we don't want to change the
@@ -2904,7 +2900,7 @@
 
 void Element::setInnerHTML(const String& html, ExceptionState& exceptionState) {
   InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-      &document(), "setInnerHTML", true);
+      &document(), "Element.setInnerHTML", true);
   if (DocumentFragment* fragment = createFragmentForInnerOuterHTML(
           html, this, AllowScriptingContent, "innerHTML", exceptionState)) {
     ContainerNode* container = this;
diff --git a/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp b/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
index 3fef3b49..167ddabab 100644
--- a/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
+++ b/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
@@ -29,7 +29,7 @@
   InspectorInstrumentation::asyncTaskScheduled(
       m_context, "requestAnimationFrame", callback);
   InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-      m_context, "requestAnimationFrame", true);
+      m_context, "DOMWindow.requestAnimationFrame", true);
   return id;
 }
 
@@ -38,7 +38,7 @@
     if (m_callbacks[i]->m_id == id) {
       InspectorInstrumentation::asyncTaskCanceled(m_context, m_callbacks[i]);
       InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-          m_context, "cancelAnimationFrame", true);
+          m_context, "DOMWindow.cancelAnimationFrame", true);
       m_callbacks.remove(i);
       TRACE_EVENT_INSTANT1("devtools.timeline", "CancelAnimationFrame",
                            TRACE_EVENT_SCOPE_THREAD, "data",
@@ -50,7 +50,7 @@
     if (callback->m_id == id) {
       InspectorInstrumentation::asyncTaskCanceled(m_context, callback);
       InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-          m_context, "cancelAnimationFrame", true);
+          m_context, "DOMWindow.cancelAnimationFrame", true);
       TRACE_EVENT_INSTANT1("devtools.timeline", "CancelAnimationFrame",
                            TRACE_EVENT_SCOPE_THREAD, "data",
                            InspectorAnimationFrameEvent::data(m_context, id));
@@ -75,7 +75,7 @@
           "devtools.timeline", "FireAnimationFrame", "data",
           InspectorAnimationFrameEvent::data(m_context, callback->m_id));
       InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-          m_context, "animationFrameFired", false);
+          m_context, "DOMWindow.requestAnimationFrame.callback", false);
       InspectorInstrumentation::AsyncTask asyncTask(m_context, callback);
       PerformanceMonitor::HandlerCall handlerCall(
           m_context, "requestAnimationFrame", true);
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
index 85dc348..913662e9 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
@@ -242,35 +242,21 @@
   if (target->ensureIntersectionObserverData().getObservationFor(*this))
     return;
 
-  bool isDOMDescendant = true;
-  bool shouldReportRootBounds = false;
+  bool shouldReportRootBounds = true;
   if (rootIsImplicit()) {
     Frame* rootFrame = targetFrame->tree().top();
     DCHECK(rootFrame);
-    if (rootFrame == targetFrame) {
-      shouldReportRootBounds = true;
-    } else {
+    if (rootFrame != targetFrame) {
       shouldReportRootBounds =
           targetFrame->securityContext()->getSecurityOrigin()->canAccess(
               rootFrame->securityContext()->getSecurityOrigin());
     }
-  } else {
-    shouldReportRootBounds = true;
-    isDOMDescendant = root()->isShadowIncludingInclusiveAncestorOf(target);
   }
 
   IntersectionObservation* observation =
       new IntersectionObservation(*this, *target, shouldReportRootBounds);
   target->ensureIntersectionObserverData().addObservation(*observation);
   m_observations.add(observation);
-
-  if (!isDOMDescendant) {
-    root()->document().addConsoleMessage(
-        ConsoleMessage::create(JSMessageSource, WarningMessageLevel,
-                               "IntersectionObserver.observe(target): target "
-                               "element is not a descendant of root."));
-  }
-
   if (FrameView* frameView = targetFrame->view())
     frameView->scheduleAnimation();
 }
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 45a0d2b..ec500eb 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -343,12 +343,7 @@
 
   clearCachedRangeIfSelectionOfDocument();
 
-  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
-  // needs to be audited.  See http://crbug.com/590369 for more details.
-  // In the long term, we should change FrameSelection::setSelection to take a
-  // parameter that does not require clean layout, so that modifying selection
-  // no longer performs synchronous layout by itself.
-  // TODO(editing-dev): Once SVG USE element doesn't modifies DOM tree, we
+  // TODO(editing-dev): Once SVG USE element doesn't modify DOM tree, we
   // should get rid of this update layout call.
   // See http://crbug.com/566281
   // See "svg/text/textpath-reference-crash.html"
@@ -424,10 +419,6 @@
   else
     return;
 
-  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
-  // needs to be audited.  See http://crbug.com/590369 for more details.
-  frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
-
   frame()->selection().modify(alter, direction, granularity);
 }
 
@@ -604,13 +595,6 @@
     return;
   }
 
-  // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
-  // needs to be audited.  See http://crbug.com/590369 for more details.
-  // In the long term, we should change FrameSelection::setSelection to take a
-  // parameter that does not require clean layout, so that modifying selection
-  // no longer performs synchronous layout by itself.
-  frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
-
   if (rangeCount() == 0) {
     selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY);
     cacheRangeIfSelectionOfDocument(newRange);
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index cf8b08e..8db85385 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -773,7 +773,10 @@
 
 void Editor::applyStyle(StylePropertySet* style,
                         InputEvent::InputType inputType) {
-  switch (frame().selection().getSelectionType()) {
+  switch (frame()
+              .selection()
+              .computeVisibleSelectionInDOMTreeDeprecated()
+              .getSelectionType()) {
     case NoSelection:
       // do nothing
       break;
@@ -1428,9 +1431,14 @@
   // call does not call EditorClient::respondToChangedSelection(), which, on the
   // Mac, sends selection change notifications and starts a new kill ring
   // sequence, but we want to do these things (matches AppKit).
-  if (selectionDidNotChangeDOMPosition)
-    client().respondToChangedSelection(m_frame,
-                                       frame().selection().getSelectionType());
+  if (selectionDidNotChangeDOMPosition) {
+    client().respondToChangedSelection(
+        m_frame,
+        frame()
+            .selection()
+            .computeVisibleSelectionInDOMTreeDeprecated()
+            .getSelectionType());
+  }
 }
 
 IntRect Editor::firstRectForRange(const EphemeralRange& range) const {
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index f9b4746..e63d68b 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -265,11 +265,6 @@
                       ? ScrollAlignment::alignTopAlways
                       : ScrollAlignment::alignToEdgeIfNeeded;
 
-    // TODO(editing-dev): The use of
-    // updateStyleAndLayoutIgnorePendingStylesheets
-    // needs to be audited.  See http://crbug.com/590369 for more details.
-    document().updateStyleAndLayoutIgnorePendingStylesheets();
-
     revealSelection(alignment, RevealExtent);
   }
 
@@ -975,7 +970,7 @@
 
   LayoutRect rect;
 
-  switch (getSelectionType()) {
+  switch (computeVisibleSelectionInDOMTree().getSelectionType()) {
     case NoSelection:
       return;
     case CaretSelection:
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h
index a68b2bee..2e8a12d 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.h
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -158,10 +158,6 @@
 
   bool contains(const LayoutPoint&);
 
-  SelectionType getSelectionType() const {
-    return computeVisibleSelectionInDOMTreeDeprecated().getSelectionType();
-  }
-
   bool modify(EAlteration,
               SelectionDirection,
               TextGranularity,
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index 82cc8352..e8cd1338 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -129,10 +129,8 @@
   LocalFrame* frame = document().frame();
   DCHECK(frame);
   EditingState editingState;
-  {
-    EventQueueScope eventQueueScope;
-    doApply(&editingState);
-  }
+  EventQueueScope eventQueueScope;
+  doApply(&editingState);
 
   // Only need to call appliedEditing for top-level commands, and TypingCommands
   // do it on their own (see TypingCommand::typingAddedToOpenCommand).
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index 164a6cb..43aace2 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -273,7 +273,10 @@
   if (pointerEventName == EventTypeNames::pointermove) {
     HeapVector<Member<PointerEvent>> coalescedPointerEvents;
     for (const auto& coalescedMouseEvent : coalescedMouseEvents) {
-      DCHECK_EQ(mouseEvent.id, coalescedMouseEvent.id);
+      // TODO(crbug.com/694742): We will set the id from low-level OS events
+      // and enable this DCHECK again.
+      // DCHECK_EQ(mouseEvent.id, coalescedMouseEvent.id);
+
       // TODO(crbug.com/684292): We need further investigation of why the
       // following DCHECK fails.
       // DCHECK_EQ(mouseEvent.pointerType, coalescedMouseEvent.pointerType);
diff --git a/third_party/WebKit/Source/core/frame/DOMWindow.cpp b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
index f2bd3f1a..6b33d24 100644
--- a/third_party/WebKit/Source/core/frame/DOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
@@ -378,8 +378,8 @@
   if (!frame()->shouldClose())
     return;
 
-  InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(context, "close",
-                                                              true);
+  InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
+      context, "DOMWindow.close", true);
 
   page->closeSoon();
 
diff --git a/third_party/WebKit/Source/core/frame/FrameOwner.h b/third_party/WebKit/Source/core/frame/FrameOwner.h
index 6a2a914..cbc0741 100644
--- a/third_party/WebKit/Source/core/frame/FrameOwner.h
+++ b/third_party/WebKit/Source/core/frame/FrameOwner.h
@@ -9,6 +9,7 @@
 #include "core/dom/SandboxFlags.h"
 #include "platform/heap/Handle.h"
 #include "platform/scroll/ScrollTypes.h"
+#include "public/platform/WebFeaturePolicy.h"
 #include "public/platform/WebVector.h"
 #include "public/platform/modules/permissions/permission.mojom-blink.h"
 
@@ -51,6 +52,7 @@
   virtual AtomicString csp() const = 0;
   virtual const WebVector<mojom::blink::PermissionName>& delegatedPermissions()
       const = 0;
+  virtual const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const = 0;
 };
 
 // TODO(dcheng): This class is an internal implementation detail of provisional
@@ -89,6 +91,10 @@
                         ());
     return permissions;
   }
+  const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override {
+    DEFINE_STATIC_LOCAL(WebVector<WebFeaturePolicyFeature>, features, ());
+    return features;
+  }
 
  private:
   // Intentionally private to prevent redundant checks when the type is
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 9332683..a55d1e43 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -1343,6 +1343,17 @@
       isPaintable() ? ImageBitmap::create(this, cropRect, options) : nullptr);
 }
 
+void HTMLCanvasElement::setPlaceholderFrame(
+    RefPtr<StaticBitmapImage> image,
+    WeakPtr<OffscreenCanvasFrameDispatcher> dispatcher,
+    RefPtr<WebTaskRunner> taskRunner,
+    unsigned resourceId) {
+  OffscreenCanvasPlaceholder::setPlaceholderFrame(
+      std::move(image), std::move(dispatcher), std::move(taskRunner),
+      resourceId);
+  notifyListenersCanvasChanged();
+}
+
 bool HTMLCanvasElement::isOpaque() const {
   return m_context && !m_context->creationAttributes().alpha();
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index 4c9dfeb6..3acb5ed 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -211,6 +211,11 @@
                                   const ImageBitmapOptions&,
                                   ExceptionState&) override;
 
+  // OffscreenCanvasPlaceholder implementation.
+  void setPlaceholderFrame(RefPtr<StaticBitmapImage>,
+                           WeakPtr<OffscreenCanvasFrameDispatcher>,
+                           RefPtr<WebTaskRunner>,
+                           unsigned resourceId) override;
   DECLARE_VIRTUAL_TRACE();
 
   DECLARE_VIRTUAL_TRACE_WRAPPERS();
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index 64a0f46..ab7e818 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -231,6 +231,12 @@
   return permissions;
 }
 
+const WebVector<WebFeaturePolicyFeature>&
+HTMLFrameOwnerElement::allowedFeatures() const {
+  DEFINE_STATIC_LOCAL(WebVector<WebFeaturePolicyFeature>, features, ());
+  return features;
+}
+
 Document* HTMLFrameOwnerElement::getSVGDocument(
     ExceptionState& exceptionState) const {
   Document* doc = contentDocument();
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
index 16e7a51b..59ea874 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
@@ -93,6 +93,7 @@
   AtomicString csp() const override { return nullAtom; }
   const WebVector<mojom::blink::PermissionName>& delegatedPermissions()
       const override;
+  const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override;
 
   DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
index b9512059..90a0daed 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -231,15 +231,14 @@
 
 void HTMLIFrameElement::allowValueWasSet() {
   String invalidTokens;
-  m_allowedFeatureNames = m_allow->parseAllowedFeatureNames(invalidTokens);
+  m_allowedFeatures = m_allow->parseAllowedFeatureNames(invalidTokens);
   if (!invalidTokens.isNull()) {
     document().addConsoleMessage(ConsoleMessage::create(
         OtherMessageSource, ErrorMessageLevel,
         "Error while parsing the 'allow' attribute: " + invalidTokens));
   }
   setSynchronizedLazyAttribute(allowAttr, m_allow->value());
-  // TODO(lunalu): Once allowedFeatureNames is passed to frame owner, call
-  // frameOwnerPropertiesChanged.
+  frameOwnerPropertiesChanged();
 }
 
 ReferrerPolicy HTMLIFrameElement::referrerPolicyAttribute() {
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
index effd213..b137443 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
@@ -85,6 +85,9 @@
       const override {
     return m_delegatedPermissions;
   }
+  const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override {
+    return m_allowedFeatures;
+  }
 
   bool initializePermissionsAttribute();
 
@@ -98,7 +101,7 @@
   Member<HTMLIFrameElementAllow> m_allow;
 
   WebVector<mojom::blink::PermissionName> m_delegatedPermissions;
-  WebVector<WebFeaturePolicyFeature> m_allowedFeatureNames;
+  WebVector<WebFeaturePolicyFeature> m_allowedFeatures;
 
   ReferrerPolicy m_referrerPolicy;
 };
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index a86fbea..0d9a229 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -762,6 +762,9 @@
 void EventHandler::handleMouseLeaveEvent(const WebMouseEvent& event) {
   TRACE_EVENT0("blink", "EventHandler::handleMouseLeaveEvent");
 
+  Page* page = m_frame->page();
+  if (page)
+    page->chromeClient().clearToolTip(*m_frame);
   handleMouseMoveOrLeaveEvent(event, Vector<WebMouseEvent>(), 0, false, true);
 }
 
diff --git a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
index 29f825c..08bd48fa 100644
--- a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
@@ -4,6 +4,7 @@
 
 #include "core/input/EventHandler.h"
 
+#include <memory>
 #include "core/dom/Document.h"
 #include "core/dom/Range.h"
 #include "core/editing/Editor.h"
@@ -11,11 +12,11 @@
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
+#include "core/loader/EmptyClients.h"
 #include "core/page/AutoscrollController.h"
 #include "core/page/Page.h"
 #include "core/testing/DummyPageHolder.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include <memory>
 
 namespace blink {
 
@@ -29,7 +30,7 @@
 
   void setHtmlInnerHTML(const char* htmlContent);
 
- private:
+ protected:
   std::unique_ptr<DummyPageHolder> m_dummyPageHolder;
 };
 
@@ -461,4 +462,63 @@
   // This test passes if it doesn't crash.
 }
 
+class TooltipCapturingChromeClient : public EmptyChromeClient {
+ public:
+  TooltipCapturingChromeClient() {}
+
+  void setToolTip(LocalFrame&, const String& str, TextDirection) override {
+    m_lastToolTip = str;
+  }
+
+  String& lastToolTip() { return m_lastToolTip; }
+
+ private:
+  String m_lastToolTip;
+};
+
+class EventHandlerTooltipTest : public EventHandlerTest {
+ public:
+  EventHandlerTooltipTest() {}
+
+  void SetUp() override {
+    m_chromeClient = new TooltipCapturingChromeClient();
+    Page::PageClients clients;
+    fillWithEmptyClients(clients);
+    clients.chromeClient = m_chromeClient.get();
+    m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600), &clients);
+  }
+
+  String& lastToolTip() { return m_chromeClient->lastToolTip(); }
+
+ private:
+  Persistent<TooltipCapturingChromeClient> m_chromeClient;
+};
+
+TEST_F(EventHandlerTooltipTest, mouseLeaveClearsTooltip) {
+  setHtmlInnerHTML(
+      "<style>.box { width: 100%; height: 100%; }</style>"
+      "<img src='image.png' class='box' title='tooltip'>link</img>");
+
+  EXPECT_EQ(WTF::String(), lastToolTip());
+
+  WebMouseEvent mouseMoveEvent(
+      WebInputEvent::MouseMove, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
+      WebPointerProperties::Button::NoButton, 0, WebInputEvent::NoModifiers,
+      TimeTicks::Now().InSeconds());
+  mouseMoveEvent.setFrameScale(1);
+  document().frame()->eventHandler().handleMouseMoveEvent(
+      mouseMoveEvent, Vector<WebMouseEvent>());
+
+  EXPECT_EQ("tooltip", lastToolTip());
+
+  WebMouseEvent mouseLeaveEvent(
+      WebInputEvent::MouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0),
+      WebPointerProperties::Button::NoButton, 0, WebInputEvent::NoModifiers,
+      TimeTicks::Now().InSeconds());
+  mouseLeaveEvent.setFrameScale(1);
+  document().frame()->eventHandler().handleMouseLeaveEvent(mouseLeaveEvent);
+
+  EXPECT_EQ(WTF::String(), lastToolTip());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
index 6919dc6..bb3419a7 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -452,7 +452,9 @@
   return Response::OK();
 }
 
-Response InspectorPageAgent::navigate(const String& url, String* outFrameId) {
+Response InspectorPageAgent::navigate(const String& url,
+                                      Maybe<String> referrer,
+                                      String* outFrameId) {
   *outFrameId = frameId(m_inspectedFrames->root());
   return Response::OK();
 }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
index 665331f..0fdc570 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
@@ -111,7 +111,9 @@
   Response setAutoAttachToCreatedPages(bool) override;
   Response reload(Maybe<bool> bypassCache,
                   Maybe<String> scriptToEvaluateOnLoad) override;
-  Response navigate(const String& url, String* frameId) override;
+  Response navigate(const String& url,
+                    Maybe<String> referrer,
+                    String* frameId) override;
   Response stopLoading() override;
   Response getResourceTree(
       std::unique_ptr<protocol::Page::FrameResourceTree>* frameTree) override;
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 74c3a3a..dd4e35c 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -251,7 +251,8 @@
             {
                 "name": "navigate",
                 "parameters": [
-                    { "name": "url", "type": "string", "description": "URL to navigate the page to." }
+                    { "name": "url", "type": "string", "description": "URL to navigate the page to." },
+                    { "name": "referrer", "type": "string", "optional": true, "experimental": true, "description": "Referrer URL." }
                 ],
                 "returns": [
                     { "name": "frameId", "$ref": "FrameId", "experimental": true, "description": "Frame id that will be navigated." }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
index f7056fd..f3f7f85 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
@@ -82,10 +82,10 @@
                                                 const ComputedStyle* oldStyle) {
   LayoutSVGHiddenContainer::styleDidChange(diff, oldStyle);
 
-  if (!m_registered) {
-    m_registered = true;
-    registerResource();
-  }
+  if (m_registered)
+    return;
+  m_registered = true;
+  svgTreeScopeResourcesFromElement(element()).updateResource(m_id, this);
 }
 
 void LayoutSVGResourceContainer::detachAllClients() {
@@ -116,8 +116,7 @@
       svgTreeScopeResourcesFromElement(element());
   treeScopeResources.removeResource(m_id);
   m_id = element()->getIdAttribute();
-
-  registerResource();
+  treeScopeResources.updateResource(m_id, this);
 }
 
 void LayoutSVGResourceContainer::markAllClientsForInvalidation(
@@ -209,38 +208,6 @@
     removeAllClientsFromCache();
 }
 
-void LayoutSVGResourceContainer::registerResource() {
-  SVGTreeScopeResources& treeScopeResources =
-      svgTreeScopeResourcesFromElement(element());
-  if (!treeScopeResources.hasPendingResource(m_id)) {
-    treeScopeResources.addResource(m_id, this);
-    return;
-  }
-
-  SVGTreeScopeResources::SVGPendingElements* clients(
-      treeScopeResources.removePendingResource(m_id));
-
-  // Cache us with the new id.
-  treeScopeResources.addResource(m_id, this);
-
-  // Update cached resources of pending clients.
-  for (const auto& pendingClient : *clients) {
-    DCHECK(pendingClient->hasPendingResources());
-    treeScopeResources.clearHasPendingResourcesIfPossible(pendingClient);
-    LayoutObject* layoutObject = pendingClient->layoutObject();
-    if (!layoutObject)
-      continue;
-    DCHECK(layoutObject->isSVG());
-
-    StyleDifference diff;
-    diff.setNeedsFullLayout();
-    SVGResourcesCache::clientStyleChanged(layoutObject, diff,
-                                          layoutObject->styleRef());
-    layoutObject->setNeedsLayoutAndFullPaintInvalidation(
-        LayoutInvalidationReason::SvgResourceInvalidated);
-  }
-}
-
 static inline void removeFromCacheAndInvalidateDependencies(
     LayoutObject* object,
     bool needsLayout) {
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
index acd3c6c..1884621 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
@@ -99,8 +99,6 @@
   void removeClient(LayoutObject*);
   void detachAllClients();
 
-  void registerResource();
-
   AtomicString m_id;
   // Track global (markAllClientsForInvalidation) invals to avoid redundant
   // crawls.
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index d675d5d..1b97f12 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -1685,6 +1685,8 @@
     if (form)
       client()->dispatchWillSubmitForm(form);
 
+    m_frame->document()->cancelParsing();
+
     return false;
   }
   if (!LocalDOMWindow::allowPopUp(*m_frame) &&
diff --git a/third_party/WebKit/Source/core/loader/PingLoader.cpp b/third_party/WebKit/Source/core/loader/PingLoader.cpp
index e138e8b..6afde83 100644
--- a/third_party/WebKit/Source/core/loader/PingLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/PingLoader.cpp
@@ -110,7 +110,7 @@
  public:
   explicit BeaconBlob(Blob* data) : m_data(data) {
     const String& blobType = m_data->type();
-    if (!blobType.isEmpty() && isValidContentType(blobType))
+    if (!blobType.isEmpty() && ParsedContentType(blobType).isValid())
       m_contentType = AtomicString(blobType);
   }
 
diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
index 2e94301..4cb6f3c 100644
--- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
@@ -7,6 +7,7 @@
 #include "core/dom/Element.h"
 #include "core/dom/TreeScope.h"
 #include "core/layout/svg/LayoutSVGResourceContainer.h"
+#include "core/layout/svg/SVGResourcesCache.h"
 #include "wtf/text/AtomicString.h"
 
 namespace blink {
@@ -21,13 +22,35 @@
 
 SVGTreeScopeResources::~SVGTreeScopeResources() = default;
 
-void SVGTreeScopeResources::addResource(const AtomicString& id,
-                                        LayoutSVGResourceContainer* resource) {
+void SVGTreeScopeResources::updateResource(
+    const AtomicString& id,
+    LayoutSVGResourceContainer* resource) {
   DCHECK(resource);
   if (id.isEmpty())
     return;
-  // Replaces resource if already present, to handle potential id changes
+  // Replaces resource if already present, to handle potential id changes.
   m_resources.set(id, resource);
+
+  SVGPendingElements* pendingElements = m_pendingResources.take(id);
+  if (!pendingElements)
+    return;
+  // Update cached resources of pending clients.
+  for (Element* clientElement : *pendingElements) {
+    DCHECK(clientElement->hasPendingResources());
+    clearHasPendingResourcesIfPossible(clientElement);
+
+    LayoutObject* layoutObject = clientElement->layoutObject();
+    if (!layoutObject)
+      continue;
+    DCHECK(layoutObject->isSVG());
+
+    StyleDifference diff;
+    diff.setNeedsFullLayout();
+    SVGResourcesCache::clientStyleChanged(layoutObject, diff,
+                                          layoutObject->styleRef());
+    layoutObject->setNeedsLayoutAndFullPaintInvalidation(
+        LayoutInvalidationReason::SvgResourceInvalidated);
+  }
 }
 
 void SVGTreeScopeResources::removeResource(const AtomicString& id) {
diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
index a58a4382..9529a4ad 100644
--- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
+++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
@@ -30,7 +30,7 @@
   explicit SVGTreeScopeResources(TreeScope*);
   ~SVGTreeScopeResources();
 
-  void addResource(const AtomicString& id, LayoutSVGResourceContainer*);
+  void updateResource(const AtomicString& id, LayoutSVGResourceContainer*);
   void removeResource(const AtomicString& id);
   LayoutSVGResourceContainer* resourceById(const AtomicString& id) const;
 
diff --git a/third_party/WebKit/Source/core/svg/UnsafeSVGAttributeSanitizationTest.cpp b/third_party/WebKit/Source/core/svg/UnsafeSVGAttributeSanitizationTest.cpp
index a435425f..70ceccb 100644
--- a/third_party/WebKit/Source/core/svg/UnsafeSVGAttributeSanitizationTest.cpp
+++ b/third_party/WebKit/Source/core/svg/UnsafeSVGAttributeSanitizationTest.cpp
@@ -60,7 +60,10 @@
   frame.document()->updateStyleAndLayout();
   frame.selection().setSelection(
       SelectionInDOMTree::Builder().selectAllChildren(*body).build());
-  EXPECT_EQ(CaretSelection, frame.selection().getSelectionType());
+  EXPECT_EQ(CaretSelection,
+            frame.selection()
+                .computeVisibleSelectionInDOMTreeDeprecated()
+                .getSelectionType());
   EXPECT_TRUE(frame.selection()
                   .computeVisibleSelectionInDOMTreeDeprecated()
                   .isContentEditable())
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index d86b35b9..98d47e7 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -812,7 +812,7 @@
   if (areMethodAndURLValidForSend()) {
     if (getRequestHeader(HTTPNames::Content_Type).isEmpty()) {
       const String& blobType = body->type();
-      if (!blobType.isEmpty() && isValidContentType(blobType)) {
+      if (!blobType.isEmpty() && ParsedContentType(blobType).isValid()) {
         setRequestHeaderInternal(HTTPNames::Content_Type,
                                  AtomicString(blobType));
       }
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index f9e30f3..8f29630 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -427,6 +427,7 @@
   "front_end/sdk/Connections.js",
   "front_end/sdk/ConsoleModel.js",
   "front_end/sdk/ContentProviders.js",
+  "front_end/sdk/CookieModel.js",
   "front_end/sdk/CookieParser.js",
   "front_end/sdk/CPUProfileDataModel.js",
   "front_end/sdk/CPUProfilerModel.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
index e1e0a91..c1adf63 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
@@ -1315,13 +1315,13 @@
     }
 
     const nonDataUrls = requests.map(r => r.url()).filter(url => url && url.asParsedURL());
-    SDK.Cookies.getCookiesAsync(target, nonDataUrls, resultCallback);
+    SDK.CookieModel.fromTarget(target).getCookiesAsync(nonDataUrls, resultCallback);
   }
 
   mapResourceCookies(requestsByDomain, allCookies, callback) {
     for (var i = 0; i < allCookies.length; ++i) {
       for (var requestDomain in requestsByDomain) {
-        if (SDK.Cookies.cookieDomainMatchesResourceDomain(allCookies[i].domain(), requestDomain))
+        if (SDK.CookieModel.cookieDomainMatchesResourceDomain(allCookies[i].domain(), requestDomain))
           this._callbackForResourceCookiePairs(requestsByDomain[requestDomain], allCookies[i], callback);
       }
     }
@@ -1331,7 +1331,7 @@
     if (!requests)
       return;
     for (var i = 0; i < requests.length; ++i) {
-      if (SDK.Cookies.cookieMatchesResourceURL(cookie, requests[i].url()))
+      if (SDK.CookieModel.cookieMatchesResourceURL(cookie, requests[i].url()))
         callback(requests[i], cookie);
     }
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js b/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js
index a8b16f5..3ce51050 100644
--- a/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js
+++ b/third_party/WebKit/Source/devtools/front_end/cookie_table/CookiesTable.js
@@ -33,14 +33,16 @@
  */
 CookieTable.CookiesTable = class extends UI.VBox {
   /**
+   * @param {!SDK.Target} target
    * @param {boolean} readOnly
    * @param {function()=} refreshCallback
    * @param {function()=} selectedCallback
    * @param {string=} cookieDomain
    */
-  constructor(readOnly, refreshCallback, selectedCallback, cookieDomain) {
+  constructor(target, readOnly, refreshCallback, selectedCallback, cookieDomain) {
     super();
 
+    this._model = SDK.CookieModel.fromTarget(target);
     this._readOnly = readOnly;
     this._refreshCallback = refreshCallback;
     this._cookieDomain = cookieDomain;
@@ -65,16 +67,14 @@
         editable: !this._readOnly
       },
       {id: 'domain', title: Common.UIString('Domain'), sortable: true, weight: 7, editable: !this._readOnly},
-      {id: 'path', title: Common.UIString('Path'), sortable: true, weight: 7, editable: !this._readOnly},
-      {
+      {id: 'path', title: Common.UIString('Path'), sortable: true, weight: 7, editable: !this._readOnly}, {
         id: 'expires',
         title: Common.UIString('Expires / Max-Age'),
         sortable: true,
         weight: 7,
         editable: !this._readOnly
       },
-      {id: 'size', title: Common.UIString('Size'), sortable: true, align: DataGrid.DataGrid.Align.Right, weight: 7},
-      {
+      {id: 'size', title: Common.UIString('Size'), sortable: true, align: DataGrid.DataGrid.Align.Right, weight: 7}, {
         id: 'httpOnly',
         title: Common.UIString('HTTP'),
         sortable: true,
@@ -100,8 +100,8 @@
     if (this._readOnly) {
       this._dataGrid = new DataGrid.DataGrid(columns);
     } else {
-      this._dataGrid = new DataGrid.DataGrid(columns, this._onUpdateCookie.bind(this), this._onDeleteCookie.bind(this), refreshCallback);
-      this._dataGrid.setRowContextMenuCallback(this._onRowContextMenu.bind(this));
+      this._dataGrid = new DataGrid.DataGrid(
+          columns, this._onUpdateCookie.bind(this), this._onDeleteCookie.bind(this), refreshCallback);
     }
 
     this._dataGrid.setName('cookiesTable');
@@ -119,31 +119,6 @@
   }
 
   /**
-   * @param {?string} domain
-   */
-  _clearAndRefresh(domain) {
-    this.clear(domain);
-    this._refresh();
-  }
-
-  /**
-   * @param {!UI.ContextMenu} contextMenu
-   * @param {!DataGrid.DataGridNode} node
-   */
-  _onRowContextMenu(contextMenu, node) {
-    if (node.isCreationNode)
-      return;
-
-    const cookie = node.cookie;
-    const domain = cookie.domain();
-    if (domain) {
-      contextMenu.appendItem(
-          Common.UIString.capitalize('Clear ^all from "%s"', domain), this._clearAndRefresh.bind(this, domain));
-    }
-    contextMenu.appendItem(Common.UIString.capitalize('Clear ^all'), this._clearAndRefresh.bind(this, null));
-  }
-
-  /**
    * @param {!Array.<!SDK.Cookie>} cookies
    */
   setCookies(cookies) {
@@ -167,19 +142,6 @@
   }
 
   /**
-   * @param {?string=} domain
-   */
-  clear(domain) {
-    for (var i = 0, length = this._data.length; i < length; ++i) {
-      var cookies = this._data[i].cookies;
-      for (var j = 0, cookieCount = cookies.length; j < cookieCount; ++j) {
-        if (!domain || cookies[j].domain() === domain)
-          cookies[j].remove();
-      }
-    }
-  }
-
-  /**
    * @override
    */
   willHide() {
@@ -412,7 +374,7 @@
     if (oldCookie && (newCookie.name() !== oldCookie.name() || newCookie.url() !== oldCookie.url()))
       oldCookie.remove();
     node.cookie = newCookie;
-    newCookie.save(success => {
+    this._model.saveCookie(newCookie, success => {
       if (success)
         this._refresh();
       else
@@ -423,11 +385,10 @@
 
   /**
    * @param {!Object.<string, *>} data
-   * @returns {SDK.Cookie}
+   * @returns {!SDK.Cookie}
    */
   _createCookieFromData(data) {
-    var target = SDK.targetManager.targets(SDK.Target.Capability.Network)[0];
-    var cookie = new SDK.Cookie(target, data.name, data.value, null);
+    var cookie = new SDK.Cookie(data.name, data.value, null);
     cookie.addAttribute('domain', data.domain);
     cookie.addAttribute('path', data.path);
     if (data.expires && data.expires !== CookieTable.CookiesTable._expiresSessionValue)
@@ -447,7 +408,8 @@
    * @returns {boolean}
    */
   _isValidCookieData(data) {
-    return (data.name || data.value) && this._isValidDomain(data.domain) && this._isValidPath(data.path) && this._isValidDate(data.expires);
+    return (data.name || data.value) && this._isValidDomain(data.domain) && this._isValidPath(data.path) &&
+        this._isValidDate(data.expires);
   }
 
   /**
@@ -485,4 +447,4 @@
 };
 
 /** @const */
-CookieTable.CookiesTable._expiresSessionValue = Common.UIString('Session');
\ No newline at end of file
+CookieTable.CookiesTable._expiresSessionValue = Common.UIString('Session');
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestCookiesView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestCookiesView.js
index 02ab5df..2fd09ce 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestCookiesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestCookiesView.js
@@ -78,7 +78,7 @@
   _buildCookiesTable() {
     this.detachChildWidgets();
 
-    this._cookiesTable = new CookieTable.CookiesTable(true);
+    this._cookiesTable = new CookieTable.CookiesTable(this._request.target(), true);
     this._cookiesTable.setCookieFolders([
       {folderName: Common.UIString('Request Cookies'), cookies: this._request.requestCookies},
       {folderName: Common.UIString('Response Cookies'), cookies: this._request.responseCookies}
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js b/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js
index 3e25d9e..a4ba75b 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js
@@ -111,7 +111,7 @@
     var set = new Set(storageTypes);
     var hasAll = set.has(Protocol.Storage.StorageType.All);
     if (set.has(Protocol.Storage.StorageType.Cookies) || hasAll)
-      this._resourcesPanel.clearCookies(this._securityOrigin);
+      SDK.CookieModel.fromTarget(this._target).clear();
 
     if (set.has(Protocol.Storage.StorageType.Indexeddb) || hasAll) {
       for (var target of SDK.targetManager.targets()) {
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
index cfc8083..cc3891c 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
@@ -38,12 +38,10 @@
 
     this.element.classList.add('storage-view');
 
-    this._target = target;
+    this._model = SDK.CookieModel.fromTarget(target);
     this._treeElement = treeElement;
     this._cookieDomain = cookieDomain;
 
-    /** @type {?Array<!SDK.Cookie>} */
-    this._cookies = null;
     this._totalSize = 0;
     /** @type {?CookieTable.CookiesTable} */
     this._cookiesTable = null;
@@ -53,21 +51,20 @@
    * @param {!Array.<!SDK.Cookie>} allCookies
    */
   _updateWithCookies(allCookies) {
-    this._cookies = allCookies;
     this._totalSize = allCookies.reduce((size, cookie) => size + cookie.size(), 0);
 
     if (!this._cookiesTable) {
       const parsedURL = this._cookieDomain.asParsedURL();
       const domain = parsedURL ? parsedURL.host : '';
       this._cookiesTable = new CookieTable.CookiesTable(
-          false, this.refreshItems.bind(this), () => this.setCanDeleteSelected(true), domain);
+          this._model.target(), false, this.refreshItems.bind(this), () => this.setCanDeleteSelected(true), domain);
     }
 
     var shownCookies = this.filter(allCookies, cookie => `${cookie.name()} ${cookie.value()} ${cookie.domain()}`);
     this._cookiesTable.setCookies(shownCookies);
     this._cookiesTable.show(this.element);
     this._treeElement.subtitle =
-        String.sprintf(Common.UIString('%d cookies (%s)'), this._cookies.length, Number.bytesToString(this._totalSize));
+        String.sprintf(Common.UIString('%d cookies (%s)'), allCookies.length, Number.bytesToString(this._totalSize));
     this.setCanFilter(true);
     this.setCanDeleteAll(true);
     this.setCanDeleteSelected(!!this._cookiesTable.selectedCookie());
@@ -77,8 +74,7 @@
    * @override
    */
   deleteAllItems() {
-    this._cookiesTable.clear();
-    this.refreshItems();
+    this._model.clear(this._cookieDomain, () => this.refreshItems());
   }
 
   /**
@@ -86,28 +82,14 @@
    */
   deleteSelectedItem() {
     var selectedCookie = this._cookiesTable.selectedCookie();
-    if (selectedCookie) {
-      selectedCookie.remove();
-      this.refreshItems();
-    }
+    if (selectedCookie)
+      this._model.deleteCookie(selectedCookie, () => this.refreshItems());
   }
 
   /**
    * @override
    */
   refreshItems() {
-    var resourceURLs = [];
-    var cookieDomain = this._cookieDomain;
-    /**
-     * @param {!SDK.Resource} resource
-     */
-    function populateResourceURLs(resource) {
-      var url = resource.documentURL.asParsedURL();
-      if (url && url.securityOrigin() === cookieDomain)
-        resourceURLs.push(resource.url);
-    }
-
-    SDK.ResourceTreeModel.fromTarget(this._target).forAllResources(populateResourceURLs);
-    SDK.Cookies.getCookiesAsync(this._target, resourceURLs, this._updateWithCookies.bind(this));
+    this._model.getCookiesForDomain(this._cookieDomain, cookies => this._updateWithCookies(cookies));
   }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
index 948c20f..9f22cbb 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
@@ -612,7 +612,7 @@
   /**
    * @param {string} cookieDomain
    */
-  clearCookies(cookieDomain) {
+  _clearCookies(cookieDomain) {
     if (this._cookieViews[cookieDomain])
       this._cookieViews[cookieDomain].deleteAllItems();
   }
@@ -1978,18 +1978,11 @@
    */
   _handleContextMenuEvent(event) {
     var contextMenu = new UI.ContextMenu(event);
-    contextMenu.appendItem(Common.UIString('Clear'), this._clearCookies.bind(this));
+    contextMenu.appendItem(Common.UIString('Clear'), () => this._storagePanel._clearCookies(this._cookieDomain));
     contextMenu.show();
   }
 
   /**
-   * @param {string} domain
-   */
-  _clearCookies(domain) {
-    this._storagePanel.clearCookies(this._cookieDomain);
-  }
-
-  /**
    * @override
    * @return {boolean}
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js
new file mode 100644
index 0000000..e2c8c76
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CookieModel.js
@@ -0,0 +1,146 @@
+// 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.
+
+SDK.CookieModel = class extends SDK.SDKModel {
+  /**
+   * @param {!SDK.Target} target
+   */
+  constructor(target) {
+    super(target);
+  }
+
+  /**
+   * @param {!Protocol.Network.Cookie} protocolCookie
+   * @return {!SDK.Cookie}
+   */
+  static _parseProtocolCookie(protocolCookie) {
+    var cookie = new SDK.Cookie(protocolCookie.name, protocolCookie.value, null);
+    cookie.addAttribute('domain', protocolCookie['domain']);
+    cookie.addAttribute('path', protocolCookie['path']);
+    cookie.addAttribute('port', protocolCookie['port']);
+    if (protocolCookie['expires'])
+      cookie.addAttribute('expires', protocolCookie['expires']);
+    if (protocolCookie['httpOnly'])
+      cookie.addAttribute('httpOnly');
+    if (protocolCookie['secure'])
+      cookie.addAttribute('secure');
+    if (protocolCookie['sameSite'])
+      cookie.addAttribute('sameSite', protocolCookie['sameSite']);
+    cookie.setSize(protocolCookie['size']);
+    return cookie;
+  }
+
+  /**
+   * @param {!SDK.Target} target
+   * @return {!SDK.CookieModel}
+   */
+  static fromTarget(target) {
+    return /** @type {!SDK.CookieModel} */ (target.model(SDK.CookieModel));
+  }
+
+  /**
+   * @param {!SDK.Cookie} cookie
+   * @param {string} resourceURL
+   * @return {boolean}
+   */
+  static cookieMatchesResourceURL(cookie, resourceURL) {
+    var url = resourceURL.asParsedURL();
+    if (!url || !SDK.CookieModel.cookieDomainMatchesResourceDomain(cookie.domain(), url.host))
+      return false;
+    return (
+        url.path.startsWith(cookie.path()) && (!cookie.port() || url.port === cookie.port()) &&
+        (!cookie.secure() || url.scheme === 'https'));
+  }
+
+  /**
+   * @param {string} cookieDomain
+   * @param {string} resourceDomain
+   * @return {boolean}
+   */
+  static cookieDomainMatchesResourceDomain(cookieDomain, resourceDomain) {
+    if (cookieDomain.charAt(0) !== '.')
+      return resourceDomain === cookieDomain;
+    return !!resourceDomain.match(
+        new RegExp('^([^\\.]+\\.)*' + cookieDomain.substring(1).escapeForRegExp() + '$', 'i'));
+  }
+
+  /**
+   * @param {!Array<string>} urls
+   * @param {function(!Array<!SDK.Cookie>)} callback
+   */
+  getCookiesAsync(urls, callback) {
+    this.target().networkAgent().getCookies(urls, (err, cookies) => {
+      if (err) {
+        console.error(err);
+        return callback([]);
+      }
+
+      callback(cookies.map(cookie => SDK.CookieModel._parseProtocolCookie(cookie)));
+    });
+  }
+
+  /**
+   * @param {!SDK.Cookie} cookie
+   * @param {function()=} callback
+   */
+  deleteCookie(cookie, callback) {
+    this._deleteAll([cookie], callback);
+  }
+
+  /**
+   * @param {string=} domain
+   * @param {function()=} callback
+   */
+  clear(domain, callback) {
+    this.getCookiesForDomain(domain || null, cookies => this._deleteAll(cookies, callback));
+  }
+
+  /**
+   * @param {!SDK.Cookie} cookie
+   * @param {function(?Protocol.Error, ?)=} callback
+   */
+  saveCookie(cookie, callback) {
+    var domain = cookie.domain();
+    if (!domain.startsWith('.'))
+      domain = '';
+    var expires = undefined;
+    if (cookie.expires())
+      expires = Math.floor(Date.parse(cookie.expires()) / 1000);
+    this.target().networkAgent().setCookie(
+        cookie.url(), cookie.name(), cookie.value(), domain, cookie.path(), cookie.secure(), cookie.httpOnly(),
+        cookie.sameSite(), expires, callback);
+  }
+
+  /**
+   * @param {?string} domain
+   * @param {function(!Array<!SDK.Cookie>)} callback
+   */
+  getCookiesForDomain(domain, callback) {
+    var resourceURLs = [];
+    /**
+     * @param {!SDK.Resource} resource
+     */
+    function populateResourceURLs(resource) {
+      var url = resource.documentURL.asParsedURL();
+      if (url && (!domain || url.securityOrigin() === domain))
+        resourceURLs.push(resource.url);
+    }
+    SDK.ResourceTreeModel.fromTarget(this.target()).forAllResources(populateResourceURLs);
+    this.getCookiesAsync(resourceURLs, callback);
+  }
+
+  /**
+   * @param {!Array<!SDK.Cookie>} cookies
+   * @param {function()=} callback
+   */
+  _deleteAll(cookies, callback) {
+    var networkAgent = this.target().networkAgent();
+    function deleteCookie(cookie) {
+      return new Promise(resolve => networkAgent.deleteCookie(cookie.name(), cookie.url(), resolve));
+    }
+    Promise.all(cookies.map(deleteCookie)).then(callback || function() {});
+  }
+};
+
+SDK.SDKModel.register(SDK.CookieModel, SDK.Target.Capability.Network);
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js b/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js
index e9b03b9f..e1da2a5 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js
@@ -38,33 +38,27 @@
  * @unrestricted
  */
 SDK.CookieParser = class {
-  /**
-   * @param {!SDK.Target} target
-   */
-  constructor(target) {
-    this._target = target;
+  constructor() {
   }
 
   /**
-   * @param {!SDK.Target} target
    * @param {string|undefined} header
-   * @return {?Array.<!SDK.Cookie>}
+   * @return {?Array<!SDK.Cookie>}
    */
-  static parseCookie(target, header) {
-    return (new SDK.CookieParser(target)).parseCookie(header);
+  static parseCookie(header) {
+    return (new SDK.CookieParser()).parseCookie(header);
   }
 
   /**
-   * @param {!SDK.Target} target
    * @param {string|undefined} header
-   * @return {?Array.<!SDK.Cookie>}
+   * @return {?Array<!SDK.Cookie>}
    */
-  static parseSetCookie(target, header) {
-    return (new SDK.CookieParser(target)).parseSetCookie(header);
+  static parseSetCookie(header) {
+    return (new SDK.CookieParser()).parseSetCookie(header);
   }
 
   /**
-   * @return {!Array.<!SDK.Cookie>}
+   * @return {!Array<!SDK.Cookie>}
    */
   cookies() {
     return this._cookies;
@@ -72,7 +66,7 @@
 
   /**
    * @param {string|undefined} cookieHeader
-   * @return {?Array.<!SDK.Cookie>}
+   * @return {?Array<!SDK.Cookie>}
    */
   parseCookie(cookieHeader) {
     if (!this._initialize(cookieHeader))
@@ -91,7 +85,7 @@
 
   /**
    * @param {string|undefined} setCookieHeader
-   * @return {?Array.<!SDK.Cookie>}
+   * @return {?Array<!SDK.Cookie>}
    */
   parseSetCookie(setCookieHeader) {
     if (!this._initialize(setCookieHeader))
@@ -169,11 +163,11 @@
   _addCookie(keyValue, type) {
     if (this._lastCookie)
       this._lastCookie.setSize(keyValue.position - this._lastCookiePosition);
+
     // Mozilla bug 169091: Mozilla, IE and Chrome treat single token (w/o "=") as
     // specifying a value for a cookie with empty name.
-    this._lastCookie = typeof keyValue.value === 'string' ?
-        new SDK.Cookie(this._target, keyValue.key, keyValue.value, type) :
-        new SDK.Cookie(this._target, '', keyValue.key, type);
+    this._lastCookie = typeof keyValue.value === 'string' ? new SDK.Cookie(keyValue.key, keyValue.value, type) :
+                                                            new SDK.Cookie('', keyValue.key, type);
     this._lastCookiePosition = keyValue.position;
     this._cookies.push(this._lastCookie);
   }
@@ -201,17 +195,16 @@
  */
 SDK.Cookie = class {
   /**
-   * @param {!SDK.Target} target
    * @param {string} name
    * @param {string} value
    * @param {?SDK.Cookie.Type} type
    */
-  constructor(target, name, value, type) {
-    this._target = target;
+  constructor(name, value, type) {
     this._name = name;
     this._value = value;
     this._type = type;
     this._attributes = {};
+    this._size = 0;
   }
 
   /**
@@ -352,35 +345,6 @@
   addAttribute(key, value) {
     this._attributes[key.toLowerCase()] = value;
   }
-
-  /**
-   * @param {function(?Protocol.Error)=} callback
-   */
-  remove(callback) {
-    this._target.networkAgent().deleteCookie(this.name(), this.url(), callback);
-  }
-
-  /**
-   * @param {function(boolean)=} callback
-   */
-  save(callback) {
-    var domain = this.domain();
-    if (!domain.startsWith('.'))
-      domain = '';
-    var expires = undefined;
-    if (this.expires())
-      expires = Math.floor(Date.parse(this.expires()) / 1000);
-    this._target.networkAgent().setCookie(this.url(), this.name(), this.value(), domain, this.path(), this.secure(),
-      this.httpOnly(), this.sameSite(), expires, mycallback);
-
-    /**
-     * @param {?Protocol.Error} error
-     * @param {boolean} success
-     */
-    function mycallback(error, success) {
-      callback(error ? false : success);
-    }
-  }
 };
 
 /**
@@ -390,68 +354,3 @@
   Request: 0,
   Response: 1
 };
-
-SDK.Cookies = {};
-
-/**
- * @param {!SDK.Target} target
- * @param {!Array.<string>} urls
- * @param {function(!Array.<!SDK.Cookie>)} callback
- */
-SDK.Cookies.getCookiesAsync = function(target, urls, callback) {
-  target.networkAgent().getCookies(urls, (err, cookies) => {
-    if (err) {
-      console.error(err);
-      return callback([]);
-    }
-
-    callback(cookies.map(cookie => SDK.Cookies._parseProtocolCookie(target, cookie)));
-  });
-};
-
-/**
- * @param {!SDK.Target} target
- * @param {!Protocol.Network.Cookie} protocolCookie
- * @return {!SDK.Cookie}
- */
-SDK.Cookies._parseProtocolCookie = function(target, protocolCookie) {
-  var cookie = new SDK.Cookie(target, protocolCookie.name, protocolCookie.value, null);
-  cookie.addAttribute('domain', protocolCookie['domain']);
-  cookie.addAttribute('path', protocolCookie['path']);
-  cookie.addAttribute('port', protocolCookie['port']);
-  if (protocolCookie['expires'])
-    cookie.addAttribute('expires', protocolCookie['expires']);
-  if (protocolCookie['httpOnly'])
-    cookie.addAttribute('httpOnly');
-  if (protocolCookie['secure'])
-    cookie.addAttribute('secure');
-  if (protocolCookie['sameSite'])
-    cookie.addAttribute('sameSite', protocolCookie['sameSite']);
-  cookie.setSize(protocolCookie['size']);
-  return cookie;
-};
-
-/**
- * @param {!SDK.Cookie} cookie
- * @param {string} resourceURL
- * @return {boolean}
- */
-SDK.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL) {
-  var url = resourceURL.asParsedURL();
-  if (!url || !SDK.Cookies.cookieDomainMatchesResourceDomain(cookie.domain(), url.host))
-    return false;
-  return (
-      url.path.startsWith(cookie.path()) && (!cookie.port() || url.port === cookie.port()) &&
-      (!cookie.secure() || url.scheme === 'https'));
-};
-
-/**
- * @param {string} cookieDomain
- * @param {string} resourceDomain
- * @return {boolean}
- */
-SDK.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain) {
-  if (cookieDomain.charAt(0) !== '.')
-    return resourceDomain === cookieDomain;
-  return !!resourceDomain.match(new RegExp('^([^\\.]+\\.)*' + cookieDomain.substring(1).escapeForRegExp() + '$', 'i'));
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
index ddb315ee..fc601e42 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
@@ -650,7 +650,7 @@
    */
   get requestCookies() {
     if (!this._requestCookies)
-      this._requestCookies = SDK.CookieParser.parseCookie(this.target(), this.requestHeaderValue('Cookie'));
+      this._requestCookies = SDK.CookieParser.parseCookie(this.requestHeaderValue('Cookie'));
     return this._requestCookies;
   }
 
@@ -749,7 +749,7 @@
    */
   get responseCookies() {
     if (!this._responseCookies)
-      this._responseCookies = SDK.CookieParser.parseSetCookie(this.target(), this.responseHeaderValue('Set-Cookie'));
+      this._responseCookies = SDK.CookieParser.parseSetCookie(this.responseHeaderValue('Set-Cookie'));
     return this._responseCookies;
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/module.json b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
index b0c25e61..a86a1ef 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
@@ -103,6 +103,7 @@
         "Connections.js",
         "ConsoleModel.js",
         "ContentProviders.js",
+        "CookieModel.js",
         "CookieParser.js",
         "ProfileTreeModel.js",
         "ServerTiming.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
index 5589753e..92761c6 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
@@ -23,9 +23,10 @@
     // Otherwise, inspector page reacts on drop event and tries to load the event data.
     // this._createCategory(Common.UIString("Drag"), ["drag", "drop", "dragstart", "dragend", "dragenter", "dragleave", "dragover"]);
     this._createCategory(
-        Common.UIString('Animation'), ['requestAnimationFrame', 'cancelAnimationFrame', 'animationFrameFired'], true);
-    this._createCategory(Common.UIString('Canvas'), ['canvasContextCreated', 'webglErrorFired', 'webglWarningFired'],
-        true);
+        Common.UIString('Animation'),
+        ['DOMWindow.requestAnimationFrame', 'DOMWindow.cancelAnimationFrame', 'animationFrameFired'], true);
+    this._createCategory(
+        Common.UIString('Canvas'), ['canvasContextCreated', 'webglErrorFired', 'webglWarningFired'], true);
     this._createCategory(
         Common.UIString('Clipboard'), ['copy', 'cut', 'paste', 'beforecopy', 'beforecut', 'beforepaste']);
     this._createCategory(
@@ -37,7 +38,8 @@
       'DOMNodeInsertedIntoDocument', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument', 'DOMSubtreeModified',
       'DOMContentLoaded'
     ]);
-    this._createCategory(Common.UIString('Geolocation'), ['navigator.geolocation.getCurrentPosition', 'navigator.geolocation.watchPosition'], true);
+    this._createCategory(
+        Common.UIString('Geolocation'), ['Geolocation.getCurrentPosition', 'Geolocation.watchPosition'], true);
     this._createCategory(Common.UIString('Drag / drop'), ['dragenter', 'dragover', 'dragleave', 'drop']);
     this._createCategory(Common.UIString('Keyboard'), ['keydown', 'keyup', 'keypress', 'input']);
     this._createCategory(
@@ -56,7 +58,7 @@
       'mouseleave', 'mousewheel', 'wheel', 'contextmenu'
     ]);
     this._createCategory(Common.UIString('Notification'), ['Notification.requestPermission'], true);
-    this._createCategory(Common.UIString('Parse'), ['setInnerHTML', 'document.write'], true);
+    this._createCategory(Common.UIString('Parse'), ['setInnerHTML', 'Document.write'], true);
     this._createCategory(Common.UIString('Pointer'), [
       'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'pointerdown', 'pointerup', 'pointermove',
       'pointercancel', 'gotpointercapture', 'lostpointercapture'
@@ -64,7 +66,7 @@
     this._createCategory(Common.UIString('Script'), ['scriptFirstStatement', 'scriptBlockedByCSP'], true);
     this._createCategory(Common.UIString('Timer'), ['setTimer', 'clearTimer', 'timerFired'], true);
     this._createCategory(Common.UIString('Touch'), ['touchstart', 'touchmove', 'touchend', 'touchcancel']);
-    this._createCategory(Common.UIString('Window'), ['close'], true);
+    this._createCategory(Common.UIString('Window'), ['DOMWindow.close'], true);
     this._createCategory(
         Common.UIString('XHR'),
         ['readystatechange', 'load', 'loadstart', 'loadend', 'abort', 'error', 'progress', 'timeout'], false,
@@ -89,16 +91,18 @@
         'instrumentation:timerFired': Common.UIString('Timer Fired'),
         'instrumentation:scriptFirstStatement': Common.UIString('Script First Statement'),
         'instrumentation:scriptBlockedByCSP': Common.UIString('Script Blocked by Content Security Policy'),
-        'instrumentation:requestAnimationFrame': Common.UIString('Request Animation Frame'),
-        'instrumentation:cancelAnimationFrame': Common.UIString('Cancel Animation Frame'),
-        'instrumentation:animationFrameFired': Common.UIString('Animation Frame Fired'),
+        'instrumentation:DOMWindow.requestAnimationFrame': Common.UIString('Request Animation Frame'),
+        'instrumentation:DOMWindow.cancelAnimationFrame': Common.UIString('Cancel Animation Frame'),
+        'instrumentation:DOMWindow.requestAnimationFrame.callback': Common.UIString('Animation Frame Fired'),
         'instrumentation:webglErrorFired': Common.UIString('WebGL Error Fired'),
         'instrumentation:webglWarningFired': Common.UIString('WebGL Warning Fired'),
-        'instrumentation:setInnerHTML': Common.UIString('Set innerHTML'),
+        'instrumentation:Element.setInnerHTML': Common.UIString('Set innerHTML'),
         'instrumentation:canvasContextCreated': Common.UIString('Create canvas context'),
-        'instrumentation:navigator.geolocation.getCurrentPosition': 'getCurrentPosition',
-        'instrumentation:navigator.geolocation.watchPosition': 'watchPosition',
+        'instrumentation:Geolocation.getCurrentPosition': 'getCurrentPosition',
+        'instrumentation:Geolocation.watchPosition': 'watchPosition',
         'instrumentation:Notification.requestPermission': 'requestPermission',
+        'instrumentation:DOMWindow.close': 'window.close',
+        'instrumentation:Document.write': 'document.write',
       };
     }
     if (auxData) {
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp b/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
index 9d0f6def..6c327a3 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
+++ b/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
@@ -51,7 +51,7 @@
   for (size_t i = 0; i < capabilities.size(); ++i) {
     const WebString& contentType = capabilities[i].contentType();
     result[i].contentType = contentType;
-    if (isValidContentType(contentType)) {
+    if (ParsedContentType(contentType).isValid()) {
       // FIXME: Fail if there are unrecognized parameters.
       // http://crbug.com/690131
       ContentType type(capabilities[i].contentType());
diff --git a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
index ba10471d..e03655f 100644
--- a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
@@ -181,7 +181,7 @@
 
   reportGeolocationViolation(document());
   InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-      document(), "navigator.geolocation.getCurrentPosition", true);
+      document(), "Geolocation.getCurrentPosition", true);
 
   GeoNotifier* notifier =
       GeoNotifier::create(this, successCallback, errorCallback, options);
@@ -198,7 +198,7 @@
 
   reportGeolocationViolation(document());
   InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-      document(), "navigator.geolocation.watchPosition", true);
+      document(), "Geolocation.watchPosition", true);
 
   GeoNotifier* notifier =
       GeoNotifier::create(this, successCallback, errorCallback, options);
diff --git a/third_party/WebKit/Source/modules/installedapp/OWNERS b/third_party/WebKit/Source/modules/installedapp/OWNERS
index e041c27e..065b132 100644
--- a/third_party/WebKit/Source/modules/installedapp/OWNERS
+++ b/third_party/WebKit/Source/modules/installedapp/OWNERS
@@ -1 +1,3 @@
-dhnishi@chromium.org
+mgiuca@chromium.org
+
+# COMPONENT: Platform>Apps>AppLauncher>Install
diff --git a/third_party/WebKit/Source/modules/webusb/USB.idl b/third_party/WebKit/Source/modules/webusb/USB.idl
index f4b5c35..6f26238 100644
--- a/third_party/WebKit/Source/modules/webusb/USB.idl
+++ b/third_party/WebKit/Source/modules/webusb/USB.idl
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://wicg.github.io/webusb/#enumeration
+// https://wicg.github.io/webusb/#usb
 
 [
-    NoInterfaceObject,
     OriginTrialEnabled=WebUSB,
 ] interface USB : EventTarget {
     attribute EventHandler onconnect;
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
index a5f5623..81e0072 100644
--- a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
@@ -91,10 +91,6 @@
 }
 
 AudioDestination::~AudioDestination() {
-#if OS(ANDROID)
-  // Log when AudioDestination is destructed. (crbug.com/692423)
-  LOG(WARNING) << "[WebAudio/AudioDestination] going away...";
-#endif
   stop();
 }
 
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp
index 1c137020..ad3e90a 100644
--- a/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp
+++ b/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp
@@ -29,12 +29,7 @@
   m_fifoBus = AudioBus::create(numberOfChannels, m_fifoLength);
 }
 
-PushPullFIFO::~PushPullFIFO() {
-#if OS(ANDROID)
-  // Log when PushPullFIFO is destructed. (crbug.com/692423)
-  LOG(WARNING) << "[WebAudio/PushPullFIFO] going away...";
-#endif
-}
+PushPullFIFO::~PushPullFIFO() {}
 
 // Push the data from |inputBus| to FIFO. The size of push is determined by
 // the length of |inputBus|.
@@ -91,10 +86,11 @@
 #if OS(ANDROID)
   if (!outputBus) {
     // Log when outputBus is invalid. (crbug.com/692423)
-    LOG(WARNING) << "[WebAudio/PushPullFIFO::pull] outputBus = " << outputBus;
+    LOG(WARNING) << "[WebAudio/PushPullFIFO::pull] |outputBus| is invalid.";
+    // Silently return to avoid crash.
+    return;
   }
 #endif
-
   CHECK(outputBus);
   SECURITY_CHECK(framesRequested <= outputBus->length());
   SECURITY_CHECK(framesRequested <= m_fifoLength);
diff --git a/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp
index a1352386..85b97a2 100644
--- a/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp
@@ -91,6 +91,9 @@
 
 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame(
     const ColorBehavior& colorBehavior) {
+  // TODO(xlai): Refactor so that sync tokens are only used when
+  // |m_textureHolder| is MailboxTextureHolder.
+  // https://crbug.com/693229
   // TODO(ccameron): This function should not ignore |colorBehavior|.
   // https://crbug.com/672306
   checkThread();
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index cbd9476bf..de1aed2 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -141,8 +141,6 @@
       m_filterQuality(kLow_SkFilterQuality),
       m_isHidden(false),
       m_isDeferralEnabled(true),
-      m_isRegisteredTaskObserver(false),
-      m_renderingTaskCompletedForCurrentFrame(false),
       m_softwareRenderingWhileHidden(false),
       m_lastImageId(0),
       m_lastFilter(GL_LINEAR),
@@ -497,7 +495,7 @@
     return;
   }
 
-  TRACE_EVENT0("cc", "Canvas2DLayerBridge::hibernate");
+  TRACE_EVENT0("blink", "Canvas2DLayerBridge::hibernate");
   sk_sp<PaintSurface> tempHibernationSurface =
       PaintSurface::MakeRasterN32Premul(m_size.width(), m_size.height());
   if (!tempHibernationSurface) {
@@ -669,8 +667,6 @@
   setIsHidden(true);
   m_surface.reset();
 
-  unregisterTaskObserver();
-
   if (m_layer && m_accelerationMode != DisableAcceleration) {
     GraphicsLayer::unregisterContentsLayer(m_layer->layer());
     m_layer->clearTexture();
@@ -683,13 +679,6 @@
   DCHECK(!m_bytesAllocated);
 }
 
-void Canvas2DLayerBridge::unregisterTaskObserver() {
-  if (m_isRegisteredTaskObserver) {
-    Platform::current()->currentThread()->removeTaskObserver(this);
-    m_isRegisteredTaskObserver = false;
-  }
-}
-
 void Canvas2DLayerBridge::setFilterQuality(SkFilterQuality filterQuality) {
   DCHECK(!m_destructionInProgress);
   m_filterQuality = filterQuality;
@@ -772,7 +761,6 @@
   }
 
   if (m_isDeferralEnabled) {
-    unregisterTaskObserver();
     if (m_rateLimiter)
       m_rateLimiter->reset();
   }
@@ -900,6 +888,11 @@
     return false;
   }
 
+  m_framesSinceLastCommit = 0;
+  if (m_rateLimiter) {
+    m_rateLimiter->reset();
+  }
+
   // If the context is lost, we don't know if we should be producing GPU or
   // software frames, until we get a new context, since the compositor will
   // be trying to get a new context and may change modes.
@@ -1035,40 +1028,21 @@
       disableDeferral(DisableDeferralReasonExpensiveOverdrawHeuristic);
     }
   }
-  if (!m_isRegisteredTaskObserver) {
-    Platform::current()->currentThread()->addTaskObserver(this);
-    m_isRegisteredTaskObserver = true;
-  }
   m_didDrawSinceLastFlush = true;
   m_didDrawSinceLastGpuFlush = true;
 }
 
 void Canvas2DLayerBridge::finalizeFrame() {
+  TRACE_EVENT0("blink", "Canvas2DLayerBridge::finalizeFrame");
   DCHECK(!m_destructionInProgress);
 
   // Make sure surface is ready for painting: fix the rendering mode now
   // because it will be too late during the paint invalidation phase.
   getOrCreateSurface(PreferAcceleration);
 
-  if (m_rateLimiter)
-    m_rateLimiter->reset();
-  m_renderingTaskCompletedForCurrentFrame = false;
-}
+  ++m_framesSinceLastCommit;
 
-void Canvas2DLayerBridge::doPaintInvalidation(const FloatRect& dirtyRect) {
-  DCHECK(!m_destructionInProgress);
-  if (m_layer && m_accelerationMode != DisableAcceleration)
-    m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect));
-}
-
-void Canvas2DLayerBridge::didProcessTask() {
-  TRACE_EVENT0("cc", "Canvas2DLayerBridge::didProcessTask");
-  DCHECK(m_isRegisteredTaskObserver);
-  // If m_renderTaskProcessedForCurrentFrame is already set to true,
-  // it means that rendering tasks are not synchronized with the compositor
-  // (i.e. not using requestAnimationFrame), so we are at risk of posting
-  // a multi-frame backlog to the GPU
-  if (m_renderingTaskCompletedForCurrentFrame) {
+  if (m_framesSinceLastCommit >= 2) {
     if (isAccelerated()) {
       flushGpu();
       if (!m_rateLimiter) {
@@ -1083,13 +1057,12 @@
   if (m_rateLimiter) {
     m_rateLimiter->tick();
   }
-
-  m_renderingTaskCompletedForCurrentFrame = true;
-  unregisterTaskObserver();
 }
 
-void Canvas2DLayerBridge::willProcessTask() {
-  NOTREACHED();
+void Canvas2DLayerBridge::doPaintInvalidation(const FloatRect& dirtyRect) {
+  DCHECK(!m_destructionInProgress);
+  if (m_layer && m_accelerationMode != DisableAcceleration)
+    m_layer->layer()->invalidateRect(enclosingIntRect(dirtyRect));
 }
 
 sk_sp<SkImage> Canvas2DLayerBridge::newImageSnapshot(AccelerationHint hint,
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index d1a7f13..20b09b9 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -34,7 +34,6 @@
 #include "platform/graphics/paint/PaintRecorder.h"
 #include "platform/graphics/paint/PaintSurface.h"
 #include "public/platform/WebExternalTextureLayer.h"
-#include "public/platform/WebThread.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "ui/gfx/color_space.h"
@@ -80,7 +79,6 @@
 
 class PLATFORM_EXPORT Canvas2DLayerBridge
     : public NON_EXPORTED_BASE(cc::TextureLayerClient),
-      public WebThread::TaskObserver,
       public RefCounted<Canvas2DLayerBridge> {
   WTF_MAKE_NONCOPYABLE(Canvas2DLayerBridge);
 
@@ -205,13 +203,8 @@
   void startRecording();
   void skipQueuedDrawCommands();
   void flushRecordingOnly();
-  void unregisterTaskObserver();
   void reportSurfaceCreationFailure();
 
-  // WebThread::TaskOberver implementation
-  void willProcessTask() override;
-  void didProcessTask() override;
-
   PaintSurface* getOrCreateSurface(AccelerationHint = PreferAcceleration);
   bool shouldAccelerate(AccelerationHint) const;
 
@@ -259,14 +252,13 @@
   WeakPtrFactory<Canvas2DLayerBridge> m_weakPtrFactory;
   ImageBuffer* m_imageBuffer;
   int m_msaaSampleCount;
+  int m_framesSinceLastCommit = 0;
   size_t m_bytesAllocated;
   bool m_haveRecordedDrawCommands;
   bool m_destructionInProgress;
   SkFilterQuality m_filterQuality;
   bool m_isHidden;
   bool m_isDeferralEnabled;
-  bool m_isRegisteredTaskObserver;
-  bool m_renderingTaskCompletedForCurrentFrame;
   bool m_softwareRenderingWhileHidden;
   bool m_surfaceCreationFailedAtLeastOnce = false;
   bool m_hibernationScheduled = false;
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasPlaceholder.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasPlaceholder.h
index d5a302e..b5dccac 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasPlaceholder.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasPlaceholder.h
@@ -20,10 +20,10 @@
  public:
   ~OffscreenCanvasPlaceholder();
 
-  void setPlaceholderFrame(RefPtr<StaticBitmapImage>,
-                           WeakPtr<OffscreenCanvasFrameDispatcher>,
-                           RefPtr<WebTaskRunner>,
-                           unsigned resourceId);
+  virtual void setPlaceholderFrame(RefPtr<StaticBitmapImage>,
+                                   WeakPtr<OffscreenCanvasFrameDispatcher>,
+                                   RefPtr<WebTaskRunner>,
+                                   unsigned resourceId);
   void releasePlaceholderFrame();
 
   static OffscreenCanvasPlaceholder* getPlaceholderById(unsigned placeholderId);
diff --git a/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.h b/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.h
index 6bfdaef..b4da4fe2 100644
--- a/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.h
+++ b/third_party/WebKit/Source/platform/graphics/SkiaTextureHolder.h
@@ -14,6 +14,9 @@
  public:
   ~SkiaTextureHolder() override;
 
+  // Methods overriding TextureHolder
+  void updateSyncToken(gpu::SyncToken) override {}
+
   bool isSkiaTextureHolder() final { return true; }
   bool isMailboxTextureHolder() final { return false; }
   unsigned sharedContextId() final;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.cpp
index 009cce51..1748aa25 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemClient.cpp
@@ -23,7 +23,7 @@
 
 DisplayItemClient::DisplayItemClient() {
   if (displayItemClientsShouldKeepAlive) {
-    for (auto item : *displayItemClientsShouldKeepAlive)
+    for (const auto& item : *displayItemClientsShouldKeepAlive)
       CHECK(!item.value.contains(this));
   }
   if (!liveDisplayItemClients)
@@ -33,7 +33,7 @@
 
 DisplayItemClient::~DisplayItemClient() {
   if (displayItemClientsShouldKeepAlive) {
-    for (auto& item : *displayItemClientsShouldKeepAlive) {
+    for (const auto& item : *displayItemClientsShouldKeepAlive) {
       CHECK(!item.value.contains(this))
           << "Short-lived DisplayItemClient: " << item.value.get(this)
           << ". See crbug.com/609218.";
diff --git a/third_party/WebKit/Source/platform/heap/PagePool.cpp b/third_party/WebKit/Source/platform/heap/PagePool.cpp
index 22973227..5c75ddd42 100644
--- a/third_party/WebKit/Source/platform/heap/PagePool.cpp
+++ b/third_party/WebKit/Source/platform/heap/PagePool.cpp
@@ -33,13 +33,11 @@
   // while in the pool.  This also allows the physical memory, backing the
   // page, to be given back to the OS.
   memory->decommit();
-  MutexLocker locker(m_mutex[index]);
   PoolEntry* entry = new PoolEntry(memory, m_pool[index]);
   m_pool[index] = entry;
 }
 
 PageMemory* PagePool::take(int index) {
-  MutexLocker locker(m_mutex[index]);
   while (PoolEntry* entry = m_pool[index]) {
     m_pool[index] = entry->next;
     PageMemory* memory = entry->data;
diff --git a/third_party/WebKit/Source/platform/heap/PagePool.h b/third_party/WebKit/Source/platform/heap/PagePool.h
index 7936d63..7a3748f 100644
--- a/third_party/WebKit/Source/platform/heap/PagePool.h
+++ b/third_party/WebKit/Source/platform/heap/PagePool.h
@@ -7,7 +7,6 @@
 
 #include "platform/heap/ThreadState.h"
 #include "wtf/Allocator.h"
-#include "wtf/ThreadingPrimitives.h"
 
 namespace blink {
 
@@ -42,7 +41,6 @@
   };
 
   PoolEntry* m_pool[BlinkGC::NumberOfArenas];
-  Mutex m_mutex[BlinkGC::NumberOfArenas];
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp b/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp
index 87449dc1..63fe7b0 100644
--- a/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp
+++ b/third_party/WebKit/Source/platform/mhtml/MHTMLParser.cpp
@@ -134,7 +134,8 @@
   KeyValueMap::iterator mimeParametersIterator =
       keyValuePairs.find("content-type");
   if (mimeParametersIterator != keyValuePairs.end()) {
-    ParsedContentType parsedContentType(mimeParametersIterator->value);
+    ParsedContentType parsedContentType(mimeParametersIterator->value,
+                                        ParsedContentType::Mode::Relaxed);
     mimeHeader->m_contentType = parsedContentType.mimeType();
     if (!mimeHeader->isMultipart()) {
       mimeHeader->m_charset = parsedContentType.charset().stripWhiteSpace();
diff --git a/third_party/WebKit/Source/platform/network/ParsedContentType.cpp b/third_party/WebKit/Source/platform/network/ParsedContentType.cpp
index 55423702..e7e6880 100644
--- a/third_party/WebKit/Source/platform/network/ParsedContentType.cpp
+++ b/third_party/WebKit/Source/platform/network/ParsedContentType.cpp
@@ -31,55 +31,144 @@
 
 #include "platform/network/ParsedContentType.h"
 
-#include "wtf/text/CString.h"
 #include "wtf/text/StringBuilder.h"
+#include "wtf/text/StringView.h"
 
 namespace blink {
 
-class DummyParsedContentType final {
-  STACK_ALLOCATED();
+using Mode = ParsedContentType::Mode;
 
- public:
-  void setContentType(const SubstringRange&) const {}
-  void setContentTypeParameter(const SubstringRange&,
-                               const SubstringRange&) const {}
-};
+namespace {
 
-static void skipSpaces(const String& input, unsigned& startIndex) {
-  while (startIndex < input.length() && input[startIndex] == ' ')
-    ++startIndex;
-}
+bool isTokenCharacter(Mode mode, UChar c) {
+  if (c >= 128)
+    return false;
+  if (c < 0x20)
+    return false;
 
-static SubstringRange parseParameterPart(const String& input,
-                                         unsigned& startIndex) {
-  unsigned inputLength = input.length();
-  unsigned tokenStart = startIndex;
-  unsigned& tokenEnd = startIndex;
-
-  if (tokenEnd >= inputLength)
-    return SubstringRange();
-
-  bool quoted = input[tokenStart] == '\"';
-  bool escape = false;
-
-  while (tokenEnd < inputLength) {
-    UChar c = input[tokenEnd];
-    if (quoted && tokenStart != tokenEnd && c == '\"' && !escape)
-      return SubstringRange(tokenStart + 1, tokenEnd++ - tokenStart - 1);
-    if (!quoted && (c == ';' || c == '='))
-      return SubstringRange(tokenStart, tokenEnd - tokenStart);
-    escape = !escape && c == '\\';
-    ++tokenEnd;
+  switch (c) {
+    case ' ':
+    case ';':
+    case '"':
+      return false;
+    case '(':
+    case ')':
+    case '<':
+    case '>':
+    case '@':
+    case ',':
+    case ':':
+    case '\\':
+    case '/':
+    case '[':
+    case ']':
+    case '?':
+    case '=':
+      return mode == Mode::Relaxed;
+    default:
+      return true;
   }
-
-  if (quoted)
-    return SubstringRange();
-  return SubstringRange(tokenStart, tokenEnd - tokenStart);
 }
 
-static String substringForRange(const String& string,
-                                const SubstringRange& range) {
-  return string.substring(range.first, range.second);
+bool consume(char c, const String& input, unsigned& index) {
+  DCHECK_NE(c, ' ');
+  while (index < input.length() && input[index] == ' ')
+    ++index;
+
+  if (index < input.length() && input[index] == c) {
+    ++index;
+    return true;
+  }
+  return false;
+}
+
+bool consumeToken(Mode mode,
+                  const String& input,
+                  unsigned& index,
+                  StringView& output) {
+  DCHECK(output.isNull());
+
+  while (index < input.length() && input[index] == ' ')
+    ++index;
+
+  auto start = index;
+  while (index < input.length() && isTokenCharacter(mode, input[index]))
+    ++index;
+
+  if (start == index)
+    return false;
+
+  output = StringView(input, start, index - start);
+  return true;
+}
+
+bool consumeQuotedString(const String& input, unsigned& index, String& output) {
+  StringBuilder builder;
+  DCHECK_EQ('"', input[index]);
+  ++index;
+  while (index < input.length()) {
+    if (input[index] == '\\') {
+      ++index;
+      if (index == input.length())
+        return false;
+      builder.append(input[index]);
+      ++index;
+      continue;
+    }
+    if (input[index] == '"') {
+      output = builder.toString();
+      ++index;
+      return true;
+    }
+    builder.append(input[index]);
+    ++index;
+  }
+  return false;
+}
+
+bool consumeTokenOrQuotedString(Mode mode,
+                                const String& input,
+                                unsigned& index,
+                                String& output) {
+  while (index < input.length() && input[index] == ' ')
+    ++index;
+  if (input.length() == index)
+    return false;
+  if (input[index] == '"') {
+    return consumeQuotedString(input, index, output);
+  }
+  StringView view;
+  auto result = consumeToken(mode, input, index, view);
+  output = view.toString();
+  return result;
+}
+
+bool isEnd(const String& input, unsigned index) {
+  while (index < input.length()) {
+    if (input[index] != ' ')
+      return false;
+    ++index;
+  }
+  return true;
+}
+
+}  // namespace
+
+ParsedContentType::ParsedContentType(const String& contentType, Mode mode)
+    : m_mode(mode) {
+  m_isValid = parse(contentType);
+}
+
+String ParsedContentType::charset() const {
+  return parameterValueForName("charset");
+}
+
+String ParsedContentType::parameterValueForName(const String& name) const {
+  return m_parameters.get(name);
+}
+
+size_t ParsedContentType::parameterCount() const {
+  return m_parameters.size();
 }
 
 // From http://tools.ietf.org/html/rfc2045#section-5.1:
@@ -128,102 +217,55 @@
 //               ; Must be in quoted-string,
 //               ; to use within parameter values
 
-template <class ReceiverType>
-bool parseContentType(const String& contentType, ReceiverType& receiver) {
+bool ParsedContentType::parse(const String& contentType) {
   unsigned index = 0;
-  unsigned contentTypeLength = contentType.length();
-  skipSpaces(contentType, index);
-  if (index >= contentTypeLength) {
-    DVLOG(1) << "Invalid Content-Type string '" << contentType << "'";
+
+  StringView type, subtype;
+  if (!consumeToken(Mode::Normal, contentType, index, type)) {
+    DVLOG(1) << "Failed to find `type' in '" << contentType << "'";
+    return false;
+  }
+  if (!consume('/', contentType, index)) {
+    DVLOG(1) << "Failed to find '/' in '" << contentType << "'";
+    return false;
+  }
+  if (!consumeToken(Mode::Normal, contentType, index, subtype)) {
+    DVLOG(1) << "Failed to find `type' in '" << contentType << "'";
     return false;
   }
 
-  // There should not be any quoted strings until we reach the parameters.
-  size_t semiColonIndex = contentType.find(';', index);
-  if (semiColonIndex == kNotFound) {
-    receiver.setContentType(SubstringRange(index, contentTypeLength - index));
-    return true;
-  }
+  StringBuilder builder;
+  builder.append(type);
+  builder.append('/');
+  builder.append(subtype);
+  m_mimeType = builder.toString();
 
-  receiver.setContentType(SubstringRange(index, semiColonIndex - index));
-  index = semiColonIndex + 1;
-  while (true) {
-    skipSpaces(contentType, index);
-    SubstringRange keyRange = parseParameterPart(contentType, index);
-    if (!keyRange.second || index >= contentTypeLength) {
+  KeyValuePairs map;
+  while (!isEnd(contentType, index)) {
+    if (!consume(';', contentType, index)) {
+      DVLOG(1) << "Failed to find ';'";
+      return false;
+    }
+
+    StringView key;
+    String value;
+    if (!consumeToken(Mode::Normal, contentType, index, key)) {
       DVLOG(1) << "Invalid Content-Type parameter name. (at " << index << ")";
       return false;
     }
-
-    // Should we tolerate spaces here?
-    if (contentType[index++] != '=' || index >= contentTypeLength) {
-      DVLOG(1) << "Invalid Content-Type malformed parameter (at " << index
-               << ").";
+    if (!consume('=', contentType, index)) {
+      DVLOG(1) << "Failed to find '='";
       return false;
     }
-
-    // Should we tolerate spaces here?
-    SubstringRange valueRange = parseParameterPart(contentType, index);
-
-    if (!valueRange.second) {
+    if (!consumeTokenOrQuotedString(m_mode, contentType, index, value)) {
       DVLOG(1) << "Invalid Content-Type, invalid parameter value (at " << index
-               << ", for '"
-               << substringForRange(contentType, keyRange).stripWhiteSpace()
-               << "').";
+               << ", for '" << key.toString() << "').";
       return false;
     }
-
-    // Should we tolerate spaces here?
-    if (index < contentTypeLength && contentType[index++] != ';') {
-      DVLOG(1) << "Invalid Content-Type, invalid character at the end of "
-                  "key/value parameter (at "
-               << index << ").";
-      return false;
-    }
-
-    receiver.setContentTypeParameter(keyRange, valueRange);
-
-    if (index >= contentTypeLength)
-      return true;
+    map.set(key.toString(), value);
   }
-
+  m_parameters = std::move(map);
   return true;
 }
 
-bool isValidContentType(const String& contentType) {
-  if (contentType.contains('\r') || contentType.contains('\n'))
-    return false;
-
-  DummyParsedContentType parsedContentType = DummyParsedContentType();
-  return parseContentType<DummyParsedContentType>(contentType,
-                                                  parsedContentType);
-}
-
-ParsedContentType::ParsedContentType(const String& contentType)
-    : m_contentType(contentType.stripWhiteSpace()) {
-  parseContentType<ParsedContentType>(m_contentType, *this);
-}
-
-String ParsedContentType::charset() const {
-  return parameterValueForName("charset");
-}
-
-String ParsedContentType::parameterValueForName(const String& name) const {
-  return m_parameters.get(name);
-}
-
-size_t ParsedContentType::parameterCount() const {
-  return m_parameters.size();
-}
-
-void ParsedContentType::setContentType(const SubstringRange& contentRange) {
-  m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace();
-}
-
-void ParsedContentType::setContentTypeParameter(const SubstringRange& key,
-                                                const SubstringRange& value) {
-  m_parameters.set(substringForRange(m_contentType, key),
-                   substringForRange(m_contentType, value));
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/network/ParsedContentType.h b/third_party/WebKit/Source/platform/network/ParsedContentType.h
index d59f6047e..a6f9008 100644
--- a/third_party/WebKit/Source/platform/network/ParsedContentType.h
+++ b/third_party/WebKit/Source/platform/network/ParsedContentType.h
@@ -39,16 +39,21 @@
 
 namespace blink {
 
-// <index, length>
-typedef std::pair<unsigned, unsigned> SubstringRange;
-PLATFORM_EXPORT bool isValidContentType(const String&);
-
+// ParsedContentType parses the constructor argument as specified in RFC2045
+// and stores the result.
 // FIXME: add support for comments.
 class PLATFORM_EXPORT ParsedContentType final {
   STACK_ALLOCATED();
 
  public:
-  explicit ParsedContentType(const String&);
+  // When |Relaxed| is specified, the parser parses parameter values in a sloppy
+  // manner, i.e., only ';' and '"' are treated as special characters.
+  // See https://chromiumcodereview.appspot.com/23043002.
+  enum class Mode {
+    Normal,
+    Relaxed,
+  };
+  explicit ParsedContentType(const String&, Mode = Mode::Normal);
 
   String mimeType() const { return m_mimeType; }
   String charset() const;
@@ -58,14 +63,15 @@
   String parameterValueForName(const String&) const;
   size_t parameterCount() const;
 
+  bool isValid() const { return m_isValid; }
+
  private:
-  template <class ReceiverType>
-  friend bool parseContentType(const String&, ReceiverType&);
-  void setContentType(const SubstringRange&);
-  void setContentTypeParameter(const SubstringRange&, const SubstringRange&);
+  bool parse(const String&);
+
+  const Mode m_mode;
+  bool m_isValid;
 
   typedef HashMap<String, String> KeyValuePairs;
-  String m_contentType;
   KeyValuePairs m_parameters;
   String m_mimeType;
 };
diff --git a/third_party/WebKit/Source/platform/network/ParsedContentTypeTest.cpp b/third_party/WebKit/Source/platform/network/ParsedContentTypeTest.cpp
index 64ed0d1..e6ffdba47 100644
--- a/third_party/WebKit/Source/platform/network/ParsedContentTypeTest.cpp
+++ b/third_party/WebKit/Source/platform/network/ParsedContentTypeTest.cpp
@@ -8,33 +8,42 @@
 
 namespace blink {
 
+namespace {
+
+using Mode = ParsedContentType::Mode;
+
+bool isValid(const String& input, Mode mode = Mode::Normal) {
+  return ParsedContentType(input, mode).isValid();
+}
+
 TEST(ParsedContentTypeTest, MimeTypeWithoutCharset) {
   ParsedContentType t("text/plain");
 
+  EXPECT_TRUE(t.isValid());
   EXPECT_EQ("text/plain", t.mimeType());
   EXPECT_EQ(String(), t.charset());
 }
 
 TEST(ParsedContentTypeTest, MimeTypeWithCharSet) {
-  ParsedContentType t(" text/plain  ;  x=y;charset=utf-8 ");
+  ParsedContentType t("text /  plain  ;  x=y; charset = utf-8 ");
 
+  EXPECT_TRUE(t.isValid());
   EXPECT_EQ("text/plain", t.mimeType());
   EXPECT_EQ("utf-8", t.charset());
 }
 
 TEST(ParsedContentTypeTest, MimeTypeWithQuotedCharSet) {
-  ParsedContentType t("text/plain; \"charset\"=\"x=y;y=z; ;;\"");
+  ParsedContentType t("text/plain; charset=\"x=y;y=\\\"\\pz; ;;\"");
 
+  EXPECT_TRUE(t.isValid());
   EXPECT_EQ("text/plain", t.mimeType());
-  EXPECT_EQ("x=y;y=z; ;;", t.charset());
+  EXPECT_EQ("x=y;y=\"pz; ;;", t.charset());
 }
 
-// TODO(yhirano): Add tests for escaped quotation: it's currently
-// mis-implemented.
-
 TEST(ParsedContentTypeTest, InvalidMimeTypeWithoutCharset) {
   ParsedContentType t(" ");
 
+  EXPECT_FALSE(t.isValid());
   EXPECT_EQ(String(), t.mimeType());
   EXPECT_EQ(String(), t.charset());
 }
@@ -42,52 +51,78 @@
 TEST(ParsedContentTypeTest, InvalidMimeTypeWithCharset) {
   ParsedContentType t("text/plain; charset;");
 
+  EXPECT_FALSE(t.isValid());
   EXPECT_EQ("text/plain", t.mimeType());
   EXPECT_EQ(String(), t.charset());
 }
 
 TEST(ParsedContentTypeTest, Validity) {
-  EXPECT_TRUE(isValidContentType("text/plain"));
-  EXPECT_TRUE(isValidContentType("text/plain; charset=utf-8"));
-  EXPECT_TRUE(isValidContentType("  text/plain  "));
-  EXPECT_TRUE(isValidContentType(" text/plain;charset=utf-8  "));
-  EXPECT_TRUE(isValidContentType("unknown/unknown"));
-  EXPECT_TRUE(isValidContentType("unknown/unknown; charset=unknown"));
-  EXPECT_TRUE(isValidContentType("x/y;\"z=\\\"q;t\"=\"ttx&r=z;;kd==\""));
+  EXPECT_TRUE(isValid("text/plain"));
+  EXPECT_TRUE(isValid("text/plain; charset=utf-8"));
+  EXPECT_TRUE(isValid("  text/plain  "));
+  EXPECT_TRUE(isValid(" text/plain;charset=utf-8  "));
+  EXPECT_TRUE(isValid("unknown/unknown"));
+  EXPECT_TRUE(isValid("unknown/unknown; charset=unknown"));
+  EXPECT_TRUE(isValid("x/y;z=\"ttx&r=z;;\\u\\\"kd==\""));
+  EXPECT_TRUE(isValid("x/y; z=\"\xff\""));
 
-  EXPECT_FALSE(isValidContentType("text/plain\r"));
-  EXPECT_FALSE(isValidContentType("text/plain\n"));
-  EXPECT_FALSE(isValidContentType(""));
-  EXPECT_FALSE(isValidContentType("   "));
-  EXPECT_FALSE(isValidContentType("text/plain;"));
-  EXPECT_FALSE(isValidContentType("text/plain;  "));
-  EXPECT_FALSE(isValidContentType("text/plain; charset"));
-  EXPECT_FALSE(isValidContentType("text/plain; charset;"));
-  EXPECT_FALSE(isValidContentType("x/y;\"xx"));
-  EXPECT_FALSE(isValidContentType("x/y;\"xx=y"));
+  EXPECT_FALSE(isValid("A"));
+  EXPECT_FALSE(isValid("text/plain\r"));
+  EXPECT_FALSE(isValid("text/plain\n"));
+  EXPECT_FALSE(isValid("text/plain charset=utf-8"));
+  EXPECT_FALSE(isValid("text/plain;charset=utf-8;"));
+  EXPECT_FALSE(isValid(""));
+  EXPECT_FALSE(isValid("   "));
+  EXPECT_FALSE(isValid("\"x\""));
+  EXPECT_FALSE(isValid("\"x\"/\"y\""));
+  EXPECT_FALSE(isValid("x/\"y\""));
+  EXPECT_FALSE(isValid("text/plain;"));
+  EXPECT_FALSE(isValid("text/plain;  "));
+  EXPECT_FALSE(isValid("text/plain; charset"));
+  EXPECT_FALSE(isValid("text/plain; charset;"));
+  EXPECT_FALSE(isValid("x/y;\"xx"));
+  EXPECT_FALSE(isValid("x/y;\"xx=y"));
+  EXPECT_FALSE(isValid("\"q\""));
+  EXPECT_FALSE(isValid("x/y; \"z\"=u"));
+  EXPECT_FALSE(isValid("x/y; z=\xff"));
 
-  // TODO(yhirano): Add tests for non-tokens. They are currently accepted.
+  EXPECT_FALSE(isValid("x/y;z=q/t:()<>@,:\\/[]?"));
+  EXPECT_TRUE(isValid("x/y;z=q/t:()<>@,:\\/[]?=", Mode::Relaxed));
+  EXPECT_FALSE(isValid("x/y;z=q r", Mode::Relaxed));
+  EXPECT_FALSE(isValid("x/y;z=q;r", Mode::Relaxed));
+  EXPECT_FALSE(isValid("x/y;z=q\"r", Mode::Relaxed));
+  EXPECT_FALSE(isValid("x/y; z=\xff", Mode::Relaxed));
 }
 
 TEST(ParsedContentTypeTest, ParameterName) {
-  String input = "x; y=z; y=u;  t=r;s=x;\"Q\"=U;\"T\"=S;\"z u\"=\"q a\"";
+  String input = "x/t; y=z  ; y= u ;  t=r;s= \"t \\u\\\"x\" ;Q=U;T=S";
 
   ParsedContentType t(input);
 
-  EXPECT_EQ(6u, t.parameterCount());
+  EXPECT_TRUE(t.isValid());
+  EXPECT_EQ(5u, t.parameterCount());
   EXPECT_EQ(String(), t.parameterValueForName("a"));
   EXPECT_EQ(String(), t.parameterValueForName("x"));
   EXPECT_EQ("u", t.parameterValueForName("y"));
   EXPECT_EQ("r", t.parameterValueForName("t"));
-  EXPECT_EQ("x", t.parameterValueForName("s"));
+  EXPECT_EQ("t u\"x", t.parameterValueForName("s"));
   EXPECT_EQ("U", t.parameterValueForName("Q"));
   EXPECT_EQ("S", t.parameterValueForName("T"));
-  EXPECT_EQ("q a", t.parameterValueForName("z u"));
 
   // TODO(yhirano): Case-sensitivity is mis-implemented.
-  // TODO(yhirano): Add tests for escaped quotations.
-  // TODO(yhirano): Leading spaces of a parameter value should be ignored.
-  // TODO(yhirano): Trailing spaces of a parameter value should be ignored.
 }
 
+TEST(ParsedContentTypeTest, RelaxedParameterName) {
+  String input = "x/t; z=q/t:()<>@,:\\/[]?=;y=u";
+
+  ParsedContentType t(input, Mode::Relaxed);
+
+  EXPECT_TRUE(t.isValid());
+  EXPECT_EQ(2u, t.parameterCount());
+  EXPECT_EQ("q/t:()<>@,:\\/[]?=", t.parameterValueForName("z"));
+  EXPECT_EQ("u", t.parameterValueForName("y"));
+}
+
+}  // namespace
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index 7dac807..a9505511 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -900,7 +900,8 @@
           frameElement->scrollingMode(), frameElement->marginWidth(),
           frameElement->marginHeight(), frameElement->allowFullscreen(),
           frameElement->allowPaymentRequest(), frameElement->csp(),
-          frameElement->delegatedPermissions()));
+          frameElement->delegatedPermissions(),
+          frameElement->allowedFeatures()));
 }
 
 void FrameLoaderClientImpl::dispatchWillStartUsingPeerConnectionHandler(
diff --git a/third_party/WebKit/Source/web/OpenedFrameTracker.cpp b/third_party/WebKit/Source/web/OpenedFrameTracker.cpp
index cc96b64..30c44ba1 100644
--- a/third_party/WebKit/Source/web/OpenedFrameTracker.cpp
+++ b/third_party/WebKit/Source/web/OpenedFrameTracker.cpp
@@ -11,7 +11,9 @@
 
 OpenedFrameTracker::OpenedFrameTracker() {}
 
-OpenedFrameTracker::~OpenedFrameTracker() {}
+OpenedFrameTracker::~OpenedFrameTracker() {
+  DCHECK(isEmpty());
+}
 
 bool OpenedFrameTracker::isEmpty() const {
   return m_openedFrames.isEmpty();
@@ -33,9 +35,4 @@
     frame->setOpener(opener);
 }
 
-void OpenedFrameTracker::traceFrames(Visitor* visitor) {
-  for (WebFrame* frame : m_openedFrames)
-    WebFrame::traceFrame(visitor, frame);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/OpenedFrameTracker.h b/third_party/WebKit/Source/web/OpenedFrameTracker.h
index c6be8f3..aadfda2 100644
--- a/third_party/WebKit/Source/web/OpenedFrameTracker.h
+++ b/third_party/WebKit/Source/web/OpenedFrameTracker.h
@@ -10,7 +10,6 @@
 
 namespace blink {
 
-class Visitor;
 class WebFrame;
 
 // Small helper class to track the set of frames that a WebFrame has opened.
@@ -31,7 +30,8 @@
   // opener for opened frames to point to the new frame being swapped in.
   void transferTo(WebFrame*);
 
-  void traceFrames(Visitor*);
+  // Helper function to clear the openers when the frame is being detached.
+  void dispose() { transferTo(nullptr); }
 
  private:
   WTF::HashSet<WebFrame*> m_openedFrames;
diff --git a/third_party/WebKit/Source/web/RemoteFrameOwner.h b/third_party/WebKit/Source/web/RemoteFrameOwner.h
index 4b553fd..428f5b8 100644
--- a/third_party/WebKit/Source/web/RemoteFrameOwner.h
+++ b/third_party/WebKit/Source/web/RemoteFrameOwner.h
@@ -52,6 +52,9 @@
       const override {
     return m_delegatedPermissions;
   }
+  const WebVector<WebFeaturePolicyFeature>& allowedFeatures() const override {
+    return m_allowedFeatures;
+  }
 
   void setBrowsingContextContainerName(const WebString& name) {
     m_browsingContextContainerName = name;
@@ -70,6 +73,10 @@
       const WebVector<mojom::blink::PermissionName>& delegatedPermissions) {
     m_delegatedPermissions = delegatedPermissions;
   }
+  void setAllowedFeatures(
+      const WebVector<WebFeaturePolicyFeature>& allowedFeatures) {
+    m_allowedFeatures = allowedFeatures;
+  }
 
   DECLARE_VIRTUAL_TRACE();
 
@@ -91,6 +98,7 @@
   bool m_allowPaymentRequest;
   WebString m_csp;
   WebVector<mojom::blink::PermissionName> m_delegatedPermissions;
+  WebVector<WebFeaturePolicyFeature> m_allowedFeatures;
 };
 
 DEFINE_TYPE_CASTS(RemoteFrameOwner,
diff --git a/third_party/WebKit/Source/web/WebFrame.cpp b/third_party/WebKit/Source/web/WebFrame.cpp
index d59c817..943f738 100644
--- a/third_party/WebKit/Source/web/WebFrame.cpp
+++ b/third_party/WebKit/Source/web/WebFrame.cpp
@@ -160,6 +160,7 @@
   owner->setAllowPaymentRequest(properties.allowPaymentRequest);
   owner->setCsp(properties.requiredCsp);
   owner->setDelegatedpermissions(properties.delegatedPermissions);
+  owner->setAllowedFeatures(properties.allowedFeatures);
 }
 
 WebFrame* WebFrame::opener() const {
@@ -291,16 +292,6 @@
   m_openedFrameTracker.reset(0);
 }
 
-ALWAYS_INLINE bool WebFrame::isFrameAlive(const WebFrame* frame) {
-  if (!frame)
-    return true;
-
-  if (frame->isWebLocalFrame())
-    return ThreadHeap::isHeapObjectAlive(toWebLocalFrameImpl(frame));
-
-  return ThreadHeap::isHeapObjectAlive(toWebRemoteFrameImpl(frame));
-}
-
 void WebFrame::traceFrame(Visitor* visitor, WebFrame* frame) {
   if (!frame)
     return;
@@ -317,13 +308,10 @@
   for (WebFrame* child = frame->firstChild(); child;
        child = child->nextSibling())
     traceFrame(visitor, child);
-  // m_opener is a weak reference.
-  frame->m_openedFrameTracker->traceFrames(visitor);
 }
 
-void WebFrame::clearWeakFrames(Visitor* visitor) {
-  if (!isFrameAlive(m_opener))
-    m_opener = nullptr;
+void WebFrame::close() {
+  m_openedFrameTracker->dispose();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 8da8f4e..b11fc7b0 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -532,6 +532,8 @@
 }
 
 void WebLocalFrameImpl::close() {
+  WebLocalFrame::close();
+
   m_client = nullptr;
 
   if (m_devToolsAgent)
@@ -1560,8 +1562,6 @@
   visitor->trace(m_textFinder);
   visitor->trace(m_printContext);
   visitor->trace(m_contextMenuNode);
-  visitor->template registerWeakMembers<WebFrame, &WebFrame::clearWeakFrames>(
-      this);
   WebFrame::traceFrames(visitor, this);
   WebFrameImplBase::trace(visitor);
 }
@@ -1613,7 +1613,7 @@
       ownerElement->scrollingMode(), ownerElement->marginWidth(),
       ownerElement->marginHeight(), ownerElement->allowFullscreen(),
       ownerElement->allowPaymentRequest(), ownerElement->csp(),
-      ownerElement->delegatedPermissions());
+      ownerElement->delegatedPermissions(), ownerElement->allowedFeatures());
   // FIXME: Using subResourceAttributeName as fallback is not a perfect
   // solution. subResourceAttributeName returns just one attribute name. The
   // element might not have the attribute, and there might be other attributes
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index cd1f73f..e43dcc01 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -47,8 +47,6 @@
 DEFINE_TRACE(WebRemoteFrameImpl) {
   visitor->trace(m_frameClient);
   visitor->trace(m_frame);
-  visitor->template registerWeakMembers<WebFrame, &WebFrame::clearWeakFrames>(
-      this);
   WebFrame::traceFrames(visitor, this);
   WebFrameImplBase::trace(visitor);
 }
@@ -71,6 +69,8 @@
 }
 
 void WebRemoteFrameImpl::close() {
+  WebRemoteFrame::close();
+
   m_selfKeepAlive.clear();
 }
 
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 5cf3d88..7c1a88f1 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -11401,4 +11401,15 @@
   webViewHelper.reset();
 }
 
+TEST_F(WebFrameTest, ClearClosedOpener) {
+  FrameTestHelpers::TestWebViewClient openerWebViewClient;
+  FrameTestHelpers::WebViewHelper openerHelper;
+  openerHelper.initialize(false, nullptr, &openerWebViewClient);
+  FrameTestHelpers::WebViewHelper helper;
+  helper.initializeWithOpener(openerHelper.webView()->mainFrame());
+
+  openerHelper.reset();
+  EXPECT_EQ(nullptr, helper.webView()->mainFrameImpl()->opener());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h
index dc707ef..2d9b5f8 100644
--- a/third_party/WebKit/Source/wtf/HashTable.h
+++ b/third_party/WebKit/Source/wtf/HashTable.h
@@ -1827,12 +1827,13 @@
       m_stats(HashTableStatsPtr<Allocator>::copy(other.m_stats))
 #endif
 {
+  if (other.size())
+    reserveCapacityForSize(other.size());
   // Copy the hash table the dumb way, by adding each element to the new
   // table.  It might be more efficient to copy the table slots, but it's not
   // clear that efficiency is needed.
-  const_iterator end = other.end();
-  for (const_iterator it = other.begin(); it != end; ++it)
-    add(*it);
+  for (const auto& element : other)
+    add(element);
 }
 
 template <typename Key,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
index f91fc421..f50d7d8 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
@@ -237,13 +237,13 @@
 
         return self._remote_merge_base()
 
-    def changed_files(self, git_commit=None):
+    def changed_files(self, git_commit=None, diff_filter='ADM'):
         # FIXME: --diff-filter could be used to avoid the "extract_filenames" step.
         status_command = ['diff', '-r', '--name-status',
                           "--no-renames", "--no-ext-diff", "--full-index", self._merge_base(git_commit)]
         # FIXME: I'm not sure we're returning the same set of files that SVN.changed_files is.
         # Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
-        return self._run_status_and_extract_filenames(status_command, self._status_regexp("ADM"))
+        return self._run_status_and_extract_filenames(status_command, self._status_regexp(diff_filter))
 
     def added_files(self):
         return self._run_status_and_extract_filenames(self.status_command(), self._status_regexp("A"))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
index 2f887ce..4d6e4fee 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
@@ -107,7 +107,7 @@
         if self._filesystem:
             self._filesystem.move(self.absolute_path(origin), self.absolute_path(destination))
 
-    def changed_files(self):
+    def changed_files(self, diff_filter='ADM'):
         return []
 
     def unstaged_changes(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py
index 2c41cd2..165961c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py
@@ -111,7 +111,7 @@
 
 class BotTestExpectationsFactory(object):
     RESULTS_URL_PREFIX = (
-        'http://test-results.appspot.com/testfile?master=chromium.webkit&'
+        'https://test-results.appspot.com/testfile?master=chromium.webkit&'
         'testtype=webkit_tests&name=results-small.json&builder=')
 
     def __init__(self, builders):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/flaky_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/flaky_tests.py
index 29ad7004..c932241 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/flaky_tests.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/flaky_tests.py
@@ -53,7 +53,7 @@
         '%20If%20not%20fixed%20in%203%20months,%20it%20will%20be%20deleted%20'
         'or%20perma-skipped.%0A%0AIn%20the%20flakiness%20dashboard,%20the%20'
         'turquoise%20boxes%20are%20runs%20where%20the%20test%20failed%20and%20'
-        'then%20passed%20on%20retry.%0A%0Ahttp://test-results.appspot.com'
+        'then%20passed%20on%20retry.%0A%0Ahttps://test-results.appspot.com'
         '/dashboards/flakiness_dashboard.html%23tests=XXXXXXX')
 
     HEADER = (
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
index e536cea..0e184dc 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
@@ -2,19 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""A command to fetch new baselines from try jobs for a Rietveld issue.
-
-This command interacts with the Rietveld API to get information about try jobs
-with layout test results.
-"""
+"""A command to fetch new baselines from try jobs for the current CL."""
 
 import json
 import logging
 import optparse
 
 from webkitpy.common.net.git_cl import GitCL
-from webkitpy.common.net.rietveld import Rietveld
-from webkitpy.common.net.web import Web
 from webkitpy.layout_tests.models.test_expectations import BASELINE_SUFFIX_LIST
 from webkitpy.tool.commands.rebaseline import AbstractParallelRebaselineCommand
 
@@ -34,9 +28,6 @@
     def __init__(self):
         super(RebaselineCL, self).__init__(options=[
             optparse.make_option(
-                '--issue', type='int', default=None,
-                help='Rietveld issue number; if none given, this will be obtained via `git cl issue`.'),
-            optparse.make_option(
                 '--dry-run', action='store_true', default=False,
                 help='Dry run mode; list actions that would be performed but do not do anything.'),
             optparse.make_option(
@@ -48,7 +39,6 @@
             self.no_optimize_option,
             self.results_directory_option,
         ])
-        self.rietveld = Rietveld(Web())
 
     def execute(self, options, args, tool):
         self._tool = tool
@@ -60,15 +50,11 @@
                 _log.error('  %s', path)
             return 1
 
-        issue_number = self._get_issue_number(options)
+        issue_number = self._get_issue_number()
         if not issue_number:
             return 1
 
-        # TODO(qyearsley): Remove dependency on Rietveld. See crbug.com/671684.
-        if options.issue:
-            builds = self.rietveld.latest_try_jobs(issue_number, self._try_bots())
-        else:
-            builds = self.git_cl().latest_try_jobs(self._try_bots())
+        builds = self.git_cl().latest_try_jobs(self._try_bots())
 
         if options.trigger_jobs:
             if self.trigger_jobs_for_missing_builds(builds):
@@ -77,7 +63,7 @@
         if not builds:
             _log.info('No builds to download baselines from.')
 
-        _log.debug('Getting results for Rietveld issue %d.', issue_number)
+        _log.debug('Getting results for issue %d.', issue_number)
         builds_to_results = self._fetch_results(builds)
         if builds_to_results is None:
             return 1
@@ -98,17 +84,12 @@
             self.rebaseline(options, test_prefix_list)
         return 0
 
-
-    def _get_issue_number(self, options):
-        """Gets the Rietveld CL number from either |options| or from the current local branch."""
-        if options.issue:
-            return options.issue
+    def _get_issue_number(self):
+        """Returns the current CL number, or None if there is none."""
         issue_number = self.git_cl().get_issue_number()
         _log.debug('Issue number for current branch: %s', issue_number)
         if not issue_number.isdigit():
-            _log.error('No issue number given and no issue for current branch. This tool requires a CL\n'
-                       'to operate on; please run `git cl upload` on this branch first, or use the --issue\n'
-                       'option to download baselines for another existing CL.')
+            _log.error('No CL number for current branch.')
             return None
         return int(issue_number)
 
@@ -194,7 +175,7 @@
         for build, results in builds_to_results.iteritems():
             builds_to_tests[build] = self._tests_to_rebaseline(build, results)
         if only_changed_tests:
-            files_in_cl = self.rietveld.changed_files(issue_number)
+            files_in_cl = self._tool.git().changed_files(diff_filter='AM')
             # Note, in the changed files list from Rietveld, paths always
             # use / as the separator, and they're always relative to repo root.
             # TODO(qyearsley): Do this without using a hard-coded constant.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
index df60e54..83dcf86 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
@@ -7,9 +7,8 @@
 
 from webkitpy.common.net.buildbot import Build
 from webkitpy.common.net.git_cl import GitCL
+from webkitpy.common.checkout.git_mock import MockGit
 from webkitpy.common.net.layout_test_results import LayoutTestResults
-from webkitpy.common.net.rietveld import Rietveld
-from webkitpy.common.net.web_mock import MockWeb
 from webkitpy.common.system.log_testing import LoggingTestCase
 from webkitpy.layout_tests.builder_list import BuilderList
 from webkitpy.tool.commands.rebaseline_cl import RebaselineCL
@@ -22,29 +21,19 @@
     def setUp(self):
         BaseTestCase.setUp(self)
         LoggingTestCase.setUp(self)
-        web = MockWeb(urls={
-            'https://codereview.chromium.org/api/11112222': json.dumps({
-                'patchsets': [1, 2],
-            }),
-            'https://codereview.chromium.org/api/11112222/2': json.dumps({
-                'try_job_results': [
-                    {
-                        'builder': 'MOCK Try Win',
-                        'buildnumber': 5000,
-                        'result': 0,
-                    },
-                    {
-                        'builder': 'MOCK Try Mac',
-                        'buildnumber': 4000,
-                        'result': 0,
-                    },
-                ],
-                'files': {
-                    'third_party/WebKit/LayoutTests/fast/dom/prototype-inheritance.html': {'status': 'M'},
-                    'third_party/WebKit/LayoutTests/fast/dom/prototype-taco.html': {'status': 'M'},
-                },
-            }),
-        })
+
+        git_cl = GitCL(self.tool)
+        git_cl.get_issue_number = lambda: '11112222'
+        git_cl.latest_try_jobs = lambda _: [Build('MOCK Try Win', 5000)]
+        self.command.git_cl = lambda: git_cl
+
+        git = MockGit(filesystem=self.tool.filesystem, executive=self.tool.executive)
+        git.changed_files = lambda **_: [
+            'third_party/WebKit/LayoutTests/fast/dom/prototype-inheritance.html',
+            'third_party/WebKit/LayoutTests/fast/dom/prototype-taco.html',
+        ]
+        self.tool.git = lambda: git
+
         self.tool.builders = BuilderList({
             "MOCK Try Win": {
                 "port_name": "test-win-win7",
@@ -57,8 +46,6 @@
                 "is_try_builder": True,
             },
         })
-        self.command.rietveld = Rietveld(web)
-
         layout_test_results = LayoutTestResults({
             'tests': {
                 'fast': {
@@ -146,7 +133,6 @@
         options = {
             'only_changed_tests': False,
             'dry_run': False,
-            'issue': None,
             'optimize': True,
             'results_directory': None,
             'verbose': False,
@@ -156,7 +142,7 @@
         return optparse.Values(dict(**options))
 
     def test_execute_with_issue_number_given(self):
-        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 0)
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
@@ -167,17 +153,14 @@
         ])
 
     def test_execute_with_no_issue_number(self):
+        git_cl = GitCL(self.tool)
+        git_cl.get_issue_number = lambda: 'None'
+        self.command.git_cl = lambda: git_cl
         return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 1)
-        self.assertLog(['ERROR: No issue number given and no issue for current branch. This tool requires a CL\n'
-                        'to operate on; please run `git cl upload` on this branch first, or use the --issue\n'
-                        'option to download baselines for another existing CL.\n'])
+        self.assertLog(['ERROR: No CL number for current branch.\n'])
 
     def test_execute_with_issue_number_from_branch(self):
-        git_cl = GitCL(self.tool)
-        git_cl.get_issue_number = lambda: '11112222'
-        git_cl.latest_try_jobs = lambda _: [Build('MOCK Try Win', 5000)]
-        self.command.git_cl = lambda: git_cl
         return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 0)
         self.assertLog([
@@ -189,7 +172,7 @@
         ])
 
     def test_execute_with_only_changed_tests_option(self):
-        return_code = self.command.execute(self.command_options(issue=11112222, only_changed_tests=True), [], self.tool)
+        return_code = self.command.execute(self.command_options(only_changed_tests=True), [], self.tool)
         self.assertEqual(return_code, 0)
         # svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html
         # is in the list of failed tests, but not in the list of files modified
@@ -211,7 +194,7 @@
             ],
             'ignored': ['svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html'],
         }))
-        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 0)
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
@@ -223,12 +206,11 @@
         # svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html
         # failed both with and without the patch in the try job, so it is not
         # rebaselined.
-        self.tool.buildbot.set_retry_sumary_json(
-            Build('MOCK Try Win', 5000), None)
-        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        self.tool.buildbot.set_retry_sumary_json(Build('MOCK Try Win', 5000), None)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 0)
         self.assertLog([
-            'WARNING: No retry summary available for build Build(builder_name=u\'MOCK Try Win\', build_number=5000).\n',
+            'WARNING: No retry summary available for build Build(builder_name=\'MOCK Try Win\', build_number=5000).\n',
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
             'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
@@ -237,7 +219,7 @@
         ])
 
     def test_execute_with_trigger_jobs_option(self):
-        return_code = self.command.execute(self.command_options(issue=11112222, trigger_jobs=True), [], self.tool)
+        return_code = self.command.execute(self.command_options(trigger_jobs=True), [], self.tool)
         self.assertEqual(return_code, 1)
         self.assertLog([
             'INFO: Triggering try jobs for:\n',
@@ -258,7 +240,7 @@
             'test contents')
 
         self.command.rebaseline(
-            self.command_options(issue=11112222),
+            self.command_options(),
             {"fast/dom/prototype-taco.html": {Build("MOCK Try Win", 5000): ["txt", "png"]}})
 
         self.assertEqual(
@@ -309,7 +291,7 @@
 
     def test_bails_when_one_build_is_missing_results(self):
         self.tool.buildbot.set_results(Build("MOCK Try Win", 5000), None)
-        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 1)
         self.assertLog([
             'ERROR: Failed to fetch results from '
@@ -321,7 +303,7 @@
     def test_bails_when_there_are_unstaged_baselines(self):
         git = self.tool.git()
         git.unstaged_changes = lambda: {'third_party/WebKit/LayoutTests/my-test-expected.txt': '?'}
-        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
         self.assertEqual(return_code, 1)
         self.assertLog([
             'ERROR: Aborting: there are unstaged baselines:\n',
diff --git a/third_party/WebKit/public/platform/modules/installedapp/OWNERS b/third_party/WebKit/public/platform/modules/installedapp/OWNERS
index e041c27e..065b132 100644
--- a/third_party/WebKit/public/platform/modules/installedapp/OWNERS
+++ b/third_party/WebKit/public/platform/modules/installedapp/OWNERS
@@ -1 +1,3 @@
-dhnishi@chromium.org
+mgiuca@chromium.org
+
+# COMPONENT: Platform>Apps>AppLauncher>Install
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h
index a0ada6b..855ed081 100644
--- a/third_party/WebKit/public/web/WebFrame.h
+++ b/third_party/WebKit/public/web/WebFrame.h
@@ -112,7 +112,7 @@
   // This method closes and deletes the WebFrame. This is typically called by
   // the embedder in response to a frame detached callback to the WebFrame
   // client.
-  virtual void close() = 0;
+  virtual void close();
 
   // Called by the embedder when it needs to detach the subtree rooted at this
   // frame.
@@ -433,7 +433,6 @@
   bool inShadowTree() const { return m_scope == WebTreeScopeType::Shadow; }
 
   static void traceFrames(Visitor*, WebFrame*);
-  void clearWeakFrames(Visitor*);
 #endif
 
  protected:
@@ -452,7 +451,6 @@
   friend class WebFrameTest;
 
   static void traceFrame(Visitor*, WebFrame*);
-  static bool isFrameAlive(const WebFrame*);
 #endif
 
   const WebTreeScopeType m_scope;
diff --git a/third_party/WebKit/public/web/WebFrameOwnerProperties.h b/third_party/WebKit/public/web/WebFrameOwnerProperties.h
index 077e20d..5ba8d741 100644
--- a/third_party/WebKit/public/web/WebFrameOwnerProperties.h
+++ b/third_party/WebKit/public/web/WebFrameOwnerProperties.h
@@ -5,6 +5,7 @@
 #ifndef WebFrameOwnerProperties_h
 #define WebFrameOwnerProperties_h
 
+#include "../platform/WebFeaturePolicy.h"
 #include "../platform/WebString.h"
 #include "../platform/WebVector.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission.mojom-shared.h"
@@ -25,6 +26,9 @@
   WebString requiredCsp;
   WebVector<mojom::PermissionName> delegatedPermissions;
 
+ public:
+  WebVector<WebFeaturePolicyFeature> allowedFeatures;
+
   WebFrameOwnerProperties()
       : scrollingMode(ScrollingMode::Auto),
         marginWidth(-1),
@@ -41,7 +45,8 @@
       bool allowFullscreen,
       bool allowPaymentRequest,
       const WebString& requiredCsp,
-      const WebVector<mojom::PermissionName>& delegatedPermissions)
+      const WebVector<mojom::PermissionName>& delegatedPermissions,
+      const WebVector<WebFeaturePolicyFeature>& allowedFeatures)
       : name(name),
         scrollingMode(static_cast<ScrollingMode>(scrollingMode)),
         marginWidth(marginWidth),
@@ -49,7 +54,8 @@
         allowFullscreen(allowFullscreen),
         allowPaymentRequest(allowPaymentRequest),
         requiredCsp(requiredCsp),
-        delegatedPermissions(delegatedPermissions) {}
+        delegatedPermissions(delegatedPermissions),
+        allowedFeatures(allowedFeatures) {}
 #endif
 };
 
diff --git a/third_party/libaddressinput/BUILD.gn b/third_party/libaddressinput/BUILD.gn
index 5eaa8607..cea22aec 100644
--- a/third_party/libaddressinput/BUILD.gn
+++ b/third_party/libaddressinput/BUILD.gn
@@ -124,6 +124,27 @@
   ]
 }
 
+# This target provides utilities for tests of libaddressinput.
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "src/cpp/test/fake_storage.cc",
+    "src/cpp/test/mock_source.cc",
+    "src/cpp/test/testdata_source.cc",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+
+  defines = [ "TEST_DATA_DIR=\"src/third_party/libaddressinput/src/testdata\"" ]
+
+  include_dirs = [ "src/cpp/src" ]
+
+  deps = [
+    ":libaddressinput",
+  ]
+}
+
 test("libaddressinput_unittests") {
   sources = [
     "chromium/addressinput_util_unittest.cc",
@@ -144,13 +165,11 @@
     "src/cpp/test/address_problem_test.cc",
     "src/cpp/test/address_ui_test.cc",
     "src/cpp/test/address_validator_test.cc",
-    "src/cpp/test/fake_storage.cc",
     "src/cpp/test/fake_storage_test.cc",
     "src/cpp/test/format_element_test.cc",
     "src/cpp/test/language_test.cc",
     "src/cpp/test/localization_test.cc",
     "src/cpp/test/lookup_key_test.cc",
-    "src/cpp/test/mock_source.cc",
     "src/cpp/test/null_storage_test.cc",
     "src/cpp/test/ondemand_supply_task_test.cc",
     "src/cpp/test/post_box_matchers_test.cc",
@@ -162,7 +181,6 @@
     "src/cpp/test/rule_retriever_test.cc",
     "src/cpp/test/rule_test.cc",
     "src/cpp/test/supplier_test.cc",
-    "src/cpp/test/testdata_source.cc",
     "src/cpp/test/testdata_source_test.cc",
     "src/cpp/test/util/json_test.cc",
     "src/cpp/test/util/md5_unittest.cc",
@@ -184,13 +202,12 @@
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [ "//build/config/compiler:no_chromium_code" ]
 
-  defines = [ "TEST_DATA_DIR=\"src/third_party/libaddressinput/src/testdata\"" ]
-
   include_dirs = [ "src/cpp/src" ]
 
   deps = [
     ":libaddressinput",
     ":strings",
+    ":test_support",
     "//base/test:run_all_unittests",
     "//components/prefs",
     "//net:test_support",
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 111eae1..2572a64 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -581,3 +581,71 @@
     testRunner = unittest.runner.TextTestRunner(verbosity=2,
       failfast=flags.failfast, buffer=(not flags.disable_buffer))
     testRunner.run(tests)
+
+# Platform-specific decorators.
+# These decorators can be used to only run a test function for certain platforms
+# by annotating the function with them.
+
+def AndroidOnly(func):
+  def wrapper(*args, **kwargs):
+    if ParseFlags().android:
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Android only.')
+  return wrapper
+
+def NotAndroid(func):
+  def wrapper(*args, **kwargs):
+    if not ParseFlags().android:
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Android.')
+  return wrapper
+
+def WindowsOnly(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform == 'win32':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Windows only.')
+  return wrapper
+
+def NotWindows(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform != 'win32':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Windows.')
+  return wrapper
+
+def LinuxOnly(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform.startswith('linux'):
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Linux only.')
+  return wrapper
+
+def NotLinux(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform.startswith('linux'):
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Linux.')
+  return wrapper
+
+def MacOnly(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform == 'darwin':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Mac OS only.')
+  return wrapper
+
+def NotMac(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform == 'darwin':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Mac OS.')
+  return wrapper
diff --git a/tools/chrome_proxy/webdriver/decorator_smoke.py b/tools/chrome_proxy/webdriver/decorator_smoke.py
new file mode 100644
index 0000000..e9a6c75
--- /dev/null
+++ b/tools/chrome_proxy/webdriver/decorator_smoke.py
@@ -0,0 +1,24 @@
+# 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.
+
+from common import AndroidOnly
+from common import ParseFlags
+from common import IntegrationTest
+
+
+class DecoratorSmokeTest(IntegrationTest):
+
+  def AndroidOnlyFunction(self):
+    # This function should never be called.
+    self.fail()
+
+  @AndroidOnly
+  def testDecorator(self):
+    # This test should always result as 'skipped' or pass if --android given.
+    if not ParseFlags().android:
+      self.AndroidOnlyFunction()
+
+
+if __name__ == '__main__':
+  IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py
index ead67e11..c080b8b 100644
--- a/tools/chrome_proxy/webdriver/video.py
+++ b/tools/chrome_proxy/webdriver/video.py
@@ -7,6 +7,7 @@
 import common
 from common import TestDriver
 from common import IntegrationTest
+from common import NotAndroid
 
 
 class Video(IntegrationTest):
@@ -117,5 +118,17 @@
       if metrics['failed']:
         raise Exception('Test failed!')
 
+  # Make sure YouTube autoplays.
+  @NotAndroid
+  def testYoutube(self):
+    with TestDriver() as t:
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.LoadURL('http://data-saver-test.appspot.com/youtube')
+      t.WaitForJavascriptExpression(
+        'window.playerState == YT.PlayerState.PLAYING', 30)
+      for response in t.GetHTTPResponses():
+        if not response.url.startswith('https'):
+          self.assertHasChromeProxyViaHeader(response)
+
 if __name__ == '__main__':
   IntegrationTest.RunAllTests()
diff --git a/tools/clang/blink_gc_plugin/Edge.h b/tools/clang/blink_gc_plugin/Edge.h
index d7af335..164112f 100644
--- a/tools/clang/blink_gc_plugin/Edge.h
+++ b/tools/clang/blink_gc_plugin/Edge.h
@@ -143,13 +143,13 @@
   {
   }
 
-  bool IsRawPtr() { return true; }
-  LivenessKind Kind() { return kWeak; }
-  bool NeedsFinalization() { return false; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool IsRawPtr() override { return true; }
+  LivenessKind Kind() override { return kWeak; }
+  bool NeedsFinalization() override { return false; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Illegal();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitRawPtr(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitRawPtr(this); }
 
   bool HasReferenceType() { return is_ref_type_; }
  private:
@@ -159,83 +159,83 @@
 class RefPtr : public PtrEdge {
  public:
   explicit RefPtr(Edge* ptr) : PtrEdge(ptr) { }
-  bool IsRefPtr() { return true; }
-  LivenessKind Kind() { return kStrong; }
-  bool NeedsFinalization() { return true; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool IsRefPtr() override { return true; }
+  LivenessKind Kind() override { return kStrong; }
+  bool NeedsFinalization() override { return true; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Illegal();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitRefPtr(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitRefPtr(this); }
 };
 
 class OwnPtr : public PtrEdge {
  public:
   explicit OwnPtr(Edge* ptr) : PtrEdge(ptr) { }
-  bool IsOwnPtr() { return true; }
-  LivenessKind Kind() { return kStrong; }
-  bool NeedsFinalization() { return true; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool IsOwnPtr() override { return true; }
+  LivenessKind Kind() override { return kStrong; }
+  bool NeedsFinalization() override { return true; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Illegal();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitOwnPtr(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitOwnPtr(this); }
 };
 
 class UniquePtr : public PtrEdge {
  public:
   explicit UniquePtr(Edge* ptr) : PtrEdge(ptr) { }
-  bool IsUniquePtr() { return true; }
-  LivenessKind Kind() { return kStrong; }
-  bool NeedsFinalization() { return true; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool IsUniquePtr() override { return true; }
+  LivenessKind Kind() override { return kStrong; }
+  bool NeedsFinalization() override { return true; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Illegal();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitUniquePtr(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitUniquePtr(this); }
 };
 
 class Member : public PtrEdge {
  public:
   explicit Member(Edge* ptr) : PtrEdge(ptr) { }
-  bool IsMember() { return true; }
-  LivenessKind Kind() { return kStrong; }
-  bool NeedsFinalization() { return false; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool IsMember() override { return true; }
+  LivenessKind Kind() override { return kStrong; }
+  bool NeedsFinalization() override { return false; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Needed();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitMember(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitMember(this); }
 };
 
 class WeakMember : public PtrEdge {
  public:
   explicit WeakMember(Edge* ptr) : PtrEdge(ptr) { }
-  bool IsWeakMember() { return true; }
-  LivenessKind Kind() { return kWeak; }
-  bool NeedsFinalization() { return false; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool IsWeakMember() override { return true; }
+  LivenessKind Kind() override { return kWeak; }
+  bool NeedsFinalization() override { return false; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Needed();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitWeakMember(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitWeakMember(this); }
 };
 
 class Persistent : public PtrEdge {
  public:
   explicit Persistent(Edge* ptr) : PtrEdge(ptr) { }
-  LivenessKind Kind() { return kRoot; }
-  bool NeedsFinalization() { return true; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  LivenessKind Kind() override { return kRoot; }
+  bool NeedsFinalization() override { return true; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Unneeded();
   }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitPersistent(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitPersistent(this); }
 };
 
 class CrossThreadPersistent : public PtrEdge {
  public:
   explicit CrossThreadPersistent(Edge* ptr) : PtrEdge(ptr) { }
-  LivenessKind Kind() { return kRoot; }
-  bool NeedsFinalization() { return true; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  LivenessKind Kind() override { return kRoot; }
+  bool NeedsFinalization() override { return true; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     return TracingStatus::Illegal();
   }
-  void Accept(EdgeVisitor* visitor) {
+  void Accept(EdgeVisitor* visitor) override {
     visitor->VisitCrossThreadPersistent(this);
   }
 };
@@ -253,18 +253,18 @@
       delete *it;
     }
   }
-  bool IsCollection() { return true; }
-  LivenessKind Kind() { return is_root_ ? kRoot : kStrong; }
+  bool IsCollection() override { return true; }
+  LivenessKind Kind() override { return is_root_ ? kRoot : kStrong; }
   bool on_heap() { return on_heap_; }
   bool is_root() { return is_root_; }
   Members& members() { return members_; }
-  void Accept(EdgeVisitor* visitor) { visitor->VisitCollection(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitCollection(this); }
   void AcceptMembers(EdgeVisitor* visitor) {
     for (Members::iterator it = members_.begin(); it != members_.end(); ++it)
       (*it)->Accept(visitor);
   }
-  bool NeedsFinalization();
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool NeedsFinalization() override;
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     if (is_root_)
       return TracingStatus::Unneeded();
     if (on_heap_)
@@ -292,10 +292,10 @@
       : info_(info), on_heap_(on_heap), is_unsafe_(is_unsafe) {}
   ~Iterator() {}
 
-  void Accept(EdgeVisitor* visitor) { visitor->VisitIterator(this); }
+  void Accept(EdgeVisitor* visitor) override { visitor->VisitIterator(this); }
   LivenessKind Kind() override { return kStrong; }
-  bool NeedsFinalization() { return false; }
-  TracingStatus NeedsTracing(NeedsTracingOption) {
+  bool NeedsFinalization() override { return false; }
+  TracingStatus NeedsTracing(NeedsTracingOption) override {
     if (on_heap_)
       return TracingStatus::Needed();
     return TracingStatus::Unneeded();
diff --git a/tools/gn/docs/cross_compiles.md b/tools/gn/docs/cross_compiles.md
index 2d7e8a3c..52f9559 100644
--- a/tools/gn/docs/cross_compiles.md
+++ b/tools/gn/docs/cross_compiles.md
@@ -49,7 +49,7 @@
 (We don't have to specify target\_cpu because of the conditionals
 mentioned above).
 
-And, to do a 64-bit MIPS ChromeOS cross-compile:
+And, to do a 64-bit MIPS Chrome OS cross-compile:
 
 ```
 gn gen out/Default --args='target_os="chromeos" target_cpu="mips64el"'
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 7e85b10..48a6683 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -3893,7 +3893,7 @@
 
   This should be set to the most specific value possible. So, "android" or
   "chromeos" should be used instead of "linux" where applicable, even though
-  Android and ChromeOS are both Linux variants. This can mean that one needs to
+  Android and Chrome OS are both Linux variants. This can mean that one needs to
   write
 
       if (target_os == "android" || target_os == "linux") {
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni
index eab1956..d437ee1 100644
--- a/tools/grit/grit_rule.gni
+++ b/tools/grit/grit_rule.gni
@@ -249,10 +249,16 @@
 grit_resource_id_file = "//tools/gritsettings/resource_ids"
 grit_info_script = "//tools/grit/grit_info.py"
 
+# TODO(asvitkine): Add predetermined ids files for other platforms.
 grit_predetermined_resource_ids_file = ""
-
-# TODO(asvitkine): Add platform-specific resource id file paths here.
-#                  http://crbug.com/692670
+if (is_mac) {
+  grit_predetermined_resource_ids_file =
+      "//tools/gritsettings/startup_resources_mac.txt"
+}
+if (is_win) {
+  grit_predetermined_resource_ids_file =
+      "//tools/gritsettings/startup_resources_win.txt"
+}
 
 template("grit") {
   assert(defined(invoker.source),
diff --git a/tools/gritsettings/startup_resources_mac.txt b/tools/gritsettings/startup_resources_mac.txt
new file mode 100644
index 0000000..f9daa12
--- /dev/null
+++ b/tools/gritsettings/startup_resources_mac.txt
@@ -0,0 +1,266 @@
+IDS_PROFILES_OPTIONS_GROUP_NAME 101
+IDS_APP_MENU_PRODUCT_NAME 102
+IDS_PRODUCT_NAME 103
+IDS_ABOUT_MAC 104
+IDS_PREFERENCES 105
+IDS_CLEAR_BROWSING_DATA 106
+IDS_IMPORT_SETTINGS_MENU_MAC 107
+IDS_SERVICES_MAC 108
+IDS_HIDE_APP_MAC 109
+IDS_HIDE_OTHERS_MAC 110
+IDS_SHOW_ALL_MAC 111
+IDS_CONFIRM_TO_QUIT_OPTION 112
+IDS_EXIT_MAC 113
+IDS_FILE_MENU_MAC 114
+IDS_NEW_TAB_MAC 115
+IDS_NEW_WINDOW_MAC 116
+IDS_NEW_INCOGNITO_WINDOW_MAC 117
+IDS_REOPEN_CLOSED_TABS_MAC 118
+IDS_OPEN_FILE_MAC 119
+IDS_OPEN_LOCATION_MAC 120
+IDS_CLOSE_WINDOW_MAC 121
+IDS_CLOSE_TAB_MAC 122
+IDS_SAVE_PAGE_MAC 123
+IDS_EMAIL_PAGE_LOCATION_MAC 124
+IDS_PRINT 125
+IDS_PRINT_USING_SYSTEM_DIALOG_MAC 126
+IDS_EDIT_MENU_MAC 127
+IDS_EDIT_UNDO_MAC 128
+IDS_EDIT_REDO_MAC 129
+IDS_CUT_MAC 130
+IDS_COPY_MAC 131
+IDS_PASTE_MAC 132
+IDS_PASTE_MATCH_STYLE_MAC 133
+IDS_EDIT_DELETE_MAC 134
+IDS_EDIT_SELECT_ALL_MAC 135
+IDS_EDIT_FIND_SUBMENU_MAC 136
+IDS_EDIT_SEARCH_WEB_MAC 137
+IDS_EDIT_FIND_MAC 138
+IDS_EDIT_FIND_NEXT_MAC 139
+IDS_EDIT_FIND_PREVIOUS_MAC 140
+IDS_EDIT_USE_SELECTION_MAC 141
+IDS_EDIT_JUMP_TO_SELECTION_MAC 142
+IDS_EDIT_SPELLING_GRAMMAR_MAC 143
+IDS_EDIT_SHOW_SPELLING_GRAMMAR_MAC 144
+IDS_EDIT_CHECK_DOCUMENT_MAC 145
+IDS_EDIT_CHECK_SPELLING_TYPING_MAC 146
+IDS_EDIT_CHECK_GRAMMAR_MAC 147
+IDS_SPEECH_MAC 148
+IDS_SPEECH_START_SPEAKING_MAC 149
+IDS_SPEECH_STOP_SPEAKING_MAC 150
+IDS_VIEW_MENU_MAC 151
+IDS_BOOKMARK_BAR_ALWAYS_SHOW_MAC 152
+IDS_TOGGLE_FULLSCREEN_TOOLBAR_MAC 153
+IDS_STOP_MENU_MAC 154
+IDS_RELOAD_MENU_MAC 155
+IDS_RELOAD_BYPASSING_CACHE_MENU_MAC 156
+IDS_ENTER_FULLSCREEN_MAC 157
+IDS_TEXT_DEFAULT_MAC 158
+IDS_TEXT_BIGGER_MAC 159
+IDS_TEXT_SMALLER_MAC 160
+IDS_MEDIA_ROUTER_MENU_ITEM_TITLE 161
+IDS_DEVELOPER_MENU_MAC 162
+IDS_VIEW_SOURCE_MAC 163
+IDS_DEV_TOOLS_MAC 164
+IDS_DEV_TOOLS_CONSOLE_MAC 165
+IDS_HISTORY_MENU_MAC 166
+IDS_HISTORY_HOME_MAC 167
+IDS_HISTORY_BACK_MAC 168
+IDS_HISTORY_FORWARD_MAC 169
+IDS_HISTORY_CLOSED_MAC 170
+IDS_HISTORY_VISITED_MAC 171
+IDS_HISTORY_SHOWFULLHISTORY_LINK 172
+IDS_BOOKMARKS_MENU 173
+IDS_BOOKMARK_MANAGER 174
+IDS_BOOKMARK_THIS_PAGE 175
+IDS_BOOKMARK_ALL_TABS_MAC 176
+IDS_WINDOW_MENU_MAC 177
+IDS_MINIMIZE_WINDOW_MAC 178
+IDS_ZOOM_WINDOW_MAC 179
+IDS_NEXT_TAB_MAC 180
+IDS_PREV_TAB_MAC 181
+IDS_SHOW_AS_TAB 182
+IDS_SHOW_DOWNLOADS_MAC 183
+IDS_SHOW_EXTENSIONS_MAC 184
+IDS_TASK_MANAGER_MAC 185
+IDS_ALL_WINDOWS_FRONT_MAC 186
+IDS_HELP_MENU_MAC 187
+IDS_FEEDBACK_MAC 188
+IDS_HELP_MAC 189
+IDS_POLICY_DEPRECATED 190
+IDR_MOJO_CONTENT_BROWSER_MANIFEST 191
+IDR_CHROME_CONTENT_BROWSER_MANIFEST_OVERLAY 192
+IDR_MOJO_CONTENT_GPU_MANIFEST 193
+IDR_CHROME_CONTENT_GPU_MANIFEST_OVERLAY 194
+IDR_MOJO_CONTENT_PACKAGED_SERVICES_MANIFEST 195
+IDR_CHROME_CONTENT_PACKAGED_SERVICES_MANIFEST_OVERLAY 196
+IDR_MOJO_CONTENT_PLUGIN_MANIFEST 197
+IDR_CHROME_CONTENT_PLUGIN_MANIFEST_OVERLAY 198
+IDR_MOJO_CONTENT_RENDERER_MANIFEST 199
+IDR_CHROME_CONTENT_RENDERER_MANIFEST_OVERLAY 200
+IDR_MOJO_CONTENT_UTILITY_MANIFEST 201
+IDR_CHROME_CONTENT_UTILITY_MANIFEST_OVERLAY 202
+IDR_MOJO_CATALOG_MANIFEST 203
+IDR_NACL_LOADER_MANIFEST 204
+IDR_DOWNLOAD_FILE_TYPES_PB 205
+IDR_PLUGIN_DB_JSON 206
+IDS_DEFAULT_PROFILE_NAME 207
+IDS_LEGACY_DEFAULT_PROFILE_NAME 208
+IDS_ACCEPT_LANGUAGES 209
+IDS_DEFAULT_ENCODING 210
+IDS_STANDARD_FONT_FAMILY 211
+IDS_FIXED_FONT_FAMILY 212
+IDS_SERIF_FONT_FAMILY 213
+IDS_SANS_SERIF_FONT_FAMILY 214
+IDS_CURSIVE_FONT_FAMILY 215
+IDS_FANTASY_FONT_FAMILY 216
+IDS_PICTOGRAPH_FONT_FAMILY 217
+IDS_STANDARD_FONT_FAMILY_JAPANESE 218
+IDS_FIXED_FONT_FAMILY_JAPANESE 219
+IDS_SERIF_FONT_FAMILY_JAPANESE 220
+IDS_SANS_SERIF_FONT_FAMILY_JAPANESE 221
+IDS_STANDARD_FONT_FAMILY_KOREAN 222
+IDS_SERIF_FONT_FAMILY_KOREAN 223
+IDS_SANS_SERIF_FONT_FAMILY_KOREAN 224
+IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN 225
+IDS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN 226
+IDS_SANS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN 227
+IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN 228
+IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN 229
+IDS_SANS_SERIF_FONT_FAMILY_TRADITIONAL_HAN 230
+IDS_CURSIVE_FONT_FAMILY_SIMPLIFIED_HAN 231
+IDS_CURSIVE_FONT_FAMILY_TRADITIONAL_HAN 232
+IDS_DEFAULT_FONT_SIZE 233
+IDS_DEFAULT_FIXED_FONT_SIZE 234
+IDS_MINIMUM_FONT_SIZE 235
+IDS_MINIMUM_LOGICAL_FONT_SIZE 236
+IDS_SPELLCHECK_DICTIONARY 237
+IDR_PREF_HASH_SEED_BIN 238
+IDS_BOOKMARK_BAR_FOLDER_NAME 239
+IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME 240
+IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME 241
+IDS_PROFILES_DEFAULT_NAME 242
+IDR_BOOKMARKS_MANIFEST 243
+IDR_CLOUDPRINT_MANIFEST 244
+IDS_WEBSTORE_NAME_STORE 245
+IDS_WEBSTORE_APP_DESCRIPTION 246
+IDR_WEBSTORE_MANIFEST 247
+IDR_HANGOUT_SERVICES_MANIFEST 248
+IDR_FEEDBACK_MANIFEST 249
+IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST 250
+IDR_CRYPTOTOKEN_MANIFEST 251
+IDR_PDF_MANIFEST 252
+IDS_CHROME_WELCOME_URL 253
+IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE 254
+IDS_WEBSTORE_URL 255
+IDS_EXTENSION_WEB_STORE_TITLE 256
+IDR_EXTENSIONS_FAVICON 257
+IDS_EXTENSION_USB_DEVICE_PRODUCT_NAME_AND_VENDOR 258
+IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME 259
+IDS_BOOKMARK_BAR_SUPERVISED_FOLDER_DEFAULT_NAME 260
+IDS_TOOLTIP_NEW_TAB 261
+IDS_PROFILES_NEW_AVATAR_BUTTON_ACCESSIBLE_NAME 262
+IDR_DEFAULT_FAVICON 263
+IDS_ACCNAME_NEWTAB 264
+IDS_APPMENU_TOOLTIP 265
+IDS_TOOLTIP_BACK 266
+IDS_TOOLTIP_FORWARD 267
+IDS_TOOLTIP_RELOAD 268
+IDS_TOOLTIP_HOME 269
+IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM 270
+IDS_RELOAD_MENU_HARD_RELOAD_ITEM 271
+IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM 272
+IDS_TOOLTIP_STAR 273
+IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP 274
+IDS_VIEW_INCOMPATIBILITIES 275
+IDR_INPUT_ALERT_MENU 276
+IDS_NEW_TAB 277
+IDS_NEW_WINDOW 278
+IDS_NEW_INCOGNITO_WINDOW 279
+IDS_HISTORY_SHOW_HISTORY 280
+IDS_RECENTLY_CLOSED 281
+IDS_RECENT_TABS_NO_DEVICE_TABS 282
+IDS_HISTORY_MENU 283
+IDS_SHOW_DOWNLOADS 284
+IDS_BOOKMARK_OPEN_PAGES 285
+IDS_SHOW_BOOKMARK_BAR 286
+IDS_IMPORT_SETTINGS_MENU_LABEL 287
+IDS_ZOOM_MENU 288
+IDS_ZOOM_MINUS2 289
+IDS_ZOOM_PLUS2 290
+IDS_FIND 291
+IDS_SAVE_PAGE 292
+IDS_SHOW_EXTENSIONS 293
+IDS_TASK_MANAGER 294
+IDS_DEV_TOOLS 295
+IDS_MORE_TOOLS_MENU 296
+IDS_EDIT 297
+IDS_CUT 298
+IDS_COPY 299
+IDS_PASTE 300
+IDS_SETTINGS 301
+IDS_ABOUT 302
+IDS_HELP_PAGE 303
+IDS_FEEDBACK 304
+IDS_HELP_MENU 305
+IDS_ACCNAME_BACK 306
+IDS_ACCNAME_TOOLTIP_BACK 307
+IDS_ACCNAME_FORWARD 308
+IDS_ACCNAME_TOOLTIP_FORWARD 309
+IDS_ACCNAME_RELOAD 310
+IDS_ACCNAME_HOME 311
+IDS_ACCNAME_LOCATION 312
+IDS_ACCNAME_APP 313
+IDR_BOOKMARK_BAR_FOLDER 314
+IDR_BOOKMARK_BAR_FOLDER_WHITE 315
+IDS_BOOKMARK_BAR_IMPORT_LINK 316
+IDS_BOOKMARKS_NO_ITEMS 317
+IDS_TOOLTIP_LOCATION_ICON 318
+IDS_NEW_TAB_TITLE 319
+IDS_DEFAULT_TAB_TITLE 320
+IDS_ACCNAME_CLOSE 321
+IDS_TOOLTIP_CLOSE_TAB 322
+IDS_ACCNAME_CLOSE_TAB 323
+IDR_THROBBER_WAITING 324
+IDR_THROBBER_WAITING_INCOGNITO 325
+IDR_THROBBER 326
+IDR_THROBBER_INCOGNITO 327
+IDR_CRASH_SAD_FAVICON 328
+IDS_TOOLTIP_STOP 329
+IDS_UTILITY_PROCESS_PROXY_RESOLVER_NAME 330
+IDS_NEW_MAC 331
+IDS_QUIT_WITH_APPS_QUIT_LABEL 332
+IDS_QUIT_WITH_APPS_SUPPRESSION_LABEL 333
+IDS_QUIT_WITH_APPS_TITLE 334
+IDS_QUIT_WITH_APPS_EXPLANATION 335
+IDR_PRODUCT_LOGO_128 336
+IDS_QUIT_WITH_APPS_NOTIFICATION_DISPLAY_SOURCE 337
+IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE 338
+IDS_PROFILES_LOCAL_PROFILE_STATE 339
+IDS_PROFILES_MANAGE_BUTTON_LABEL 340
+IDS_PROFILES_CREATE_NEW_PROFILE_OPTION 341
+IDR_PROFILE_AVATAR_26 342
+IDS_BOOKMARK_BAR_APPS_SHORTCUT_NAME 343
+IDR_BOOKMARK_BAR_APPS_SHORTCUT 344
+IDS_BOOKMARK_BAR_APPS_SHORTCUT_TOOLTIP 345
+IDR_BOOKMARK_BAR_FOLDER_MANAGED 346
+IDR_BOOKMARK_BAR_FOLDER_SUPERVISED 347
+IDS_WEB_FONT_FAMILY 348
+IDS_WEB_FONT_SIZE 349
+IDR_HISTORY_FAVICON 350
+IDS_UTILITY_PROCESS_MANIFEST_PARSER_NAME 351
+IDR_MOST_VISITED_SINGLE_HTML 352
+IDR_MOST_VISITED_SINGLE_CSS 353
+IDR_MOST_VISITED_SINGLE_JS 354
+IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL 355
+IDR_PRODUCT_LOGO_16 356
+IDR_NEWTAB_WEBSTORE_THUMBNAIL 357
+IDR_WEBSTORE_ICON_16 358
+IDR_CLOSE_3_MASK 359
+IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME 360
+IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION 361
+IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR 362
+IDR_OVERLAY_DROP_SHADOW 363
+IDS_ANNOUNCEMENT_COMPLETION_AVAILABLE_MAC 364
+IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD_READWRITE 365
+IDS_EXTENSION_PROMPT_WARNING_NOTIFICATIONS 366
diff --git a/tools/gritsettings/startup_resources_win.txt b/tools/gritsettings/startup_resources_win.txt
new file mode 100644
index 0000000..3c56a67
--- /dev/null
+++ b/tools/gritsettings/startup_resources_win.txt
@@ -0,0 +1,223 @@
+IDR_MOJO_CONTENT_BROWSER_MANIFEST 101
+IDR_CHROME_CONTENT_BROWSER_MANIFEST_OVERLAY 102
+IDR_MOJO_CONTENT_GPU_MANIFEST 103
+IDR_CHROME_CONTENT_GPU_MANIFEST_OVERLAY 104
+IDR_MOJO_CONTENT_PACKAGED_SERVICES_MANIFEST 105
+IDR_CHROME_CONTENT_PACKAGED_SERVICES_MANIFEST_OVERLAY 106
+IDR_MOJO_CONTENT_PLUGIN_MANIFEST 107
+IDR_CHROME_CONTENT_PLUGIN_MANIFEST_OVERLAY 108
+IDR_MOJO_CONTENT_RENDERER_MANIFEST 109
+IDR_CHROME_CONTENT_RENDERER_MANIFEST_OVERLAY 110
+IDR_MOJO_CONTENT_UTILITY_MANIFEST 111
+IDR_CHROME_CONTENT_UTILITY_MANIFEST_OVERLAY 112
+IDR_MOJO_CATALOG_MANIFEST 113
+IDR_NACL_LOADER_MANIFEST 114
+IDR_NACL_BROKER_MANIFEST 115
+IDR_DOWNLOAD_FILE_TYPES_PB 116
+IDR_PLUGIN_DB_JSON 117
+IDS_DEFAULT_PROFILE_NAME 118
+IDS_LEGACY_DEFAULT_PROFILE_NAME 119
+IDS_ACCEPT_LANGUAGES 120
+IDS_DEFAULT_ENCODING 121
+IDS_STANDARD_FONT_FAMILY 122
+IDS_FIXED_FONT_FAMILY 123
+IDS_FIXED_FONT_FAMILY_ALT_WIN 124
+IDS_SERIF_FONT_FAMILY 125
+IDS_SANS_SERIF_FONT_FAMILY 126
+IDS_CURSIVE_FONT_FAMILY 127
+IDS_FANTASY_FONT_FAMILY 128
+IDS_PICTOGRAPH_FONT_FAMILY 129
+IDS_STANDARD_FONT_FAMILY_JAPANESE 130
+IDS_FIXED_FONT_FAMILY_JAPANESE 131
+IDS_SERIF_FONT_FAMILY_JAPANESE 132
+IDS_SANS_SERIF_FONT_FAMILY_JAPANESE 133
+IDS_STANDARD_FONT_FAMILY_KOREAN 134
+IDS_SERIF_FONT_FAMILY_KOREAN 135
+IDS_SANS_SERIF_FONT_FAMILY_KOREAN 136
+IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN 137
+IDS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN 138
+IDS_SANS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN 139
+IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN 140
+IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN 141
+IDS_SANS_SERIF_FONT_FAMILY_TRADITIONAL_HAN 142
+IDS_CURSIVE_FONT_FAMILY_SIMPLIFIED_HAN 143
+IDS_CURSIVE_FONT_FAMILY_TRADITIONAL_HAN 144
+IDS_FIXED_FONT_FAMILY_ARABIC 145
+IDS_SANS_SERIF_FONT_FAMILY_ARABIC 146
+IDS_STANDARD_FONT_FAMILY_CYRILLIC 147
+IDS_FIXED_FONT_FAMILY_CYRILLIC 148
+IDS_SERIF_FONT_FAMILY_CYRILLIC 149
+IDS_SANS_SERIF_FONT_FAMILY_CYRILLIC 150
+IDS_STANDARD_FONT_FAMILY_GREEK 151
+IDS_FIXED_FONT_FAMILY_GREEK 152
+IDS_SERIF_FONT_FAMILY_GREEK 153
+IDS_SANS_SERIF_FONT_FAMILY_GREEK 154
+IDS_FIXED_FONT_FAMILY_KOREAN 155
+IDS_CURSIVE_FONT_FAMILY_KOREAN 156
+IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN 157
+IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN 158
+IDS_DEFAULT_FONT_SIZE 159
+IDS_DEFAULT_FIXED_FONT_SIZE 160
+IDS_MINIMUM_FONT_SIZE 161
+IDS_MINIMUM_LOGICAL_FONT_SIZE 162
+IDS_SPELLCHECK_DICTIONARY 163
+IDR_PREF_HASH_SEED_BIN 164
+IDS_POLICY_VALUE_FORMAT_ERROR 165
+IDS_POLICY_LIST_ENTRY_ERROR 166
+IDS_BOOKMARK_BAR_FOLDER_NAME 167
+IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME 168
+IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME 169
+IDS_PRODUCT_NAME 170
+IDS_PROFILES_DEFAULT_NAME 171
+IDR_BOOKMARKS_MANIFEST 172
+IDR_CLOUDPRINT_MANIFEST 173
+IDS_WEBSTORE_APP_DESCRIPTION 174
+IDS_WEBSTORE_NAME_STORE 175
+IDR_WEBSTORE_MANIFEST 176
+IDR_HANGOUT_SERVICES_MANIFEST 177
+IDR_FEEDBACK_MANIFEST 178
+IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST 179
+IDR_CRYPTOTOKEN_MANIFEST 180
+IDR_PDF_MANIFEST 181
+IDS_CHROME_WELCOME_URL 182
+IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE 183
+IDS_WEBSTORE_URL 184
+IDS_EXTENSION_WEB_STORE_TITLE 185
+IDR_EXTENSIONS_FAVICON 186
+IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME 187
+IDS_BOOKMARK_BAR_SUPERVISED_FOLDER_DEFAULT_NAME 188
+IDS_CRASH_RECOVERY_TITLE 189
+IDS_CRASH_RECOVERY_CONTENT 190
+IDR_CONTENT_RIGHT_SIDE 191
+IDR_CONTENT_BOTTOM_CENTER 192
+IDR_CONTENT_LEFT_SIDE 193
+IDS_UI_FONT_FAMILY 194
+IDS_UI_FONT_SIZE_SCALER 195
+IDS_MINIMUM_UI_FONT_SIZE 196
+IDS_APP_COPY 197
+IDS_APP_SELECT_ALL 198
+IDR_TEXTBUTTON_HOVER_TOP_LEFT 199
+IDR_TEXTBUTTON_HOVER_TOP 200
+IDR_TEXTBUTTON_HOVER_TOP_RIGHT 201
+IDR_TEXTBUTTON_HOVER_LEFT 202
+IDR_TEXTBUTTON_HOVER_CENTER 203
+IDR_TEXTBUTTON_HOVER_RIGHT 204
+IDR_TEXTBUTTON_HOVER_BOTTOM_LEFT 205
+IDR_TEXTBUTTON_HOVER_BOTTOM 206
+IDR_TEXTBUTTON_HOVER_BOTTOM_RIGHT 207
+IDR_TEXTBUTTON_PRESSED_TOP_LEFT 208
+IDR_TEXTBUTTON_PRESSED_TOP 209
+IDR_TEXTBUTTON_PRESSED_TOP_RIGHT 210
+IDR_TEXTBUTTON_PRESSED_LEFT 211
+IDR_TEXTBUTTON_PRESSED_CENTER 212
+IDR_TEXTBUTTON_PRESSED_RIGHT 213
+IDR_TEXTBUTTON_PRESSED_BOTTOM_LEFT 214
+IDR_TEXTBUTTON_PRESSED_BOTTOM 215
+IDR_TEXTBUTTON_PRESSED_BOTTOM_RIGHT 216
+IDR_AVATAR_GLASS_BUTTON_NORMAL_TOP_LEFT 217
+IDR_AVATAR_GLASS_BUTTON_NORMAL_TOP 218
+IDR_AVATAR_GLASS_BUTTON_NORMAL_TOP_RIGHT 219
+IDR_AVATAR_GLASS_BUTTON_NORMAL_LEFT 220
+IDR_AVATAR_GLASS_BUTTON_NORMAL_CENTER 221
+IDR_AVATAR_GLASS_BUTTON_NORMAL_RIGHT 222
+IDR_AVATAR_GLASS_BUTTON_NORMAL_BOTTOM_LEFT 223
+IDR_AVATAR_GLASS_BUTTON_NORMAL_BOTTOM 224
+IDR_AVATAR_GLASS_BUTTON_NORMAL_BOTTOM_RIGHT 225
+IDR_AVATAR_GLASS_BUTTON_HOVER_TOP_LEFT 226
+IDR_AVATAR_GLASS_BUTTON_HOVER_TOP 227
+IDR_AVATAR_GLASS_BUTTON_HOVER_TOP_RIGHT 228
+IDR_AVATAR_GLASS_BUTTON_HOVER_LEFT 229
+IDR_AVATAR_GLASS_BUTTON_HOVER_CENTER 230
+IDR_AVATAR_GLASS_BUTTON_HOVER_RIGHT 231
+IDR_AVATAR_GLASS_BUTTON_HOVER_BOTTOM_LEFT 232
+IDR_AVATAR_GLASS_BUTTON_HOVER_BOTTOM 233
+IDR_AVATAR_GLASS_BUTTON_HOVER_BOTTOM_RIGHT 234
+IDR_AVATAR_GLASS_BUTTON_PRESSED_TOP_LEFT 235
+IDR_AVATAR_GLASS_BUTTON_PRESSED_TOP 236
+IDR_AVATAR_GLASS_BUTTON_PRESSED_TOP_RIGHT 237
+IDR_AVATAR_GLASS_BUTTON_PRESSED_LEFT 238
+IDR_AVATAR_GLASS_BUTTON_PRESSED_CENTER 239
+IDR_AVATAR_GLASS_BUTTON_PRESSED_RIGHT 240
+IDR_AVATAR_GLASS_BUTTON_PRESSED_BOTTOM_LEFT 241
+IDR_AVATAR_GLASS_BUTTON_PRESSED_BOTTOM 242
+IDR_AVATAR_GLASS_BUTTON_PRESSED_BOTTOM_RIGHT 243
+IDR_AVATAR_GLASS_BUTTON_AVATAR 244
+IDS_TOOLTIP_NEW_TAB 245
+IDS_ACCNAME_NEWTAB 246
+IDR_TAB_DROP_DOWN 247
+IDS_TOOLTIP_BACK 248
+IDS_ACCNAME_BACK 249
+IDS_TOOLTIP_FORWARD 250
+IDS_ACCNAME_FORWARD 251
+IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM 252
+IDS_RELOAD_MENU_HARD_RELOAD_ITEM 253
+IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM 254
+IDS_ACCNAME_RELOAD 255
+IDS_TOOLTIP_HOME 256
+IDS_ACCNAME_HOME 257
+IDR_DEVELOPER_MODE_HIGHLIGHT_TOP_LEFT 258
+IDR_DEVELOPER_MODE_HIGHLIGHT_TOP 259
+IDR_DEVELOPER_MODE_HIGHLIGHT_TOP_RIGHT 260
+IDR_DEVELOPER_MODE_HIGHLIGHT_LEFT 261
+IDR_DEVELOPER_MODE_HIGHLIGHT_CENTER 262
+IDR_DEVELOPER_MODE_HIGHLIGHT_RIGHT 263
+IDR_DEVELOPER_MODE_HIGHLIGHT_BOTTOM_LEFT 264
+IDR_DEVELOPER_MODE_HIGHLIGHT_BOTTOM 265
+IDR_DEVELOPER_MODE_HIGHLIGHT_BOTTOM_RIGHT 266
+IDR_MENU_DROPARROW 267
+IDS_ACCNAME_APP 268
+IDS_APPMENU_TOOLTIP 269
+IDS_APP_TAB_KEY 270
+IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP 271
+IDS_TOOLTIP_SAVE_CREDIT_CARD 272
+IDS_TOOLTIP_TRANSLATE 273
+IDS_TOOLTIP_STAR 274
+IDS_DEFAULT_TAB_TITLE 275
+IDS_BROWSER_WINDOW_TITLE_FORMAT 276
+IDR_DEFAULT_FAVICON 277
+IDS_NEW_TAB_TITLE 278
+IDS_ACCNAME_CLOSE 279
+IDS_ACCNAME_BOOKMARKS_CHEVRON 280
+IDS_BOOKMARK_BAR_APPS_SHORTCUT_NAME 281
+IDS_BOOKMARK_BAR_APPS_SHORTCUT_TOOLTIP 282
+IDR_BOOKMARK_BAR_APPS_SHORTCUT 283
+IDS_BOOKMARKS_NO_ITEMS 284
+IDS_BOOKMARK_BAR_IMPORT_LINK 285
+IDR_BOOKMARK_BAR_FOLDER 286
+IDR_BOOKMARK_BAR_FOLDER_MANAGED 287
+IDR_BOOKMARK_BAR_FOLDER_SUPERVISED 288
+IDS_WEB_FONT_SIZE 289
+IDS_WEB_FONT_FAMILY 290
+IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT 291
+IDS_DEFAULT_BROWSER_INFOBAR_OK_BUTTON_LABEL 292
+IDR_CONTENT_BOTTOM_RIGHT_CORNER 293
+IDR_CONTENT_BOTTOM_LEFT_CORNER 294
+IDS_UTILITY_PROCESS_PROXY_RESOLVER_NAME 295
+IDS_UTILITY_PROCESS_MANIFEST_PARSER_NAME 296
+IDR_MOST_VISITED_SINGLE_HTML 297
+IDR_MOST_VISITED_SINGLE_CSS 298
+IDR_MOST_VISITED_SINGLE_JS 299
+IDR_NEWTAB_CHROME_WELCOME_PAGE_THUMBNAIL 300
+IDR_PRODUCT_LOGO_16 301
+IDR_NEWTAB_WEBSTORE_THUMBNAIL 302
+IDR_WEBSTORE_ICON_16 303
+IDR_CLOSE_3_MASK 304
+IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION 305
+IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR 306
+IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME 307
+IDS_NEW_TAB_MOST_VISITED 308
+IDS_RECENTLY_CLOSED 309
+IDS_NEW_WINDOW 310
+IDS_NEW_INCOGNITO_WINDOW 311
+IDS_EXTENSION_USB_DEVICE_PRODUCT_NAME_AND_VENDOR 312
+IDS_APP_SHORTCUTS_SUBDIR_NAME 313
+IDR_LOCAL_NTP_HTML 314
+IDR_LOCAL_NTP_CSS 315
+IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION 316
+IDS_NEW_TAB_REMOVE_THUMBNAIL_TOOLTIP 317
+IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE 318
+IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK 319
+IDS_NEW_TAB_ATTRIBUTION_INTRO 320
+IDS_SEARCH_BOX_EMPTY_HINT 321
+IDR_LOCAL_NTP_JS 322
+IDR_ADDITIONAL_MODULE_IDS 323
diff --git a/tools/mb/docs/design_spec.md b/tools/mb/docs/design_spec.md
index 33fda80..fb202da 100644
--- a/tools/mb/docs/design_spec.md
+++ b/tools/mb/docs/design_spec.md
@@ -411,9 +411,9 @@
 ### Non-goals
 
 * MB is not intended to replace direct invocation of GN or GYP for
-  complicated build scenarios (aka ChromeOS), where multiple flags need
+  complicated build scenarios (a.k.a. Chrome OS), where multiple flags need
   to be set to user-defined paths for specific toolchains (e.g., where
-  ChromeOS needs to specify specific board types and compilers).
+  Chrome OS needs to specify specific board types and compilers).
 
 * MB is not intended at this time to be something developers use frequently,
   or to add a lot of features to. We hope to be able to get rid of it once
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 459a7e9..10a462f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -25832,6 +25832,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.HasEverPlayed" enum="BooleanHasPlayed">
+  <owner>dalecurtis@chromium.org</owner>
+  <summary>
+    Whether a given WebMediaPlayer instance, after preload, started playback;
+    recorded once at time of player destruction.
+  </summary>
+</histogram>
+
 <histogram name="Media.HighLatencyAudioCaptureStartupSuccess"
     enum="AudioCaptureStartupResult">
   <owner>maxmorin@chromium.org</owner>
@@ -26473,6 +26481,9 @@
 </histogram>
 
 <histogram name="Media.UnderflowCount">
+  <obsolete>
+    Removed Feb 2017. Media.UnderflowDuration provides more useful counts.
+  </obsolete>
   <owner>dalecurtis@chromium.org</owner>
   <summary>
     The number of times a src= playback has underflowed; i.e. ran out of data.
@@ -26482,7 +26493,16 @@
 <histogram name="Media.UnderflowDuration" units="ms">
   <owner>dalecurtis@chromium.org</owner>
   <summary>
-    The amount of time taken to leave the underflow state; i.e. resume playback.
+    The amount of time taken to leave the underflow state (i.e. resume playback)
+    for src= playbacks.
+  </summary>
+</histogram>
+
+<histogram name="Media.UnderflowDuration.MSE" units="ms">
+  <owner>dalecurtis@chromium.org</owner>
+  <summary>
+    The amount of time taken to leave the underflow state (i.e. resume playback)
+    for Media Source Extensions (MSE) based playbacks.
   </summary>
 </histogram>
 
@@ -43938,6 +43958,19 @@
   <summary>Events related to Google CAPTCHA pages being seen by users.</summary>
 </histogram>
 
+<histogram name="PageLoad.Clients.SubresourceFilter.ActivationDecision"
+    enum="SubresourceFilterActivationDecision">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Records the policy decision to activate subresource filtering for a page
+    load. 'Activated' indicates that subresource filtering was activated. All
+    other reasons indicate that subresource filtering was not activated. Page
+    loads where subresource filtering was activated ('Activated') and at least
+    one subresource matched the subresource filter are counted in
+    PageLoad.Clients.SubresourceFilter.Count.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Clients.SubresourceFilter.Count" enum="Boolean">
   <owner>bmcquade@chromium.org</owner>
   <summary>
@@ -44074,6 +44107,9 @@
 
 <histogram base="true" name="PageLoad.Experimental.AbortTiming.ClientRedirect"
     units="ms">
+  <obsolete>
+    Deprecated in favor of PageLoad.Internal.ClientRedirect.*.
+  </obsolete>
   <owner>csharrison@chromium.org</owner>
   <summary>
     This metric is still experimental and not yet ready to be relied upon.
@@ -44215,6 +44251,43 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Experimental.PageTiming.FirstPaintToFirstBackground"
+    units="ms">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Measures the total time the page load was active after first paint, up until
+    being backgrounded, prior to the page load terminating. Recorded only for
+    page loads that started in the foreground.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Experimental.PageTiming.FirstPaintToPageEnd"
+    units="ms">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Measures the total time the page load was active after first paint, for page
+    loads that spend the entire time in the foreground.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Experimental.PageTiming.NavigationToFirstBackground"
+    units="ms">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Measures the total time the page load was active, up until being
+    backgrounded, for page loads that started in the foreground.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Experimental.PageTiming.NavigationToPageEnd"
+    units="ms">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Measures the total time the page load was active, for page loads that spend
+    the entire time in the foreground.
+  </summary>
+</histogram>
+
 <histogram
     name="PageLoad.Experimental.PaintTiming.FirstMeaningfulPaintSignalStatus"
     enum="FirstMeaningfulPaintSignalStatus">
@@ -44452,6 +44525,27 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.PageTiming.NavigationToFailedProvisionalLoad"
+    units="ms">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>shivanisha@chromium.org</owner>
+  <summary>
+    Measures the time from navigation timing's navigation start to the time the
+    provisional load failed. Only measures provisional loads that failed in the
+    foreground.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.PageTiming.NavigationToFirstForeground" units="ms">
+  <owner>bmcquade@chromium.org</owner>
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    Measures the time from navigation timing's navigation start to the time the
+    user first foregrounds an initially backgrounded tab. Only measures
+    navigations that started in the background.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.PaintTiming.ForegroundToFirstPaint" units="ms">
   <owner>pkotwicz@chromium.org</owner>
   <summary>
@@ -44667,6 +44761,9 @@
 </histogram>
 
 <histogram name="PageLoad.Timing2.NavigationToFailedProvisionalLoad" units="ms">
+  <obsolete>
+    deprecated in favor of PageLoad.PageTiming.NavigationToFailedProvisionalLoad
+  </obsolete>
   <owner>bmcquade@chromium.org</owner>
   <owner>shivanisha@chromium.org</owner>
   <summary>
@@ -44702,6 +44799,9 @@
 </histogram>
 
 <histogram name="PageLoad.Timing2.NavigationToFirstForeground" units="ms">
+  <obsolete>
+    deprecated in favor of PageLoad.PageTiming.NavigationToFirstForeground
+  </obsolete>
   <owner>bmcquade@chromium.org</owner>
   <owner>csharrison@chromium.org</owner>
   <summary>
@@ -80925,6 +81025,11 @@
   <int value="1" label="Has path"/>
 </enum>
 
+<enum name="BooleanHasPlayed" type="int">
+  <int value="0" label="Never played"/>
+  <int value="1" label="Played"/>
+</enum>
+
 <enum name="BooleanHasSeekPenalty" type="int">
   <int value="0" label="Has no seek penalty (e.g. is flash memory)"/>
   <int value="1" label="Has seek penalty (e.g. spinning disk)"/>
@@ -95409,7 +95514,7 @@
   <int value="2" label="IPC received from a frame we navigated away from"/>
   <int value="3" label="IPC received from a bad URL scheme"/>
   <int value="4" label="No IPCs received for this navigation"/>
-  <int value="5" label="Abort reported before navigation start"/>
+  <int value="5" label="Page end reported before navigation start"/>
   <int value="6"
       label="Multiple aborted provisional loads at navigation start"/>
   <int value="7"
@@ -95417,6 +95522,7 @@
              (deprecated)"/>
   <int value="8" label="Inter process TimeTicks skew"/>
   <int value="9" label="No commit or failed provisional load received"/>
+  <int value="10" label="No page load end time recorded"/>
 </enum>
 
 <enum name="InterruptReason" type="int">
@@ -97879,6 +97985,7 @@
   <int value="1862207743" label="enable-android-spellchecker"/>
   <int value="1865068568" label="disable-audio-support-for-desktop-share"/>
   <int value="1865799183" label="javascript-harmony"/>
+  <int value="1866079109" label="team-drives"/>
   <int value="1867085340" label="brotli-encoding:enabled"/>
   <int value="1878331098" label="GuestViewCrossProcessFrames:enabled"/>
   <int value="1881036528" label="disable-multilingual-spellchecker"/>
@@ -108600,6 +108707,15 @@
   <int value="2" label="MemoryCached StyleSheetContents was reused"/>
 </enum>
 
+<enum name="SubresourceFilterActivationDecision" type="int">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="Activated"/>
+  <int value="2" label="Disabled"/>
+  <int value="3" label="Unsupported scheme"/>
+  <int value="4" label="URL whitelisted"/>
+  <int value="5" label="Activation list not matched"/>
+</enum>
+
 <enum name="SubresourceFilterActivationState" type="int">
   <int value="0" label="Disabled"/>
   <int value="1" label="DryRun"/>
@@ -117726,6 +117842,16 @@
       name="PageLoad.PaintTiming.ParseStartToFirstContentfulPaint"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsClientsTabRestore" separator="."
+    ordering="prefix">
+  <suffix name="Clients.TabRestore"
+      label="PageLoadMetrics that are a result of a navigation caused by a
+             tab restore."/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Cache"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Network"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Total"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsLoadType" separator=".">
   <suffix name="LoadType.Reload" label="Restricted to reloaded pages."/>
   <suffix name="LoadType.ForwardBackNavigation"
@@ -117734,10 +117860,22 @@
       label="Restricted to new navigations (link clicks, URLs typed into the
              URL box, etc)."/>
   <affected-histogram
+      name="PageLoad.Clients.SubresourceFilter.ActivationDecision"/>
+  <affected-histogram
       name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/>
   <affected-histogram name="PageLoad.ParseTiming.NavigationToParseStart"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsNoEndTime" separator=".">
+  <suffix name="NoEndTime"
+      label="The page load had no recorded end time, so an end time was
+             synthesized at the time the page end notification was processed."/>
+  <affected-histogram
+      name="PageLoad.Experimental.PageTiming.FirstPaintToPageEnd"/>
+  <affected-histogram
+      name="PageLoad.Experimental.PageTiming.NavigationToPageEnd"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsUserGesture" separator=".">
   <suffix name="UserGesture"
       label="Restricted to pages loaded via a user gesture."/>
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index 2ea35fb..164a5f9 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -61,9 +61,7 @@
 
   @classmethod
   def ShouldDisable(cls, possible_browser):
-    # http://crbug.com/624355 (reference builds).
-    return (possible_browser.platform.GetDeviceTypeName() != 'Desktop' or
-            possible_browser.browser_type == 'reference')
+    return possible_browser.platform.GetDeviceTypeName() != 'Desktop'
 
 @benchmark.Enabled('android')
 class MobileCommonSystemHealth(_CommonSystemHealthBenchmark):
@@ -116,9 +114,7 @@
 
   @classmethod
   def ShouldDisable(cls, possible_browser):
-    # http://crbug.com/624355 (reference builds).
-    return (possible_browser.platform.GetDeviceTypeName() != 'Desktop' or
-            possible_browser.browser_type == 'reference')
+    return possible_browser.platform.GetDeviceTypeName() != 'Desktop'
 
 
 @benchmark.Enabled('android')
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 60d37720..22922f5 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -39,6 +39,8 @@
     "ax_tree_combiner.h",
     "ax_tree_data.cc",
     "ax_tree_data.h",
+    "ax_tree_id_registry.cc",
+    "ax_tree_id_registry.h",
     "ax_tree_serializer.cc",
     "ax_tree_serializer.h",
     "ax_tree_source.h",
diff --git a/content/browser/accessibility/ax_tree_id_registry.cc b/ui/accessibility/ax_tree_id_registry.cc
similarity index 86%
rename from content/browser/accessibility/ax_tree_id_registry.cc
rename to ui/accessibility/ax_tree_id_registry.cc
index 1b167e7..35e5d2ad 100644
--- a/content/browser/accessibility/ax_tree_id_registry.cc
+++ b/ui/accessibility/ax_tree_id_registry.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/accessibility/ax_tree_id_registry.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
 
 #include "base/memory/singleton.h"
 
-namespace content {
+namespace ui {
 
 // static
 const AXTreeIDRegistry::AXTreeID AXTreeIDRegistry::kNoAXTreeID = -1;
@@ -17,7 +17,8 @@
 }
 
 AXTreeIDRegistry::AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID(
-    int process_id, int routing_id) {
+    int process_id,
+    int routing_id) {
   FrameID frame_id(process_id, routing_id);
   std::map<FrameID, AXTreeID>::iterator it;
   it = frame_to_ax_tree_id_map_.find(frame_id);
@@ -31,6 +32,10 @@
   return new_id;
 }
 
+int AXTreeIDRegistry::CreateID() {
+  return ++ax_tree_id_counter_;
+}
+
 AXTreeIDRegistry::FrameID AXTreeIDRegistry::GetFrameID(
     AXTreeIDRegistry::AXTreeID ax_tree_id) {
   std::map<AXTreeID, FrameID>::iterator it;
@@ -55,7 +60,6 @@
   GetOrCreateAXTreeID(0, 0);
 }
 
-AXTreeIDRegistry::~AXTreeIDRegistry() {
-}
+AXTreeIDRegistry::~AXTreeIDRegistry() {}
 
-}  // namespace content
+}  // namespace ui
diff --git a/content/browser/accessibility/ax_tree_id_registry.h b/ui/accessibility/ax_tree_id_registry.h
similarity index 77%
rename from content/browser/accessibility/ax_tree_id_registry.h
rename to ui/accessibility/ax_tree_id_registry.h
index 7ef4fda..7c16405 100644
--- a/content/browser/accessibility/ax_tree_id_registry.h
+++ b/ui/accessibility/ax_tree_id_registry.h
@@ -2,23 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
-#define CONTENT_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
+#ifndef UI_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
+#define UI_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
 
 #include <map>
 #include <utility>
 
 #include "base/macros.h"
+#include "ui/accessibility/ax_export.h"
 
 namespace base {
 template <typename T>
 struct DefaultSingletonTraits;
 }  // namespace base
 
-namespace content {
+namespace ui {
 
-// A class which generates a unique id given a process id and frame routing id.
-class AXTreeIDRegistry {
+// A class which generates a unique id.
+class AX_EXPORT AXTreeIDRegistry {
  public:
   using FrameID = std::pair<int, int>;
 
@@ -35,6 +36,9 @@
   FrameID GetFrameID(AXTreeID ax_tree_id);
   void RemoveAXTreeID(AXTreeID ax_tree_id);
 
+  // Create an id not associated with any process.
+  int CreateID();
+
  private:
   friend struct base::DefaultSingletonTraits<AXTreeIDRegistry>;
 
@@ -53,6 +57,6 @@
   DISALLOW_COPY_AND_ASSIGN(AXTreeIDRegistry);
 };
 
-}  // namespace content
+}  // namespace ui
 
-#endif  // CONTENT_BROWSER_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
+#endif  // UI_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc
index 98b02c3..b8e7cf7b 100644
--- a/ui/aura/client/aura_constants.cc
+++ b/ui/aura/client/aura_constants.cc
@@ -39,6 +39,7 @@
 DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kImmersiveFullscreenKey, false);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kMirroringEnabledKey, false);
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kTopLevelWindowInWM, false);
 DEFINE_UI_CLASS_PROPERTY_KEY(ui::ModalType, kModalKey, ui::MODAL_TYPE_NONE);
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kNameKey, nullptr);
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kPreferredSize, nullptr);
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index 11a4627..3c02cdd 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -116,6 +116,9 @@
 // A property key to store the window icon, typically 16x16 for title bars.
 AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kWindowIconKey;
 
+// Set to true if this window is a top level window in the window manager.
+AURA_EXPORT extern const aura::WindowProperty<bool>* const kTopLevelWindowInWM;
+
 AURA_EXPORT extern const aura::WindowProperty<ui::mojom::WindowType>* const
     kWindowTypeKey;
 
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index 30c9c0e..0b6b67f 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -8,9 +8,11 @@
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_local.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/env_observer.h"
 #include "ui/aura/input_state_lookup.h"
+#include "ui/aura/mus/mus_types.h"
 #include "ui/aura/mus/window_port_mus.h"
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
@@ -105,9 +107,12 @@
     return base::MakeUnique<WindowPortLocal>(window);
 
   DCHECK(window_tree_client_);
+  WindowMusType window_mus_type =
+      window->GetProperty(aura::client::kTopLevelWindowInWM)
+          ? WindowMusType::TOP_LEVEL_IN_WM
+          : WindowMusType::LOCAL;
   // Use LOCAL as all other cases are created by WindowTreeClient explicitly.
-  return base::MakeUnique<WindowPortMus>(window_tree_client_,
-                                         WindowMusType::LOCAL);
+  return base::MakeUnique<WindowPortMus>(window_tree_client_, window_mus_type);
 }
 
 void Env::AddObserver(EnvObserver* observer) {
diff --git a/ui/aura/mus/mus_types.h b/ui/aura/mus/mus_types.h
index de576d3..897c6b6 100644
--- a/ui/aura/mus/mus_types.h
+++ b/ui/aura/mus/mus_types.h
@@ -31,9 +31,12 @@
   // The window was created by requesting a top level
   // (WindowTree::NewTopLevel()).
   // NOTE: in the window manager (the one responsible for actually creating the
-  // real window) the window is of type LOCAL.
+  // real window) the window is of type TOP_LEVEL_IN_WM.
   TOP_LEVEL,
 
+  // The window is a top level window in the window manager.
+  TOP_LEVEL_IN_WM,
+
   // The window is a display root for the window manager.
   DISPLAY,
 
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 0a5be65e..4f0faf9 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -38,6 +38,9 @@
 
 namespace ui {
 namespace {
+// The client_id used here should not conflict with the client_id generated
+// from RenderWidgetHostImpl.
+constexpr uint32_t kDefaultClientId = 0u;
 
 class FakeReflector : public Reflector {
  public:
@@ -129,7 +132,7 @@
 InProcessContextFactory::InProcessContextFactory(
     bool context_factory_for_test,
     cc::SurfaceManager* surface_manager)
-    : next_surface_sink_id_(1u),
+    : frame_sink_id_allocator_(kDefaultClientId),
       use_test_surface_(true),
       context_factory_for_test_(context_factory_for_test),
       surface_manager_(surface_manager) {
@@ -285,12 +288,7 @@
 }
 
 cc::FrameSinkId InProcessContextFactory::AllocateFrameSinkId() {
-  // The FrameSinkId generated here must be unique with
-  // RenderWidgetHostViewAura's
-  // and RenderWidgetHostViewMac's FrameSinkId allocation.
-  // TODO(crbug.com/685777): Centralize allocation in one place for easier
-  // maintenance.
-  return cc::FrameSinkId(0, next_surface_sink_id_++);
+  return frame_sink_id_allocator_.NextFrameSinkId();
 }
 
 cc::SurfaceManager* InProcessContextFactory::GetSurfaceManager() {
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h
index 72924b6..9d40c121 100644
--- a/ui/compositor/test/in_process_context_factory.h
+++ b/ui/compositor/test/in_process_context_factory.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "cc/surfaces/display.h"
+#include "cc/surfaces/frame_sink_id_allocator.h"
 #include "cc/test/test_gpu_memory_buffer_manager.h"
 #include "cc/test/test_image_factory.h"
 #include "cc/test/test_shared_bitmap_manager.h"
@@ -84,7 +85,7 @@
   cc::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
   cc::TestImageFactory image_factory_;
   cc::TestTaskGraphRunner task_graph_runner_;
-  uint32_t next_surface_sink_id_;
+  cc::FrameSinkIdAllocator frame_sink_id_allocator_;
   bool use_test_surface_;
   bool context_factory_for_test_;
   cc::SurfaceManager* surface_manager_;
diff --git a/ui/display/test/display_manager_test_api.cc b/ui/display/test/display_manager_test_api.cc
index 16e9a1b..0a8078b4e 100644
--- a/ui/display/test/display_manager_test_api.cc
+++ b/ui/display/test/display_manager_test_api.cc
@@ -58,7 +58,9 @@
 }  // namespace
 
 DisplayManagerTestApi::DisplayManagerTestApi(DisplayManager* display_manager)
-    : display_manager_(display_manager) {}
+    : display_manager_(display_manager) {
+  DCHECK(display_manager);
+}
 
 DisplayManagerTestApi::~DisplayManagerTestApi() {}
 
diff --git a/ui/events/android/motion_event_android.cc b/ui/events/android/motion_event_android.cc
index ee645bf..8e99aa3 100644
--- a/ui/events/android/motion_event_android.cc
+++ b/ui/events/android/motion_event_android.cc
@@ -229,8 +229,8 @@
 }
 
 int MotionEventAndroid::GetActionIndex() const {
-  DCHECK(cached_action_ == ACTION_POINTER_UP ||
-         cached_action_ == ACTION_POINTER_DOWN)
+  DCHECK(cached_action_ == MotionEvent::ACTION_POINTER_UP ||
+         cached_action_ == MotionEvent::ACTION_POINTER_DOWN)
       << "Invalid action for GetActionIndex(): " << cached_action_;
   DCHECK_GE(cached_action_index_, 0);
   DCHECK_LT(cached_action_index_, static_cast<int>(cached_pointer_count_));
@@ -304,6 +304,8 @@
   // accessed at most once per event instance).
   if (!event_.obj())
     return 0.f;
+  if (cached_action_ == MotionEvent::ACTION_UP)
+    return 0.f;
   return Java_MotionEvent_getPressureF_I(AttachCurrentThread(), event_,
                                          pointer_index);
 }
diff --git a/ui/events/latency_info.dot b/ui/events/latency_info.dot
index e234cd6..7dcac5ad 100644
--- a/ui/events/latency_info.dot
+++ b/ui/events/latency_info.dot
@@ -3,36 +3,38 @@
 digraph g {
   node [shape=box];
 
-  INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT ->
-  INPUT_EVENT_LATENCY_UI_COMPONENT ->
   INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT ->
-  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT;
+  INPUT_EVENT_LATENCY_UI_COMPONENT [label="Event.Latency.OS.*"]
+  INPUT_EVENT_LATENCY_UI_COMPONENT -> INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT [label="Event.Latency.Browser.INPUT_MODALITYUI"];
 
-  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT -> INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT [label="Event.Latency.Browser.*Acked"];
+  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT -> INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT [label="Event.Latency.Browser.INPUT_MODALITYAcked"];
 
-  INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT;
-  INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT;
+  INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT;
 
-  INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT -> INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT [label="Event.Latency.ScrollBegin/ScrollUpdate.*.HandledToRendererSwap2_Main"];
-  INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT -> INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT [label="Event.Latency.ScrollBegin/ScrollUpdate.*.HandledToRendererSwap2_Impl"];
+  INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT -> INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT [label="Event.Latency.SCROLL.INPUT_MODALITY.HandledToRendererSwap2_THREAD"];
 
-  INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT -> INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT [label="Event.Latency.ScrollBegin/ScrollUpdate.*.RendererSwapToBrowserNotified2"];
-  INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT -> INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT [label="Event.Latency.ScrollBegin/ScrollUpdate.*.BrowserNotifiedToBeforeGpuSwap2"];
-  INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT -> INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT [label="Event.Latency.ScrollBegin/ScrollUpdate.*.GpuSwap2"];
-
-  INPUT_EVENT_LATENCY_UI_COMPONENT ->
-  INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT ->
-  INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT;
+  INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT -> INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT [label="Event.Latency.SCROLL.INPUT_MODALITY.RendererSwapToBrowserNotified2"];
+  INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT -> INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT [label="Event.Latency.SCROLL.INPUT_MODALITY.BrowserNotifiedToBeforeGpuSwap2"];
+  INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT -> INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT [label="Event.Latency.SCROLL.INPUT_MODALITY.GpuSwap2"];
 
   edge[style="dashed"];
-  INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT [label="Event.Latency.ScrollUpdate.*.TimeToScrollUpdateSwapBegin2"];
-  INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT [label="Event.Latency.ScrollBegin.*.TimeToScrollUpdateSwapBegin2"];
+  INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT [label="Event.Latency.SCROLL.INPUT_MODALITY.TimeToScrollUpdateSwapBegin2"];
 
-  INPUT_EVENT_LATENCY_UI_COMPONENT -> INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT [label="Event.Latency.Browser.*UI"];
-  INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT [label="Event.Latency.ScrollUpdate.*.TimeToHandled2_Main"];
-  INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT [label="Event.Latency.ScrollUpdate.*.TimeToHandled2_Impl"];
+  INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT [label="Event.Latency.SCROLL.INPUT_MODALITY.TimeToHandled2_THREAD"];
 
-  INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT [label="Event.Latency.ScrollBegin.*.TimeToHandled2_Main"];
-  INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT -> INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT [label="Event.Latency.ScrollBegin.*.TimeToHandled2_Impl"];
+  INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT[label="\
+EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT\l\
+EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT\l\
+INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT \l"];
+  INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT[label="INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_(MAIN | IMPL)_COMPONENT"];
 
+
+  subgraph cluster_01 {
+    style=invis;
+    node [shape=plaintext];
+    key [label="\
+INPUT_MODALITY = (Wheel | Mouse)\l\
+THREAD = (Main | Impl)\l\
+SCROLL = (ScrollBegin | ScrollUpdate)\l"]
+  }
 }
diff --git a/ui/events/x/events_x_unittest.cc b/ui/events/x/events_x_unittest.cc
index 6e77c97..cf62b2b 100644
--- a/ui/events/x/events_x_unittest.cc
+++ b/ui/events/x/events_x_unittest.cc
@@ -305,7 +305,7 @@
   EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.25f);
   pointer_details = GetTouchPointerDetailsFromNative(scoped_xevent);
   EXPECT_FLOAT_EQ(pointer_details.radius_x, 10.0f);
-  EXPECT_FLOAT_EQ(pointer_details.force, 0.05f);
+  EXPECT_FLOAT_EQ(pointer_details.force, 0.f);
 
   // Touch with tracking id 6 should have old angle/pressure value and new
   // radius value.
@@ -321,7 +321,7 @@
   EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.45f);
   pointer_details = GetTouchPointerDetailsFromNative(scoped_xevent);
   EXPECT_FLOAT_EQ(pointer_details.radius_x, 25.0f);
-  EXPECT_FLOAT_EQ(pointer_details.force, 0.5f);
+  EXPECT_FLOAT_EQ(pointer_details.force, 0.f);
 }
 
 int GetTouchIdForTrackingId(uint32_t tracking_id) {
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc
index 3b19c7ab..fa37616 100644
--- a/ui/events/x/events_x_utils.cc
+++ b/ui/events/x/events_x_utils.cc
@@ -725,6 +725,9 @@
 }
 
 float GetTouchForceFromXEvent(const XEvent& xev) {
+  XIDeviceEvent* event = static_cast<XIDeviceEvent*>(xev.xcookie.data);
+  if (event->evtype == XI_TouchEnd)
+    return 0.0;
   double force = 0.0;
   force = GetTouchParamFromXEvent(
       xev, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
diff --git a/ui/gfx/vector_icons/BUILD.gn b/ui/gfx/vector_icons/BUILD.gn
index 1bd790f..7dad812 100644
--- a/ui/gfx/vector_icons/BUILD.gn
+++ b/ui/gfx/vector_icons/BUILD.gn
@@ -4,6 +4,9 @@
 
 import("//build/config/chrome_build.gni")
 
+# NB: This is a deprecated vector icon target that should be removed. Add vector
+# icons to a more specific target, or ui/vector_icons if ui/ is the right place
+# for them. TODO(estade): remove this target.
 action("aggregate_vector_icons") {
   visibility = [ ":*" ]
 
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h
index 893b0de0d..ecb9345 100644
--- a/ui/gl/gl_context.h
+++ b/ui/gl/gl_context.h
@@ -43,6 +43,9 @@
   GpuPreference gpu_preference = PreferIntegratedGpu;
   bool bind_generates_resource = true;
   bool webgl_compatibility_context = false;
+  bool global_texture_share_group = false;
+  int client_major_es_version = 3;
+  int client_minor_es_version = 0;
 };
 
 // Encapsulates an OpenGL context, hiding platform specific management.
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index ca34e4b..f764a889 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -32,6 +32,11 @@
 #define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x3AAC
 #endif /* EGL_ANGLE_create_context_webgl_compatibility */
 
+#ifndef EGL_ANGLE_display_texture_share_group
+#define EGL_ANGLE_display_texture_share_group 1
+#define EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE 0x3AAF
+#endif /* EGL_ANGLE_display_texture_share_group */
+
 using ui::GetLastEGLErrorString;
 
 namespace gl {
@@ -61,16 +66,36 @@
     return false;
   }
 
-  EGLint context_client_version = 2;
-  if ((config_renderable_type & EGL_OPENGL_ES3_BIT) != 0 &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableES3GLContext)) {
-    context_client_version = 3;
+  EGLint context_client_major_version = attribs.client_major_es_version;
+  EGLint context_client_minor_version = attribs.client_minor_es_version;
+
+  // If the requested context is ES3 but the config cannot support ES3, request
+  // ES2 instead.
+  if ((config_renderable_type & EGL_OPENGL_ES3_BIT) == 0 &&
+      context_client_major_version >= 3) {
+    context_client_major_version = 2;
+    context_client_minor_version = 0;
   }
 
   std::vector<EGLint> context_attributes;
-  context_attributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
-  context_attributes.push_back(context_client_version);
+
+  // EGL_KHR_create_context allows requesting both a major and minor context
+  // version
+  if (GLSurfaceEGL::HasEGLExtension("EGL_KHR_create_context")) {
+    context_attributes.push_back(EGL_CONTEXT_MAJOR_VERSION);
+    context_attributes.push_back(context_client_major_version);
+
+    context_attributes.push_back(EGL_CONTEXT_MINOR_VERSION);
+    context_attributes.push_back(context_client_minor_version);
+  } else {
+    context_attributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+    context_attributes.push_back(context_client_major_version);
+
+    // Can only request 2.0 or 3.0 contexts without the EGL_KHR_create_context
+    // extension, DCHECK to make sure we update the code to support devices
+    // without this extension
+    DCHECK(context_client_minor_version == 0);
+  }
 
   if (GLSurfaceEGL::IsCreateContextRobustnessSupported()) {
     DVLOG(1) << "EGL_EXT_create_context_robustness supported.";
@@ -105,6 +130,14 @@
     DCHECK(!attribs.webgl_compatibility_context);
   }
 
+  if (GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_display_texture_share_group")) {
+    context_attributes.push_back(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE);
+    context_attributes.push_back(
+        attribs.global_texture_share_group ? EGL_TRUE : EGL_FALSE);
+  } else {
+    DCHECK(!attribs.global_texture_share_group);
+  }
+
   // Append final EGL_NONE to signal the context attributes are finished
   context_attributes.push_back(EGL_NONE);
   context_attributes.push_back(EGL_NONE);
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 9012fe5..cd2138d 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -167,8 +167,6 @@
     "controls/link.cc",
     "controls/link.h",
     "controls/link_listener.h",
-    "controls/md_slider.cc",
-    "controls/md_slider.h",
     "controls/menu/display_change_listener_mac.cc",
     "controls/menu/menu_config.cc",
     "controls/menu/menu_config.h",
@@ -222,8 +220,6 @@
     "controls/native/native_view_host.h",
     "controls/native/native_view_host_mac.h",
     "controls/native/native_view_host_mac.mm",
-    "controls/non_md_slider.cc",
-    "controls/non_md_slider.h",
     "controls/prefix_delegate.h",
     "controls/prefix_selector.cc",
     "controls/prefix_selector.h",
@@ -720,8 +716,6 @@
     "test/test_layout_manager.cc",
     "test/test_layout_manager.h",
     "test/test_platform_native_widget.h",
-    "test/test_slider.cc",
-    "test/test_slider.h",
     "test/test_views.cc",
     "test/test_views.h",
     "test/test_views_delegate.h",
diff --git a/ui/views/controls/md_slider.cc b/ui/views/controls/md_slider.cc
deleted file mode 100644
index 64bed2fa..0000000
--- a/ui/views/controls/md_slider.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/md_slider.h"
-
-#include "cc/paint/paint_flags.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "ui/gfx/animation/slide_animation.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/controls/slider.h"
-
-namespace views {
-
-// Color of slider at the active and the disabled state, respectively.
-const SkColor kActiveColor = SkColorSetARGB(0xFF, 0x42, 0x85, 0xF4);
-const SkColor kDisabledColor = SkColorSetARGB(0xFF, 0xBD, 0xBD, 0xBD);
-const uint8_t kHighlightColorAlpha = 0x4D;
-
-// The thickness of the slider.
-const int kLineThickness = 2;
-
-// The radius used to draw rounded slider ends.
-const float kSliderRoundedRadius = 2.f;
-
-// The radius of the thumb and the highlighted thumb of the slider,
-// respectively.
-const float kThumbRadius = 6.f;
-const float kThumbHighlightRadius = 10.f;
-
-// The stroke of the thumb when the slider is disabled.
-const int kThumbStroke = 2;
-
-// Duration of the thumb highlight growing effect animation.
-const int kSlideHighlightChangeDurationMs = 150;
-
-MdSlider::MdSlider(SliderListener* listener)
-    : Slider(listener), is_active_(true), thumb_highlight_radius_(0.f) {
-  SchedulePaint();
-}
-
-MdSlider::~MdSlider() {}
-
-void MdSlider::OnPaint(gfx::Canvas* canvas) {
-  Slider::OnPaint(canvas);
-
-  // Paint the slider.
-  const gfx::Rect content = GetContentsBounds();
-  const int width = content.width() - kThumbRadius * 2;
-  const int full = GetAnimatingValue() * width;
-  const int empty = width - full;
-  const int y = content.height() / 2 - kLineThickness / 2;
-  const int x = content.x() + full + kThumbRadius;
-  const SkColor current_thumb_color =
-      is_active_ ? kActiveColor : kDisabledColor;
-
-  // Extra space used to hide slider ends behind the thumb.
-  const int extra_padding = 1;
-
-  cc::PaintFlags slider_flags;
-  slider_flags.setAntiAlias(true);
-  slider_flags.setColor(current_thumb_color);
-  canvas->DrawRoundRect(
-      gfx::Rect(content.x(), y, full + extra_padding, kLineThickness),
-      kSliderRoundedRadius, slider_flags);
-  slider_flags.setColor(kDisabledColor);
-  canvas->DrawRoundRect(gfx::Rect(x + kThumbRadius - extra_padding, y,
-                                  empty + extra_padding, kLineThickness),
-                        kSliderRoundedRadius, slider_flags);
-
-  gfx::Point thumb_center(x, content.height() / 2);
-
-  // Paint the thumb highlight if it exists.
-  const int thumb_highlight_radius =
-      HasFocus() ? kThumbHighlightRadius : thumb_highlight_radius_;
-  if (is_active_ && thumb_highlight_radius > kThumbRadius) {
-    cc::PaintFlags highlight;
-    SkColor kHighlightColor = SkColorSetA(kActiveColor, kHighlightColorAlpha);
-    highlight.setColor(kHighlightColor);
-    highlight.setFlags(cc::PaintFlags::kAntiAlias_Flag);
-    canvas->DrawCircle(thumb_center, thumb_highlight_radius, highlight);
-  }
-
-  // Paint the thumb of the slider.
-  cc::PaintFlags flags;
-  flags.setColor(current_thumb_color);
-  flags.setFlags(cc::PaintFlags::kAntiAlias_Flag);
-
-  if (!is_active_) {
-    flags.setStrokeWidth(kThumbStroke);
-    flags.setStyle(cc::PaintFlags::kStroke_Style);
-  }
-  canvas->DrawCircle(
-      thumb_center,
-      is_active_ ? kThumbRadius : (kThumbRadius - kThumbStroke / 2), flags);
-}
-
-const char* MdSlider::GetClassName() const {
-  return "MdSlider";
-}
-
-void MdSlider::UpdateState(bool control_on) {
-  is_active_ = control_on;
-  SchedulePaint();
-}
-
-int MdSlider::GetThumbWidth() {
-  return kThumbRadius * 2;
-}
-
-void MdSlider::SetHighlighted(bool is_highlighted) {
-  if (!highlight_animation_) {
-    if (!is_highlighted)
-      return;
-
-    highlight_animation_.reset(new gfx::SlideAnimation(this));
-    highlight_animation_->SetSlideDuration(kSlideHighlightChangeDurationMs);
-  }
-  if (is_highlighted)
-    highlight_animation_->Show();
-  else
-    highlight_animation_->Hide();
-}
-
-void MdSlider::AnimationProgressed(const gfx::Animation* animation) {
-  if (animation != highlight_animation_.get()) {
-    Slider::AnimationProgressed(animation);
-    return;
-  }
-  thumb_highlight_radius_ =
-      animation->CurrentValueBetween(kThumbRadius, kThumbHighlightRadius);
-  SchedulePaint();
-}
-
-void MdSlider::AnimationEnded(const gfx::Animation* animation) {
-  if (animation != highlight_animation_.get()) {
-    Slider::AnimationEnded(animation);
-    return;
-  }
-  if (animation == highlight_animation_.get() &&
-      !highlight_animation_->IsShowing()) {
-    highlight_animation_.reset();
-  }
-}
-
-}  // namespace views
diff --git a/ui/views/controls/md_slider.h b/ui/views/controls/md_slider.h
deleted file mode 100644
index 9a534f5..0000000
--- a/ui/views/controls/md_slider.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_MD_SLIDER_H_
-#define UI_VIEWS_CONTROLS_MD_SLIDER_H_
-
-#include "base/macros.h"
-#include "ui/views/controls/slider.h"
-#include "ui/views/view.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class SlideAnimation;
-}
-
-namespace views {
-
-// TODO(yiyix): When material design is enabled by default, use
-// MdSlider as the default slider implementation. (crbug.com/614453)
-class VIEWS_EXPORT MdSlider : public Slider {
- public:
-  explicit MdSlider(SliderListener* listener);
-  ~MdSlider() override;
-
-  // ui::Slider:
-  void UpdateState(bool control_on) override;
-
-  // views::View:
-  void OnPaint(gfx::Canvas* canvas) override;
-  const char* GetClassName() const override;
-
- protected:
-  // ui::Slider:
-  int GetThumbWidth() override;
-  void SetHighlighted(bool is_highlighted) override;
-
- private:
-  // gfx::AnimationDelegate:
-  void AnimationProgressed(const gfx::Animation* animation) override;
-  void AnimationEnded(const gfx::Animation* animation) override;
-
-  // Record whether the slider is in the active state or the disabled state.
-  bool is_active_;
-
-  // Animating value of the current radius of the thumb's highlight.
-  float thumb_highlight_radius_;
-
-  std::unique_ptr<gfx::SlideAnimation> highlight_animation_;
-
-  DISALLOW_COPY_AND_ASSIGN(MdSlider);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_MD_SLIDER_H_
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 37db59d..335945f2 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -1554,7 +1554,7 @@
   alt_menu->PrepareForRun(
       false, has_mnemonics,
       source->GetMenuItem()->GetRootMenuItem()->show_mnemonics_);
-  alt_menu->controller_ = this;
+  alt_menu->controller_ = AsWeakPtr();
   SetSelection(alt_menu, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
   return true;
 }
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index 70aded9..5d918d3 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -24,6 +24,7 @@
 #include "ui/views/controls/menu/menu_controller_delegate.h"
 #include "ui/views/controls/menu/menu_delegate.h"
 #include "ui/views/controls/menu/menu_host.h"
+#include "ui/views/controls/menu/menu_host_root_view.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/menu_message_loop.h"
 #include "ui/views/controls/menu/menu_scroll_view_container.h"
@@ -31,6 +32,7 @@
 #include "ui/views/test/menu_test_utils.h"
 #include "ui/views/test/test_views_delegate.h"
 #include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/root_view.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/client/drag_drop_client.h"
@@ -506,6 +508,10 @@
 
   MenuHost* GetMenuHost(SubmenuView* submenu) { return submenu->host_; }
 
+  MenuHostRootView* CreateMenuHostRootView(MenuHost* host) {
+    return static_cast<MenuHostRootView*>(host->CreateRootView());
+  }
+
   void MenuHostOnDragWillStart(MenuHost* host) { host->OnDragWillStart(); }
 
   void MenuHostOnDragComplete(MenuHost* host) { host->OnDragComplete(); }
@@ -607,7 +613,6 @@
     menu_controller_->ExitMenuRun();
   }
 
- private:
   void DestroyMenuController() {
     if (!menu_controller_)
       return;
@@ -621,6 +626,7 @@
     menu_controller_ = nullptr;
   }
 
+ private:
   void Init() {
     owner_.reset(new Widget);
     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
@@ -1192,6 +1198,32 @@
   MenuHostOnDragComplete(host);
 }
 
+// Widget destruction and cleanup occurs on the MessageLoop after the
+// MenuController has been destroyed. A MenuHostRootView should not attempt to
+// access a destroyed MenuController. This test should not cause a crash.
+TEST_F(MenuControllerTest, HostReceivesInputBeforeDestruction) {
+  MenuController* controller = menu_controller();
+  controller->SetAsyncRun(true);
+
+  SubmenuView* submenu = menu_item()->GetSubmenu();
+  submenu->ShowAt(owner(), menu_item()->bounds(), false);
+  gfx::Point location(submenu->bounds().bottom_right());
+  location.Offset(1, 1);
+
+  MenuHost* host = GetMenuHost(submenu);
+  // Normally created as the full Widget is brought up. Explicitly created here
+  // for testing.
+  std::unique_ptr<MenuHostRootView> root_view(CreateMenuHostRootView(host));
+  DestroyMenuController();
+
+  ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location,
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
+
+  // This should not attempt to access the destroyed MenuController and should
+  // not crash.
+  root_view->OnMouseMoved(event);
+}
+
 // Tets that an asynchronous menu nested within an asynchronous menu closes both
 // menus, and notifies both delegates.
 TEST_F(MenuControllerTest, DoubleAsynchronousNested) {
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index 556cb24..def3514 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -435,11 +435,11 @@
 }
 
 MenuController* MenuItemView::GetMenuController() {
-  return GetRootMenuItem()->controller_;
+  return GetRootMenuItem()->controller_.get();
 }
 
 const MenuController* MenuItemView::GetMenuController() const {
-  return GetRootMenuItem()->controller_;
+  return GetRootMenuItem()->controller_.get();
 }
 
 MenuDelegate* MenuItemView::GetDelegate() {
diff --git a/ui/views/controls/menu/menu_item_view.h b/ui/views/controls/menu/menu_item_view.h
index 5176807..a7c729ed 100644
--- a/ui/views/controls/menu/menu_item_view.h
+++ b/ui/views/controls/menu/menu_item_view.h
@@ -11,11 +11,13 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "ui/base/models/menu_separator_types.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/controls/menu/menu_config.h"
+#include "ui/views/controls/menu/menu_controller.h"
 #include "ui/views/controls/menu/menu_types.h"
 #include "ui/views/view.h"
 
@@ -418,7 +420,12 @@
     actual_menu_position_ = actual_menu_position;
   }
 
-  void set_controller(MenuController* controller) { controller_ = controller; }
+  void set_controller(MenuController* controller) {
+    if (controller)
+      controller_ = controller->AsWeakPtr();
+    else
+      controller_.reset();
+  }
 
   // Returns true if this MenuItemView contains a single child
   // that is responsible for rendering the content.
@@ -442,7 +449,7 @@
   MenuDelegate* delegate_;
 
   // The controller for the run operation, or NULL if the menu isn't showing.
-  MenuController* controller_;
+  base::WeakPtr<MenuController> controller_;
 
   // Used to detect when Cancel was invoked.
   bool canceled_;
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index 88431ca..1f9abd4 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -454,7 +454,9 @@
 
 void SubmenuView::MenuHostDestroyed() {
   host_ = NULL;
-  GetMenuItem()->GetMenuController()->Cancel(MenuController::EXIT_DESTROYED);
+  MenuController* controller = GetMenuItem()->GetMenuController();
+  if (controller)
+    controller->Cancel(MenuController::EXIT_DESTROYED);
 }
 
 const char* SubmenuView::GetClassName() const {
diff --git a/ui/views/controls/non_md_slider.cc b/ui/views/controls/non_md_slider.cc
deleted file mode 100644
index 1778ddc7..0000000
--- a/ui/views/controls/non_md_slider.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/non_md_slider.h"
-
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/resources/grit/ui_resources.h"
-#include "ui/views/controls/slider.h"
-#include "ui/views/resources/grit/views_resources.h"
-
-namespace {
-const int kBarImagesActive[] = {
-    IDR_SLIDER_ACTIVE_LEFT, IDR_SLIDER_ACTIVE_CENTER, IDR_SLIDER_PRESSED_CENTER,
-    IDR_SLIDER_PRESSED_RIGHT,
-};
-
-const int kBarImagesDisabled[] = {
-    IDR_SLIDER_DISABLED_LEFT, IDR_SLIDER_DISABLED_CENTER,
-    IDR_SLIDER_DISABLED_CENTER, IDR_SLIDER_DISABLED_RIGHT,
-};
-
-// The image chunks.
-enum BorderElements {
-  LEFT,
-  CENTER_LEFT,
-  CENTER_RIGHT,
-  RIGHT,
-};
-}  // namespace
-
-namespace views {
-
-NonMdSlider::NonMdSlider(SliderListener* listener)
-    : Slider(listener),
-      bar_active_images_(kBarImagesActive),
-      bar_disabled_images_(kBarImagesDisabled) {
-  UpdateSliderAppearance(true);
-}
-
-NonMdSlider::~NonMdSlider() {}
-
-void NonMdSlider::OnPaint(gfx::Canvas* canvas) {
-  Slider::OnPaint(canvas);
-  gfx::Rect content = GetContentsBounds();
-  float value = GetAnimatingValue();
-
-  // Inset the slider bar a little bit, so that the left or the right end of
-  // the slider bar will not be exposed under the thumb button when the thumb
-  // button slides to the left most or right most position.
-  const int kBarInsetX = 2;
-  int bar_width = content.width() - kBarInsetX * 2;
-  int bar_cy = content.height() / 2 - bar_height_ / 2;
-
-  int w = content.width() - thumb_->width();
-  int full = value * w;
-  int middle = std::max(full, images_[LEFT]->width());
-
-  canvas->Save();
-  canvas->Translate(gfx::Vector2d(kBarInsetX, bar_cy));
-  canvas->DrawImageInt(*images_[LEFT], 0, 0);
-  canvas->DrawImageInt(*images_[RIGHT], bar_width - images_[RIGHT]->width(), 0);
-  canvas->TileImageInt(*images_[CENTER_LEFT], images_[LEFT]->width(), 0,
-                       middle - images_[LEFT]->width(), bar_height_);
-  canvas->TileImageInt(*images_[CENTER_RIGHT], middle, 0,
-                       bar_width - middle - images_[RIGHT]->width(),
-                       bar_height_);
-  canvas->Restore();
-
-  // Paint slider thumb.
-  int button_cx = content.x() + full;
-  int thumb_y = content.height() / 2 - thumb_->height() / 2;
-  canvas->DrawImageInt(*thumb_, button_cx, thumb_y);
-}
-
-const char* NonMdSlider::GetClassName() const {
-  return "NonMdSlider";
-}
-
-void NonMdSlider::UpdateState(bool control_on) {
-  UpdateSliderAppearance(control_on);
-}
-
-void NonMdSlider::UpdateSliderAppearance(bool control_on) {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  if (control_on) {
-    thumb_ = rb.GetImageNamed(IDR_SLIDER_ACTIVE_THUMB).ToImageSkia();
-    for (int i = 0; i < 4; ++i)
-      images_[i] = rb.GetImageNamed(bar_active_images_[i]).ToImageSkia();
-  } else {
-    thumb_ = rb.GetImageNamed(IDR_SLIDER_DISABLED_THUMB).ToImageSkia();
-    for (int i = 0; i < 4; ++i)
-      images_[i] = rb.GetImageNamed(bar_disabled_images_[i]).ToImageSkia();
-  }
-  bar_height_ = images_[LEFT]->height();
-  SchedulePaint();
-}
-
-int NonMdSlider::GetThumbWidth() {
-  return thumb_->width();
-}
-
-}  // namespace views
diff --git a/ui/views/controls/non_md_slider.h b/ui/views/controls/non_md_slider.h
deleted file mode 100644
index fa6bfc9c..0000000
--- a/ui/views/controls/non_md_slider.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_NON_MD_SLIDER_H_
-#define UI_VIEWS_CONTROLS_NON_MD_SLIDER_H_
-
-#include "base/macros.h"
-#include "ui/views/controls/slider.h"
-#include "ui/views/view.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-class Slider;
-
-class VIEWS_EXPORT NonMdSlider : public Slider {
- public:
-  explicit NonMdSlider(SliderListener* listener);
-  ~NonMdSlider() override;
-
-  // ui::Slider:
-  void UpdateState(bool control_on) override;
-
-  // views::View:
-  void OnPaint(gfx::Canvas* canvas) override;
-  const char* GetClassName() const override;
-
- protected:
-  // ui::Slider:
-  int GetThumbWidth() override;
-
- private:
-  void UpdateSliderAppearance(bool control_on);
-
-  // Array used to hold active slider states and disabled slider states images.
-  const int* bar_active_images_;
-  const int* bar_disabled_images_;
-  const gfx::ImageSkia* thumb_;
-
-  // Array used to hold current state of slider images.
-  const gfx::ImageSkia* images_[4];
-  int bar_height_;
-
-  DISALLOW_COPY_AND_ASSIGN(NonMdSlider);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_NON_MD_SLIDER_H_
diff --git a/ui/views/controls/slider.cc b/ui/views/controls/slider.cc
index d35b8046..219ebf6c 100644
--- a/ui/views/controls/slider.cc
+++ b/ui/views/controls/slider.cc
@@ -10,20 +10,18 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "cc/paint/paint_flags.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/events/event.h"
-#include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/resources/grit/ui_resources.h"
-#include "ui/views/controls/md_slider.h"
-#include "ui/views/controls/non_md_slider.h"
 #include "ui/views/resources/grit/views_resources.h"
 #include "ui/views/widget/widget.h"
 
@@ -41,19 +39,50 @@
 
 namespace views {
 
+namespace {
+
+// Color of slider at the active and the disabled state, respectively.
+const SkColor kActiveColor = SkColorSetARGB(0xFF, 0x42, 0x85, 0xF4);
+const SkColor kDisabledColor = SkColorSetARGB(0xFF, 0xBD, 0xBD, 0xBD);
+constexpr uint8_t kHighlightColorAlpha = 0x4D;
+
+// The thickness of the slider.
+constexpr int kLineThickness = 2;
+
+// The radius used to draw rounded slider ends.
+constexpr float kSliderRoundedRadius = 2.f;
+
+// The radius of the thumb and the highlighted thumb of the slider,
+// respectively.
+constexpr float kThumbRadius = 6.f;
+constexpr float kThumbWidth = 2 * kThumbRadius;
+constexpr float kThumbHighlightRadius = 10.f;
+
+// The stroke of the thumb when the slider is disabled.
+constexpr int kThumbStroke = 2;
+
+// Duration of the thumb highlight growing effect animation.
+constexpr int kSlideHighlightChangeDurationMs = 150;
+
+}  // namespace
+
 // static
 const char Slider::kViewClassName[] = "Slider";
 
-// static
-Slider* Slider::CreateSlider(bool is_material_design,
-                             SliderListener* listener) {
-  if (is_material_design)
-    return new MdSlider(listener);
-  return new NonMdSlider(listener);
+Slider::Slider(SliderListener* listener)
+    : listener_(listener), highlight_animation_(this) {
+  highlight_animation_.SetSlideDuration(kSlideHighlightChangeDurationMs);
+  EnableCanvasFlippingForRTLUI(true);
+#if defined(OS_MACOSX)
+  SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
+#else
+  SetFocusBehavior(FocusBehavior::ALWAYS);
+#endif
+
+  SchedulePaint();
 }
 
-Slider::~Slider() {
-}
+Slider::~Slider() {}
 
 void Slider::SetValue(float value) {
   SetValueInternal(value, VALUE_CHANGED_BY_API);
@@ -63,20 +92,9 @@
   accessible_name_ = name;
 }
 
-Slider::Slider(SliderListener* listener)
-    : listener_(listener),
-      value_(0.f),
-      keyboard_increment_(0.1f),
-      initial_animating_value_(0.f),
-      value_is_valid_(false),
-      accessibility_events_enabled_(true),
-      initial_button_offset_(0) {
-  EnableCanvasFlippingForRTLUI(true);
-#if defined(OS_MACOSX)
-  SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
-#else
-  SetFocusBehavior(FocusBehavior::ALWAYS);
-#endif
+void Slider::UpdateState(bool control_on) {
+  is_active_ = control_on;
+  SchedulePaint();
 }
 
 float Slider::GetAnimatingValue() const{
@@ -86,21 +104,28 @@
              : value_;
 }
 
-void Slider::SetHighlighted(bool is_highlighted) {}
-
-void Slider::OnPaint(gfx::Canvas* canvas) {
-  View::OnPaint(canvas);
-  OnPaintFocus(canvas);
+void Slider::SetHighlighted(bool is_highlighted) {
+  if (is_highlighted)
+    highlight_animation_.Show();
+  else
+    highlight_animation_.Hide();
 }
 
 void Slider::AnimationProgressed(const gfx::Animation* animation) {
-  if (animation == move_animation_.get())
-    SchedulePaint();
+  if (animation == &highlight_animation_) {
+    thumb_highlight_radius_ =
+        animation->CurrentValueBetween(kThumbRadius, kThumbHighlightRadius);
+  }
+
+  SchedulePaint();
 }
 
 void Slider::AnimationEnded(const gfx::Animation* animation) {
-  if (animation == move_animation_.get())
+  if (animation == move_animation_.get()) {
     move_animation_.reset();
+    return;
+  }
+  DCHECK_EQ(animation, &highlight_animation_);
 }
 
 void Slider::SetValueInternal(float value, SliderChangeReason reason) {
@@ -140,26 +165,24 @@
   gfx::Rect content = GetContentsBounds();
   float value = GetAnimatingValue();
 
-  const int thumb_width = GetThumbWidth();
-  const int thumb_x = value * (content.width() - thumb_width);
+  const int thumb_x = value * (content.width() - kThumbWidth);
   const int candidate_x = (base::i18n::IsRTL() ?
       width() - (new_x - inset.left()) :
       new_x - inset.left()) - thumb_x;
-  if (candidate_x >= 0 && candidate_x < thumb_width)
+  if (candidate_x >= 0 && candidate_x < kThumbWidth)
     initial_button_offset_ = candidate_x;
   else
-    initial_button_offset_ = thumb_width / 2;
+    initial_button_offset_ = kThumbRadius;
 }
 
 void Slider::MoveButtonTo(const gfx::Point& point) {
   const gfx::Insets inset = GetInsets();
-  const int thumb_width = GetThumbWidth();
   // Calculate the value.
   int amount = base::i18n::IsRTL()
                    ? width() - inset.left() - point.x() - initial_button_offset_
                    : point.x() - inset.left() - initial_button_offset_;
   SetValueInternal(
-      static_cast<float>(amount) / (width() - inset.width() - thumb_width),
+      static_cast<float>(amount) / (width() - inset.width() - kThumbWidth),
       VALUE_CHANGED_BY_USER);
 }
 
@@ -238,6 +261,60 @@
       base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5))));
 }
 
+void Slider::OnPaint(gfx::Canvas* canvas) {
+  // Paint the slider.
+  const gfx::Rect content = GetContentsBounds();
+  const int width = content.width() - kThumbRadius * 2;
+  const int full = GetAnimatingValue() * width;
+  const int empty = width - full;
+  const int y = content.height() / 2 - kLineThickness / 2;
+  const int x = content.x() + full + kThumbRadius;
+  const SkColor current_thumb_color =
+      is_active_ ? kActiveColor : kDisabledColor;
+
+  // Extra space used to hide slider ends behind the thumb.
+  const int extra_padding = 1;
+
+  cc::PaintFlags slider_flags;
+  slider_flags.setAntiAlias(true);
+  slider_flags.setColor(current_thumb_color);
+  canvas->DrawRoundRect(
+      gfx::Rect(content.x(), y, full + extra_padding, kLineThickness),
+      kSliderRoundedRadius, slider_flags);
+  slider_flags.setColor(kDisabledColor);
+  canvas->DrawRoundRect(gfx::Rect(x + kThumbRadius - extra_padding, y,
+                                  empty + extra_padding, kLineThickness),
+                        kSliderRoundedRadius, slider_flags);
+
+  gfx::Point thumb_center(x, content.height() / 2);
+
+  // Paint the thumb highlight if it exists.
+  const int thumb_highlight_radius =
+      HasFocus() ? kThumbHighlightRadius : thumb_highlight_radius_;
+  if (is_active_ && thumb_highlight_radius > kThumbRadius) {
+    cc::PaintFlags highlight;
+    SkColor kHighlightColor = SkColorSetA(kActiveColor, kHighlightColorAlpha);
+    highlight.setColor(kHighlightColor);
+    highlight.setFlags(cc::PaintFlags::kAntiAlias_Flag);
+    canvas->DrawCircle(thumb_center, thumb_highlight_radius, highlight);
+  }
+
+  // Paint the thumb of the slider.
+  cc::PaintFlags flags;
+  flags.setColor(current_thumb_color);
+  flags.setFlags(cc::PaintFlags::kAntiAlias_Flag);
+
+  if (!is_active_) {
+    flags.setStrokeWidth(kThumbStroke);
+    flags.setStyle(cc::PaintFlags::kStroke_Style);
+  }
+  canvas->DrawCircle(
+      thumb_center,
+      is_active_ ? kThumbRadius : (kThumbRadius - kThumbStroke / 2), flags);
+
+  OnPaintFocus(canvas);
+}
+
 void Slider::OnFocus() {
   View::OnFocus();
   SchedulePaint();
diff --git a/ui/views/controls/slider.h b/ui/views/controls/slider.h
index 8d1b24c4..0290beb 100644
--- a/ui/views/controls/slider.h
+++ b/ui/views/controls/slider.h
@@ -7,15 +7,12 @@
 
 #include "base/macros.h"
 #include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/animation/slide_animation.h"
 #include "ui/views/view.h"
 #include "ui/views/views_export.h"
 
 typedef unsigned int SkColor;
 
-namespace gfx {
-class SlideAnimation;
-}
-
 namespace views {
 
 namespace test {
@@ -50,10 +47,7 @@
   // Internal class name.
   static const char kViewClassName[];
 
-  // Based on the bool |is_material_design|, either a md version or a non-md
-  // version of the slider will be created.
-  static Slider* CreateSlider(bool is_material_design,
-                              SliderListener* listener);
+  explicit Slider(SliderListener* listener);
   ~Slider() override;
 
   float value() const { return value_; }
@@ -66,23 +60,15 @@
   }
 
   // Update UI based on control on/off state.
-  virtual void UpdateState(bool control_on) = 0;
+  void UpdateState(bool control_on);
 
  protected:
-  explicit Slider(SliderListener* listener);
-
   // Returns the current position of the thumb on the slider.
   float GetAnimatingValue() const;
 
   // Shows or hides the highlight on the slider thumb. The default
   // implementation does nothing.
-  virtual void SetHighlighted(bool is_highlighted);
-
-  // Gets the size of the slider's thumb.
-  virtual int GetThumbWidth() = 0;
-
-  // views::View:
-  void OnPaint(gfx::Canvas* canvas) override;
+  void SetHighlighted(bool is_highlighted);
 
   // gfx::AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override;
@@ -117,6 +103,7 @@
   void OnMouseReleased(const ui::MouseEvent& event) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void OnPaint(gfx::Canvas* canvas) override;
   void OnFocus() override;
   void OnBlur() override;
 
@@ -131,16 +118,24 @@
 
   std::unique_ptr<gfx::SlideAnimation> move_animation_;
 
-  float value_;
-  float keyboard_increment_;
-  float initial_animating_value_;
-  bool value_is_valid_;
+  float value_ = 0.f;
+  float keyboard_increment_ = 0.1f;
+  float initial_animating_value_ = 0.f;
+  bool value_is_valid_ = false;
   base::string16 accessible_name_;
-  bool accessibility_events_enabled_;
+  bool accessibility_events_enabled_ = true;
 
   // Relative position of the mouse cursor (or the touch point) on the slider's
   // button.
-  int initial_button_offset_;
+  int initial_button_offset_ = 0;
+
+  // Record whether the slider is in the active state or the disabled state.
+  bool is_active_ = true;
+
+  // Animating value of the current radius of the thumb's highlight.
+  float thumb_highlight_radius_ = 0.f;
+
+  gfx::SlideAnimation highlight_animation_;
 
   DISALLOW_COPY_AND_ASSIGN(Slider);
 };
diff --git a/ui/views/controls/slider_unittest.cc b/ui/views/controls/slider_unittest.cc
index 390d837..44893c9 100644
--- a/ui/views/controls/slider_unittest.cc
+++ b/ui/views/controls/slider_unittest.cc
@@ -19,7 +19,6 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/test/slider_test_api.h"
-#include "ui/views/test/test_slider.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
@@ -183,7 +182,7 @@
 void SliderTest::SetUp() {
   views::ViewsTestBase::SetUp();
 
-  slider_ = new TestSlider(nullptr);
+  slider_ = new Slider(nullptr);
   View* view = slider_;
   gfx::Size size = view->GetPreferredSize();
   view->SetSize(size);
@@ -219,22 +218,7 @@
   event_generator_->ClickLeftButton();
 }
 
-// Test fixture for horizontally oriented slider tests.
-class HorizontalSliderTest : public SliderTest {
- public:
-  HorizontalSliderTest();
-  ~HorizontalSliderTest() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HorizontalSliderTest);
-};
-
-HorizontalSliderTest::HorizontalSliderTest() : SliderTest() {}
-
-HorizontalSliderTest::~HorizontalSliderTest() {
-}
-
-TEST_F(HorizontalSliderTest, UpdateFromClickHorizontal) {
+TEST_F(SliderTest, UpdateFromClickHorizontal) {
   ClickAt(0, 0);
   EXPECT_EQ(0.0f, slider()->value());
 
@@ -242,8 +226,7 @@
   EXPECT_EQ(1.0f, slider()->value());
 }
 
-
-TEST_F(HorizontalSliderTest, UpdateFromClickRTLHorizontal) {
+TEST_F(SliderTest, UpdateFromClickRTLHorizontal) {
   base::i18n::SetICUDefaultLocale("he");
 
   ClickAt(0, 0);
@@ -257,7 +240,7 @@
 #if !defined(OS_MACOSX) || defined(USE_AURA)
 
 // Test the slider location after a tap gesture.
-TEST_F(HorizontalSliderTest, SliderValueForTapGesture) {
+TEST_F(SliderTest, SliderValueForTapGesture) {
   // Tap below the minimum.
   slider()->SetValue(0.5);
   event_generator()->GestureTapAt(gfx::Point(0, 0));
@@ -275,7 +258,7 @@
 }
 
 // Test the slider location after a scroll gesture.
-TEST_F(HorizontalSliderTest, SliderValueForScrollGesture) {
+TEST_F(SliderTest, SliderValueForScrollGesture) {
   // Scroll below the minimum.
   slider()->SetValue(0.5);
   event_generator()->GestureScrollSequence(
@@ -303,8 +286,8 @@
 }
 
 // Test the slider location by adjusting it using keyboard.
-TEST_F(HorizontalSliderTest, SliderValueForKeyboard) {
-  float value =0.5;
+TEST_F(SliderTest, SliderValueForKeyboard) {
+  float value = 0.5;
   slider()->SetValue(value);
   slider()->RequestFocus();
   event_generator()->PressKey(ui::VKEY_RIGHT, 0);
@@ -316,7 +299,7 @@
 }
 
 // Verifies the correct SliderListener events are raised for a tap gesture.
-TEST_F(HorizontalSliderTest, SliderListenerEventsForTapGesture) {
+TEST_F(SliderTest, SliderListenerEventsForTapGesture) {
   test::SliderTestApi slider_test_api(slider());
   slider_test_api.SetListener(&slider_listener());
 
@@ -328,7 +311,7 @@
 }
 
 // Verifies the correct SliderListener events are raised for a scroll gesture.
-TEST_F(HorizontalSliderTest, SliderListenerEventsForScrollGesture) {
+TEST_F(SliderTest, SliderListenerEventsForScrollGesture) {
   test::SliderTestApi slider_test_api(slider());
   slider_test_api.SetListener(&slider_listener());
 
@@ -347,7 +330,7 @@
 
 // Verifies the correct SliderListener events are raised for a multi
 // finger scroll gesture.
-TEST_F(HorizontalSliderTest, SliderListenerEventsForMultiFingerScrollGesture) {
+TEST_F(SliderTest, SliderListenerEventsForMultiFingerScrollGesture) {
   test::SliderTestApi slider_test_api(slider());
   slider_test_api.SetListener(&slider_listener());
 
diff --git a/ui/views/examples/slider_example.cc b/ui/views/examples/slider_example.cc
index 9367d12..db33940 100644
--- a/ui/views/examples/slider_example.cc
+++ b/ui/views/examples/slider_example.cc
@@ -25,8 +25,7 @@
 
 void SliderExample::CreateExampleView(View* container) {
   label_ = new Label();
-  // Create a material design slider in this example.
-  slider_ = Slider::CreateSlider(true /** is_material_design **/, this);
+  slider_ = new views::Slider(this);
 
   slider_->SetValue(0.5);
 
diff --git a/ui/views/resources/default_100_percent/slider_center_active.png b/ui/views/resources/default_100_percent/slider_center_active.png
deleted file mode 100644
index 76e9bb2..0000000
--- a/ui/views/resources/default_100_percent/slider_center_active.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_center_disabled.png b/ui/views/resources/default_100_percent/slider_center_disabled.png
deleted file mode 100644
index 96765331..0000000
--- a/ui/views/resources/default_100_percent/slider_center_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_center_pressed.png b/ui/views/resources/default_100_percent/slider_center_pressed.png
deleted file mode 100644
index 60b11ebd..0000000
--- a/ui/views/resources/default_100_percent/slider_center_pressed.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_left_active.png b/ui/views/resources/default_100_percent/slider_left_active.png
deleted file mode 100644
index 4029a007..0000000
--- a/ui/views/resources/default_100_percent/slider_left_active.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_left_disabled.png b/ui/views/resources/default_100_percent/slider_left_disabled.png
deleted file mode 100644
index b9d763e..0000000
--- a/ui/views/resources/default_100_percent/slider_left_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_left_pressed.png b/ui/views/resources/default_100_percent/slider_left_pressed.png
deleted file mode 100644
index 16cb2822..0000000
--- a/ui/views/resources/default_100_percent/slider_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_right_disabled.png b/ui/views/resources/default_100_percent/slider_right_disabled.png
deleted file mode 100644
index 765a38b..0000000
--- a/ui/views/resources/default_100_percent/slider_right_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_right_pressed.png b/ui/views/resources/default_100_percent/slider_right_pressed.png
deleted file mode 100644
index 401d8c6..0000000
--- a/ui/views/resources/default_100_percent/slider_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_thumb.png b/ui/views/resources/default_100_percent/slider_thumb.png
deleted file mode 100644
index c73a283..0000000
--- a/ui/views/resources/default_100_percent/slider_thumb.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_100_percent/slider_thumb_disabled.png b/ui/views/resources/default_100_percent/slider_thumb_disabled.png
deleted file mode 100644
index 9a1fa00..0000000
--- a/ui/views/resources/default_100_percent/slider_thumb_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_center_active.png b/ui/views/resources/default_200_percent/slider_center_active.png
deleted file mode 100644
index b8c22455..0000000
--- a/ui/views/resources/default_200_percent/slider_center_active.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_center_disabled.png b/ui/views/resources/default_200_percent/slider_center_disabled.png
deleted file mode 100644
index 21a752ff3..0000000
--- a/ui/views/resources/default_200_percent/slider_center_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_center_pressed.png b/ui/views/resources/default_200_percent/slider_center_pressed.png
deleted file mode 100644
index 6d55487..0000000
--- a/ui/views/resources/default_200_percent/slider_center_pressed.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_left_active.png b/ui/views/resources/default_200_percent/slider_left_active.png
deleted file mode 100644
index 33e1a27..0000000
--- a/ui/views/resources/default_200_percent/slider_left_active.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_left_disabled.png b/ui/views/resources/default_200_percent/slider_left_disabled.png
deleted file mode 100644
index bb4ff9e..0000000
--- a/ui/views/resources/default_200_percent/slider_left_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_left_pressed.png b/ui/views/resources/default_200_percent/slider_left_pressed.png
deleted file mode 100644
index e3c2545..0000000
--- a/ui/views/resources/default_200_percent/slider_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_right_disabled.png b/ui/views/resources/default_200_percent/slider_right_disabled.png
deleted file mode 100644
index 9703f983..0000000
--- a/ui/views/resources/default_200_percent/slider_right_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_right_pressed.png b/ui/views/resources/default_200_percent/slider_right_pressed.png
deleted file mode 100644
index cac9203c..0000000
--- a/ui/views/resources/default_200_percent/slider_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_thumb.png b/ui/views/resources/default_200_percent/slider_thumb.png
deleted file mode 100644
index bb5f51e4..0000000
--- a/ui/views/resources/default_200_percent/slider_thumb.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/default_200_percent/slider_thumb_disabled.png b/ui/views/resources/default_200_percent/slider_thumb_disabled.png
deleted file mode 100644
index d711d8ad..0000000
--- a/ui/views/resources/default_200_percent/slider_thumb_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ui/views/resources/views_resources.grd b/ui/views/resources/views_resources.grd
index dbcd9c47..7468fad1 100644
--- a/ui/views/resources/views_resources.grd
+++ b/ui/views/resources/views_resources.grd
@@ -159,16 +159,6 @@
       <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_MENU_CHECK" file="cros/menu_check.png" />
       </if>
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_ACTIVE_LEFT" file="slider_left_active.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_ACTIVE_CENTER" file="slider_center_active.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_DISABLED_LEFT" file="slider_left_disabled.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_DISABLED_RIGHT" file="slider_right_disabled.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_DISABLED_CENTER" file="slider_center_disabled.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_PRESSED_LEFT" file="slider_left_pressed.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_PRESSED_RIGHT" file="slider_right_pressed.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_PRESSED_CENTER" file="slider_center_pressed.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_ACTIVE_THUMB" file="slider_thumb.png" />
-      <structure type="chrome_scaled_image" name="IDR_SLIDER_DISABLED_THUMB" file="slider_thumb_disabled.png" />
       <if expr="desktop_linux">
         <structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="linux/linux_minimize.png" />
         <structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="linux/linux_minimize_hover.png" />
diff --git a/ui/views/test/test_slider.cc b/ui/views/test/test_slider.cc
deleted file mode 100644
index 72d7098..0000000
--- a/ui/views/test/test_slider.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/test/test_slider.h"
-
-#include "ui/views/controls/slider.h"
-
-namespace views {
-
-// Arbitrary thumb size used for tests.
-const int thumb_size_ = 10;
-
-TestSlider::TestSlider(SliderListener* listener) : Slider(listener) {}
-
-TestSlider::~TestSlider() {}
-
-void TestSlider::UpdateState(bool control_on) {
-}
-
-const char* TestSlider::GetClassName() const {
-  return "TestSlider";
-}
-
-int TestSlider::GetThumbWidth() {
-  return thumb_size_;
-}
-
-}  // namespace views
diff --git a/ui/views/test/test_slider.h b/ui/views/test/test_slider.h
deleted file mode 100644
index d9496d89..0000000
--- a/ui/views/test/test_slider.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_TEST_TEST_SLIDER_H_
-#define UI_VIEWS_TEST_TEST_SLIDER_H_
-
-#include "base/macros.h"
-#include "ui/views/controls/slider.h"
-#include "ui/views/view.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-class Slider;
-
-// It is a dummy implementation of slider used for testing functionalities in
-// slider.
-class TestSlider : public Slider {
- public:
-  explicit TestSlider(SliderListener* listener);
-  ~TestSlider() override;
-
-  // ui::Slider:
-  void UpdateState(bool control_on) override;
-
-  // views::View:
-  const char* GetClassName() const override;
-
- protected:
-  // ui::Slider:
-  int GetThumbWidth() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestSlider);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_TEST_TEST_SLIDER_H_
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list.js b/ui/webui/resources/cr_elements/network/cr_network_list.js
index 82b5fc7..64e3a13 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list.js
+++ b/ui/webui/resources/cr_elements/network/cr_network_list.js
@@ -67,12 +67,35 @@
 
   observers: ['updateListItems_(networks, customItems)'],
 
+  /** @private {boolean} */
+  focusRequested_: false,
+
+  focus: function() {
+    this.focusRequested_ = true;
+    this.focusFirstItem_();
+  },
+
   /** @private */
   updateListItems_: function() {
     this.saveScroll(this.$.networkList);
     this.listItems_ = this.networks.concat(this.customItems);
     this.restoreScroll(this.$.networkList);
     this.updateScrollableContents();
+    if (this.focusRequested_) {
+      this.async(function() {
+        this.focusFirstItem_();
+      });
+    }
+  },
+
+  /** @private */
+  focusFirstItem_: function() {
+    // Select the first cr-network-list-item if there is one.
+    var item = this.$$('cr-network-list-item');
+    if (!item)
+      return;
+    item.focus();
+    this.focusRequested_ = false;
   },
 
   /**
diff --git a/ui/webui/resources/cr_elements/network/cr_network_select.html b/ui/webui/resources/cr_elements/network/cr_network_select.html
index 3bd7169..d0d12d1 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_select.html
+++ b/ui/webui/resources/cr_elements/network/cr_network_select.html
@@ -10,7 +10,8 @@
         display: inline-flex;
       }
     </style>
-    <cr-network-list class ="flex" on-selected="onNetworkListItemSelected_"
+    <cr-network-list id="neworkList" class ="flex"
+        on-selected="onNetworkListItemSelected_"
         on-network-connected="onNetworkConnected_"
         networks="[[networkStateList_]]" custom-items="[[customItems]]"
         show-buttons="[[showButtons]]"
diff --git a/ui/webui/resources/cr_elements/network/cr_network_select.js b/ui/webui/resources/cr_elements/network/cr_network_select.js
index eb1efea6..9d66e5e 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_select.js
+++ b/ui/webui/resources/cr_elements/network/cr_network_select.js
@@ -56,6 +56,10 @@
     },
   },
 
+  focus: function() {
+    this.$.neworkList.focus();
+  },
+
   /**
    * Listener function for chrome.networkingPrivate.onNetworkListChanged event.
    * @type {function(!Array<string>)}